Menu

SPI Arduino (AtMega) Uno

Help
2017-03-30
2017-03-30
1 2 > >> (Page 1 of 2)
  • Macgman2000

    Macgman2000 - 2017-03-30

    Hello, I did a quick search for SPI on Atmega (Arduino Uno) using GCB. I was not able to find anything useful. Is there example code for master set up?

    Thanks!
    Nick

     
  • William Roth

    William Roth - 2017-03-30

    In the demo folder...C:\GCB@Syn\GreatCowBasic\Demos\SPI Digital Pot Solutions\MCP4xxx SPI Pot

    The HELP file covers SPI pretty well. CmmandReference> SPI.

    Is there a specific problem or question?

     
  • Macgman2000

    Macgman2000 - 2017-03-30

    I want to use the SPI to drive a 3-wire communication interface to a PLL. The interface is not SPI or I2C. basically Clk, data and LE. I thought maybe I can use Hardware SPI in master mode just sending data one way (no need to read back) utilizing 3 out of the 4 interfaces in SPI.

    -Nick

     
  • Anobium

    Anobium - 2017-03-30

    You can do that. Nothing to stop you. Create you own SPI command and call it. Note: Dependent on your chip you may have to clear flags even if do not read the incoming buffer - use the HWPSI.H as a source.

     
    • Macgman2000

      Macgman2000 - 2017-03-31

      I looked at the examples, still confused. I don't know how to load the TX buffer. Nor do I know how to send out 3 bytes. I want to find an example for the arduino that uses the hardware SPI. No offense to whomever wrote the manual for GCB, but the example for SPI is confusing and unclear.

      -Nick

       
  • Anobium

    Anobium - 2017-03-31

    That's OK. Always looking for feedback.

    Here is how to do it. See glcd_ILI9340.h as an example

    The method below sends either a hardware or software SPI command - this depends on ILI9340_HardwareSPI being defined. Using the hardware as the example SPITransfer ILI9340SendByte, ILI9340TempOut sends one byte and get a byte. As I stated before the low level code handles the PIC variants and AVR in terms of the actual code.

    '''Send a command to the ILI9340 GLCD
    '''@param ILI9340SendByte Command to send
    '''@hide
    sub  SendCommand_ILI9340( IN ILI9340SendByte as byte )
    
      set ILI9340_CS OFF;
      set ILI9340_DC OFF;
    
      #ifdef ILI9340_HardwareSPI
         SPITransfer  ILI9340SendByte,  ILI9340TempOut  
         set ILI9340_CS ON;
         exit sub
      #endif
    
      repeat 8
    
        if ILI9340SendByte.7 = ON  then
          set ILI9340_DO ON;
        else
          set ILI9340_DO OFF;
        end if
        SET GLCD_SCK On;
        rotate ILI9340SendByte left
        set GLCD_SCK Off;
    
      end repeat
      set ILI9340_CS ON;
    
    end Sub
    

    Now, if I look at the Ethernet driver - I need to send two bytes. There are two calls to FastHWSPITransfer.

    ; writes byte ENC_Outbyte in ENC register addr of the current bank
    sub ENC28j60_writeReg( in addr,  in ENC_Outbyte as byte )
    '       banktobeselected = ( addr & BANK_MASK) / 32
            banktobeselected =  ( addr & BANK_MASK)
            Repeat 5
                set c off
                rotate banktobeselected right
            end Repeat
    
            if lastselectedBank <> banktobeselected then
              if ( ( addr & ADDR_MASK )  <= EIE  ) then
                  ENC28j60_selectBank ( banktobeselected, addr )
              end if
            Else
              lastselectedBank = banktobeselected
            end if
    
            ENC28j60_Select
            FastHWSPITransfer( ENC28j60_WRITE_CTRL_REG | (addr AND ADDR_MASK ) )
            FastHWSPITransfer( ENC_Outbyte )
            ENC28j60_Deselect
    
    end sub
    

    But, I you think... what is FastHWSPITransfer compared to SPITransfer? FastHWSPITransfer is an undocumented but supported method that is faster by only handling SPI Master mode and one out byte - So, in your code you could use FastHWSPITransfer - but, dont.

    So, how do you send three bytes? I would do the following. In your main code add.

    #define FastHWSPITransfer myFastHWSPITransfer
    
    Sub to handle SPI data send - Master mode only
    Sub myFastHWSPITransfer( In SPITxData1, In SPITxData2, In SPITxData3 )
    
    'Sub to handle SPI data send - Master mode only
    Sub FastHWSPITransfer( In SPITxData )
      'Master mode only
      #ifdef PIC
    
        'Clear WCOL
        Set SSPCON1.WCOL Off
    
        'Put byte to send into buffer
        'Will start transfer
        SSPBUF = SPITxData1
        'Same for master and slave
        Wait While SSPSTAT.BF = Off
        Set SSPSTAT.BF Off
    
        'Handle 18F chips
        #if ChipFamily 16
          SPIRxData1 = SSPBUF
        #endif
    
    
        'Clear WCOL
        Set SSPCON1.WCOL Off
    
        'Put byte to send into buffer
        'Will start transfer
        SSPBUF = SPITxData2
        'Same for master and slave
        Wait While SSPSTAT.BF = Off
        Set SSPSTAT.BF Off
    
        'Handle 18F chips
        #if ChipFamily 16
          SPIRxData2 = SSPBUF
        #endif
    
        'Clear WCOL
        Set SSPCON1.WCOL Off
    
        'Put byte to send into buffer
        'Will start transfer
        SSPBUF = SPITxData3
        'Same for master and slave
        Wait While SSPSTAT.BF = Off
        Set SSPSTAT.BF Off
    
        'Handle 18F chips
        #if ChipFamily 16
          SPIRxData3 = SSPBUF
        #endif
    
      #endif
    
      #ifdef AVR
        'Master mode only
        Do
          SPDR = SPITxData1
        Loop While SPSR.WCOL
        'Read buffer
        'Same for master and slave
        Wait While SPSR.SPIF = Off
    
        'Master mode only
        Do
          SPDR = SPITxData2
        Loop While SPSR.WCOL
        'Read buffer
        'Same for master and slave
        Wait While SPSR.SPIF = Off
    
        'Master mode only
        Do
          SPDR = SPITxData3
        Loop While SPSR.WCOL
        'Read buffer
        'Same for master and slave
        Wait While SPSR.SPIF = Off
    
    
    
      #endif
    
    End Sub
    

    Or, simply call FastHWSPITransfer three times. :-)

    FastHWSPITransfer (byte1)
    FastHWSPITransfer (byte2)
    FastHWSPITransfer (byte3)
    

    Or,

    Or, to be compliant with the Open documented methods call SPITransfer three times. :-)

    SPITransfer (byte1, temp)  'send a byte and throw any the incoming byte.
    SPITransfer (byte2, temp)  'send a byte and throw any the incoming byte.
    SPITransfer (byte3, temp)  'send a byte and throw any the incoming byte.
    

    Hope this helps.

    And, once you have this working - I would be truly grateful for any updates to the Help to make this easier for the next person.

    Anobium

     

    Last edit: Anobium 2017-03-31
  • Macgman2000

    Macgman2000 - 2017-03-31

    Hello Anobium,

    Thanks for the examples. Trying to make sense of it, please bear with me.
    I am going to grab one example and run with it. I am unsure how to force master mode or if the routine would send 3 bytes every 100ms they way I wrote it....Please see below.

    '#chip mega328p, 16

    'variable defines
    dim Data1 as byte
    dim Data2 as byte
    dim Data3 as byte

    Data1 = 100 ' these later will be values seeded from A/D pots
    Data2 = 150
    Data3 = 200

    Do

    'Master mode only
    Do
    SPDR = SPITxData1
    Loop While SPSR.WCOL
    'Read buffer
    'Same for master and slave
    Wait While SPSR.SPIF = Off

    'Master mode only
    Do
      SPDR = SPITxData2
    Loop While SPSR.WCOL
    'Read buffer
    'Same for master and slave
    Wait While SPSR.SPIF = Off
    
    'Master mode only
    Do
      SPDR = SPITxData3
    Loop While SPSR.WCOL
    'Read buffer
    'Same for master and slave
    Wait While SPSR.SPIF = Off
    
    wait 100ms
    Loop
    
     
  • Anobium

    Anobium - 2017-04-01

    I guess so. Not sure why this would not work.

    FastHWSPITransfer (byte1)
    FastHWSPITransfer (byte2)
    FastHWSPITransfer (byte3)

     

    Last edit: Anobium 2017-04-01
  • Macgman2000

    Macgman2000 - 2017-04-01

    I will try that. So the TX mechanism is that simple, just unsure of what support files need to be called. Any .h or initialization files need to be included? Anything that determines LSB first? Master/slave mode? Speed of transmission?....etc.

     
  • Anobium

    Anobium - 2017-04-02

    When you have this working... you can help rewrite the Help. :-)

    The LSB is determined by the order that youy send. MasterSlave (see the Help) but SPIMode MasterFast, 0 will use MasterMode at clocked at 1/4 of the frequency of the microcontroller, speed of transmission is dependent on the chips clock speed, clock polarity and clock edge is set by the second parameter. I am copying thos from the help.

    So, this is all that is needed.

    SPIMode MasterFast, 0 'which equates to SPIMode ( MasterFast, SPI_CPOL_0 + SPI_CPHA_0 ) you need to determine the correct clock polarity and clock edge from your device.
    
    FastHWSPITransfer (byte1)
    FastHWSPITransfer (byte2)
    FastHWSPITransfer (byte3)
    
     
  • Macgman2000

    Macgman2000 - 2017-04-03

    Hello Anobium,

    This is what I have so far and it does not output anything. Not sure where I have gone wrong...

    chip mega328p, 16

    #config osc = Ext

    'port direction configuration
    dir PortC.7 out ' CLK
    dir PortD.6 out ' MISO
    dir PortB.7 out ' MOSI
    dir PortB.6 out ' SS

    DIM byte1 As byte
    DIM byte2 As byte
    DIM byte3 As byte

    byte1 = 100 ' temp values (will come from potentiometer later)
    byte2 = 150
    byte3 = 200

    SPIMode ( MasterFast, SPI_CPOL_0 + SPI_CPHA_0 )

    do forever

    FastHWSPITransfer (byte1)
    FastHWSPITransfer (byte2)
    FastHWSPITransfer (byte3)
    wait 100 ms
    

    loop

     
  • Anobium

    Anobium - 2017-04-03

    Use the GLCD_ILI934x as the source as I am not sure how you determined the CLK, MOSI and MISO. Please review ..\GreatCowBasic\Demos\GLCD Solutions\GLCD Simple Demonstration Solutions\GLCD_Simple_Demonstation_mega328p_for_ILI9341@16.gcb

     'Chip Settings.
      #chip mega328p, 16
      #option explicit
    
        #include <glcd.h>
        #include <UNO_mega328p.h >
    
        #define GLCD_TYPE GLCD_TYPE_ILI9341
    
        'Pin mappings for SPI - this GLCD driver supports Hardware SPI
        #define GLCD_DC       DIGITAL_8         ' Data command line
        #define GLCD_CS       DIGITAL_10          ' Chip select line
        #define GLCD_RESET    DIGITAL_9          ' Reset line
    
        #define GLCD_DI       DIGITAL_12          ' Data in | MISO
        #define GLCD_DO       DIGITAL_11          ' Data out | MOSI
        #define GLCD_SCK      DIGITAL_13          ' Clock Line
    
    DIM byte1 As byte
    DIM byte2 As byte
    DIM byte3 As byte
    byte1 = 100 ' temp values (will come from potentiometer later)
    byte2 = 150
    byte3 = 200
    SPIMode ( MasterFast, SPI_CPOL_0 + SPI_CPHA_0 )
    do forever
    FastHWSPITransfer (byte1)
    FastHWSPITransfer (byte2)
    FastHWSPITransfer (byte3)
    wait 100 ms
    loop
    

    And, are you testing with a protocol analyser? (Just checking how you are determining if things are working).

    Anobium

     
  • Anobium

    Anobium - 2017-04-03

    I have assummed you have your connections on the hardware SPI ports. If not, we need to give you the software SPI methods.

    😃

     
  • Macgman2000

    Macgman2000 - 2017-04-03

    I am getting this error....SPI2.gcb (27): Error: Variable SPICLOCKMODE was not explicitly declared

     
  • Anobium

    Anobium - 2017-04-04

    Sorry, I cannot reproduce that error.

    See my exact code attached. If your code does not work please provide source GCB file, the ASM related to the source file (generated with error), restate your build version (I have assumed you are using v0.97.00 or greater).

    Puzzled here.

     
  • Macgman2000

    Macgman2000 - 2017-04-04

    I downloaded v0.97. It compiles. Neither your code nor mine is outputting a signal on SPI....not sure what is going on.

     
  • Anobium

    Anobium - 2017-04-04

    I will spin up a test rig now. Check back in 10 mins.

     
  • Macgman2000

    Macgman2000 - 2017-04-04

    OK...I had to initialize port direction....now it works. The data needs to be inverted though....

    'Chip Settings.
    #chip mega328p, 16
    #option explicit

    #include <UNO_mega328p.h >
    
    
    'Pin mappings for SPI - this GLCD driver supports Hardware SPI
    #define GLCD_DC       DIGITAL_8         ' Data command line
    #define GLCD_CS       DIGITAL_10          ' Chip select line
    #define GLCD_RESET    DIGITAL_9          ' Reset line
    
    #define GLCD_DI       DIGITAL_12          ' Data in | MISO
    #define GLCD_DO       DIGITAL_11          ' Data out | MOSI
    #define GLCD_SCK      DIGITAL_13          ' Clock Line
    

    'port direction configuration
    dir PortB.5 out
    dir PortB.4 out
    dir PortB.3 out
    dir PortB.2 out
    dir PortB.1 out

    DIM byte1 As byte
    DIM byte2 As byte
    DIM byte3 As byte
    
    byte1 = 100 ' temp values (will come from potentiometer later)
    byte2 = 150
    byte3 = 200
    
    SPIMode ( MasterFast, SPI_CPOL_0 + SPI_CPHA_0 )
    
    do forever
        FastHWSPITransfer (byte1)
        FastHWSPITransfer (byte2)
        FastHWSPITransfer (byte3)
        wait 100 ms
    loop
    
     
  • Anobium

    Anobium - 2017-04-04

    Very good. Well done.

    Here is complete posting, totally based upon your good work. So, thank you! The HELP will get improved as a result.

    This shows how the MEGA328p can support hardware and software SPI. To use hardware make sure the #define SPI_HardwareSPI is not commented out.
    To use software comment out #define SPI_HardwareSPI.

    To use the hardware SPI the Data Out, Data In and Clock (DO/DI and SCK) cannot be moved but the optional Data Command, Chip Select and Reset are all moveable.

    To use the hardware SPI the Data Out, Data In and Clock (DO/DI and SCK), Data Command, Chip Select and Reset are all moveable.

    I have called InitSPIMode to call SPIMode if needed, and set the lines.

    I have also define a sub called SendByteviaSPI to handle whether to call the Hardware or use Software (bit-banging) SPI.

    Enjoy - really sorry for not getting this right in the first place!

    'Chip Settings.
        #chip mega328p, 16
        #option explicit
        #include <UNO_mega328p.h >
    
        #define SPI_HardwareSPI  'comment this out to make into Software SPI but, you may have to change clock lines
    
        'Pin mappings for SPI - this SPI driver supports Hardware SPI
        #define SPI_DC       DIGITAL_8         ' Data command line
        #define SPI_CS       DIGITAL_4          ' Chip select line
        #define SPI_RESET    DIGITAL_9          ' Reset line
    
        'mandated for hardware
        #define SPI_DI       DIGITAL_12          ' Data in | MISO 
        #define SPI_DO       DIGITAL_11          ' Data out | MOSI
        #define SPI_SCK      DIGITAL_13          ' Clock Line
    
        dir SPI_DC    out
        dir SPI_CS    out
        dir SPI_RESET out
        dir SPI_DO    Out
        dir SPI_DI    In
        dir SPI_SCK   Out
    
        dir DIGITAL_10 Out    'needed and I am not sure why!
    
        DIM byte1 As byte
        DIM byte2 As byte
        DIM byte3 As byte
        DIM tt as byte
        DIM SPISendByte as byte
    
        byte1 = 100 ' temp values (will come from potentiometer later)
        byte2 = 150
        byte3 = 200
    
        InitSPIMode
    
    
    
        do forever
            set SPI_CS OFF;
            set SPI_DC OFF;
            SendByteviaSPI (byte1)
            set SPI_CS ON;
            set SPI_DC ON
    
            set SPI_CS OFF;
            set SPI_DC OFF;
            SendByteviaSPI (byte2)
            set SPI_CS ON;
            set SPI_DC ON
    
            set SPI_CS OFF;
            set SPI_DC OFF;
            SendByteviaSPI (byte3)
            set SPI_CS ON;
            set SPI_DC ON
    
            wait 100 ms
        loop
    
    
    
    sub InitSPIMode
    
          #ifdef SPI_HardwareSPI
              SPIMode ( MasterFast, SPI_CPOL_0 + SPI_CPHA_0 )
          #endif
    
          set SPI_DO OFF;
          set SPI_CS ON;   therefore CPOL=0
          set SPI_DC ON;   deselect
    
    End sub
    
    sub  SendByteviaSPI( in SPISendByte )
    
      set SPI_CS OFF
      set SPI_DC OFF;
    
      #ifdef SPI_HardwareSPI
         FastHWSPITransfer  SPISendByte
         set SPI_CS ON;
         exit sub
      #endif
    
      #ifndef SPI_HardwareSPI
      repeat 8
    
        if SPISendByte.7 = ON  then
          set SPI_DO ON;
        else
          set SPI_DO OFF;
        end if
        SET SPI_SCK On;           ; therefore CPOL=0 ==ON, and, where CPOL=1==ON
        rotate SPISendByte left
        set SPI_SCK Off;          ; therefore CPOL=0  =OFF, and, where CPOL=1==OFF
    
      end repeat
      set SPI_CS ON;
      set SPI_DO OFF;
      #endif
    
    end Sub
    
     
  • Macgman2000

    Macgman2000 - 2017-04-04

    weird data on the scope. byte1 = 255, byte2= 0 and byte3 = 255....looking at the clock edges the 255 on the right side of the scope is high all the way through. if I use anything less than 255 in byte1 then the waveform starts low before the clock pulses start. When set to 255 it starts off as high before the clock pulses.....why is this?

     
  • Anobium

    Anobium - 2017-04-04

    Mine sample code looks ok, but, I am set CS line.

    Let me try you code.

     
  • Anobium

    Anobium - 2017-04-04

    Your code works here.
    I did make the change to code to support my lines and implement the CS line to get my analyser to work.

    'Chip Settings.
    #chip mega328p, 16
    #option explicit
    #include <UNO_mega328p.h >
    
        'Pin mappings for SPI - this SPI driver supports Hardware SPI
        #define SPI_DC       DIGITAL_8         ' Data command line
        #define SPI_CS       DIGITAL_4          ' Chip select line
        #define SPI_RESET    DIGITAL_9          ' Reset line
    
        #define SPI_DI       DIGITAL_12          ' Data in | MISO
        #define SPI_DO       DIGITAL_11          ' Data out | MOSI
        #define SPI_SCK      DIGITAL_13          ' Clock Line
    
        dir SPI_DC    out
        dir SPI_CS    out
        dir SPI_RESET out
        dir SPI_DO    Out
        dir SPI_DI    In
        dir SPI_SCK   Out
    
        dir DIGITAL_10 Out    'needed and I am not sure why!
    
    
    DIM byte1 As byte
    DIM byte2 As byte
    DIM byte3 As byte
    
    byte1 = 100 ' temp values (will come from potentiometer later)
    byte2 = 150
    byte3 = 200
    
    SPIMode ( MasterFast, SPI_CPOL_0 + SPI_CPHA_0 )
    
    do forever
            set SPI_CS off
            FastHWSPITransfer (byte1)
            set SPI_CS on
    
            set SPI_CS off
            FastHWSPITransfer (byte2)
            set SPI_CS on
    
            set SPI_CS off
            FastHWSPITransfer (byte3)
            set SPI_CS on
    
        wait 100 ms
    loop
    
     
  • Anobium

    Anobium - 2017-04-04

    @Macgman2000 . You were so right. HELP was meaningless!

    Updated - check tomorrow. :-)

     
  • Macgman2000

    Macgman2000 - 2017-04-10

    Is there an easy way to flip bits around to send LSB first?

     
  • Anobium

    Anobium - 2017-04-10

    You want to flip the bits? Assign the bits to a temporary variable and send the temporary variable.

    Temp.7 = orginal.0
    ..
    
    ...
    Temp.0 = original.7
    
     
1 2 > >> (Page 1 of 2)

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.