Shop OBEX P1 Docs P2 Docs Learn Events
SPI protocol — Parallax Forums

SPI protocol

AleksAleks Posts: 52
edited 2008-08-11 13:07 in Propeller 1
I've just been given a challenge to program a system with the Spin Stamp to communicate with a master device using SPI protocol, but I don't have a clue where to begin. Can anyone help me understand the SPI protocol and methods of achieving this with the Spin Stamp?

Comments

  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2008-08-07 14:51
    Aleks,
    For the spin stamp, you can achieve higher input clockfrequency if you
    program the SPI slave driver in assembly. I am not sure up to which
    input frequency but I guess >300kHz should be possible.

    regards peter
  • AleksAleks Posts: 52
    edited 2008-08-07 14:56
    That is a definite improvement. After doing some research I found that SPI is similar to i2c in the way data is transferred, with the exception that SPI uses full duplex communication via he MISO and MOSI pins. The documentation I've been reading suggests that in SPI the slave device may receive a message from the master while it is in the process of transmitting a message to another slave or back to the master. I'm not quite sure what kind of messages to return, but I am assuming that the immediate return during the reading from the master would be an acknowledge statement of sorts? Is there any advice to be offered regarding this?
  • TimmooreTimmoore Posts: 1,031
    edited 2008-08-07 15:54
    depends on the device. Some devices send and receive at the same time, some do not. Look at tlv2543, it sends and receives at the same time - it sends the next channel to read when it reads the previous channel. Others like N256S0830HDA SRAM dont send and receive at the same time. You can communicate with asm at up to clkfreq/8, if the device supports it in either send or receive, if you need to do both up to clkfreq/12 should be possible. There are a lot of spi objects on the ojet exchange to look at including the 2 mentioned plus the is spi_engine which is a more generic spi engine.
  • AleksAleks Posts: 52
    edited 2008-08-07 16:01
    Thank you timmore. I hate asking for so much help, but I'm just going to describe the application and see what everyone thinks the proper structure should be.

    The project is a digitally tunable filter, using an SPI interface to be controlled. Previously, I implemented serial communication via an RS232 port debugged through a hyperterminal program in order to issue commands and receive responses. The most common commands would be "Tune", and "Identify Current Frequency". Logically the latter of the two returns an integer containing the frequency to which the filter is tuned to, for instance "357 MHz". I have also created a version that scrapped the RS232 and replaced it with a 4x4 matrix keypad and an LCD screen. The latest version incorporates an ethernet card and is tuned via a local HTML-based page which displays the part/serial numbers, the current frequency, and a firmware version. Now, I'm interfacing the original RS232 model with an SPI instead of the 9pin connector previously used, and can't decide how to arrange the command structure. Any suggestions?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ~Some men see things as they are and ask "why?"
    I dream of things that never were and ask "why not?"~
  • TimmooreTimmoore Posts: 1,031
    edited 2008-08-07 16:30
    Take a look at the SRAM spec for read/write to the status register. For read you send a command and it returns the value of the status register, for write you send a command followed by the new value of the status register. The read sounds what you want for identify and the write sources correct for tune.
    http://www.amis.com/pdf/ulp_memory/serial_srams/N256S08xxHDA_ds.pdf
  • evanhevanh Posts: 15,545
    edited 2008-08-07 22:32
    A point of clarification. There is no real "protocol" for SPI as such ... Things that you need to specify:
    - What clock edge is used for shifting your simulated shift register. Or the read and write shifts may be phase shifted so both can be specified separately.
    - What polarity the clock pin is.
    - What polarity the data pins are.
    - What bit order is used.
    - How many bits in the word.
    - How the above differ when the port is used as a master or a slave.
    - What the maximum clock rate is. 1-10 MHz is common but others have no problem at 100 MHz. This is only a maximum though, not what you'll actually be using.

    You then need to specify what sequences will be used for reading writing the registers, addressing and the likes.

    As you can see, there is no hard spec. About the only things that are a given is that the clock, read data and write data are all separate pins. ie: With SPI, the devices have free reign to have any protocol they like. This is why a chip select line is important when many devices are on the one bus.


    Evan
  • AleksAleks Posts: 52
    edited 2008-08-08 14:23
    Thats also the beauty and complexity of my project. I get to define the protocol myself. However I've never used SPI before so I don't even know how other SPI devices would work. I'm developing the slave (in this case, a digitally tuned filter [noparse][[/noparse]DTF]). I could use examples of other SPI devices if anyone can help me find them

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ~Some men see things as they are and ask "why?"
    I dream of things that never were and ask "why not?"~
  • tekochiptekochip Posts: 56
    edited 2008-08-08 14:42
    I did a SPI communication between two propeller gadgets, and was surprised by how small the code really is, only 56 longs in assembly.· Take a look at the wikipedia entry on SPI, it does an excellent job of explaining all the variants, and yes, there is no specification.

    http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
  • AleksAleks Posts: 52
    edited 2008-08-08 14:47
    tekochip - is there any way I can take a look at the code you used for ideas?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ~Some men see things as they are and ask "why?"
    I dream of things that never were and ask "why not?"~
  • LeonLeon Posts: 7,620
    edited 2008-08-08 14:55
    The 74HC595 is a useful device for experimenting with SPI. I have one mounted on a small PCB with LEDs on the outputs so that I can see what is going on.

    Leon

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Amateur radio callsign: G1HSM
    Suzuki SV1000S motorcycle
  • Stephen MoracoStephen Moraco Posts: 303
    edited 2008-08-08 16:21
    Aleks,

    ··· I'm using SPI to communicate to the CAN controller in my own project.
    ····· http://propcan.moraco.us/

    ··· I had to start somewhere to learn how it worked as well.· One of the most
    ··· useful starting points I found is an object found in this forum called
    ··· the SPI Engine (crafted by·Beau Schwabe·of Parallax).· This is fully
    ··· parameterized so it works with nearly any SPI device when properly
    ··· configured to match the device (even your own ;-)

    ··· I took this driver and needed much more performance so I created
    ··· a specialized driver based on the SPI Engine.· On my way to a
    ··· version which meets my performance needs I dropped a copy
    ··· to the Propeller Object Exchange.·· See:
    ····· http://obex.parallax.com/objects/227/
    ····(Note the object here is NOT the final version.)

    ··· During my development of the driver and other drivers I
    ··· blogged about what I was changing and why I needed the
    ··· performance and how I got there.· This may be of some
    ··· use to you since there is both discussion and there are
    ··· waveforms showing captures of the actual SPI traffic.
    ··· See:· http://propcandev.blogspot.com/

    ····I've found that this group here in the propeller forum has
    ··· examples for nearly anything I've tried so I thought I'd
    ··· "remember them to you".·· I hope this helps.

    ··· One more thing... every time I've branched into a new
    ··· area wanting to interface to some new-to-me device
    ··· I've been able to find starting code either in the object
    ··· exchange, or this forum or pointed to by the propeller
    ··· Wiki.··You probably·don't want to miss the chance to get
    ··· a leg up by using code found from these sources.· I am
    ····constantly amazed by the open contributions from this
    ··· great group of people.

    Regards,
    Stephen, KZ0Q




    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔


    ·
  • tekochiptekochip Posts: 56
    edited 2008-08-09 12:09
    Sure thing Aleks, the code's at the office so it'll have to wait `til Monday.
  • tekochiptekochip Posts: 56
    edited 2008-08-11 13:07
    Here's the SPI Master object.· This code retrieves two longs from·hub memory and transmits them on the bus.

    {******************************************Master SPI**********************************************
    **************************************************************************************************}
    CON
      BitTime= 80_000_000/800_000 'Clock frequency for a single edge  400KHz appears to be MAX
     
    PUB ReadXSwitch(clk, data, ss, dest_) 'Reads the extended switches
      dest:=dest_ 'Save the destination
      flag:=@flag 'Save the destination
      
      clkMask:= |<clk 'and the pin numbers
      dataMask:= |<data
      ssMask:= |<SS
    
      cognew(@entry, 0) 'Launch the cog, but don't wait for result
    
    PUB IsBusy 'Returns the status of the SPI Master
      return flag
     
    DAT
                            org     0
    entry
    
    '__________________________________________Initialization_________________________________________
    
              muxz          outa,SSMask             'Make sure the SS is low
              muxz          outa, ClkMask           'Make sure the clock is low too
              muxnz         dira, SSMask            'SS is an output
              muxnz         dira, ClkMask           'Clock is an output
              muxz          dira, DataMask          'Data is an input
              movd          rxIndirect, #switch0    'Look at the first switch
              mov           bit, #1                 'and first bit
              mov           longs, #2
              mov           switch0, #0             'Clear the data registers
              mov           switch1, #0             'Clear the data registers
    
              
    '___________________________________________Assert SS______________________________________________
              mov           bitDelay, cnt           'Get the current time
              add           bitDelay, bitPeriod     'Add the time to wait for the first clock
    
              call          #WaitBit                'Wait a couple of bits for the Slave to see SS low
              call          #WaitBit
              muxnz         outa, SSMask            'SS asserted
              call          #WaitBit                'Wait a couple of bits for the Slave to see SS high
              call          #WaitBit
    '__________________________________________Receive Loop____________________________________________
    Loop
              muxnz         outa, ClkMask           'Set the clock high
              call          #WaitBit                'Wait a clock
              test          DataMask, ina wc        'What is the bit?
              muxz          outa, ClkMask           'Now low to read bit
              call          #WaitBit                'Wait a clock
    RxIndirect
     if_c     or            0, bit                  'Toss this data on
              shl           bit, #1 wz              'Next bit over
     if_z     mov           bit, #1                 'Restart if second long
     if_z     movd          RxIndirect, #switch1    'and point to it
     if_nz    jmp           #Loop
              djnz          longs, #Loop wz         'Until done
     
    '____________________________________________Idle SS_______________________________________________
              muxnz         outa, SSMask            'Z flag up, push SS down
              
    '___________________________________________Store Data_____________________________________________
              wrlong        switch0, dest           'save the low long
              add           dest, #4                'Next long
              wrlong        switch1, dest           'Now the high long
              mov           dest, #0                'We need a zero to write
              wrlong        dest, flag              'So write the zero to flag
     
    '______________________________________________Stop________________________________________________
              cogid         dest                    'Get our cog#
              cogstop       dest                    'and stop it
    
    '********************************************WaitBit***********************************************
    WaitBit
              waitcnt       bitdelay, bitPeriod     'Wait for it
    WaitBit_Ret
              ret
     
    '********************************************Variables*********************************************
    dest      long          0                       'The address of the SPI structure
    flag      long          0                       'The address of the XFlag
    ClkMask   long          0                       'Which pin is clock on
    DataMask  long          0                       'Which pin is the data on
    SSMask    long          0                       'And the slave select
    BitPeriod long          BitTime                 'How long each bit is
    bitDelay  res           1                       'Used for waitcount delay
    switch0   res           1                       'Switch data as it is put together
    switch1   res           1
    bit       res           1                       'Which bit is being read
    longs     res           1                       'How many longs have been read
    
Sign In or Register to comment.