Shop OBEX P1 Docs P2 Docs Learn Events
Faster SPI in C (GCC), how? — Parallax Forums

Faster SPI in C (GCC), how?

mh3soldiermh3soldier Posts: 3
edited 2014-09-02 19:43 in Propeller 1
Hello,

Is there a way to specify the frequency for the functions?:

shift_out(7, 8, MSBFIRST, 7, 0b1010110);
shift_in(7, 8, MSBPRE, 8);

Using those two functions will start a COG, right? So there should be a way to specify the frequency, am I right?


Thanks in advance.

Comments

  • ElectrodudeElectrodude Posts: 1,658
    edited 2014-09-01 10:45
    They don't start a new cog. They do it in the cog that calls them.

    Do you want faster or slower? Either way, you can't change the speeds of these functions. They send as fast as they can, which is pretty slow because they use many higher-level functions instead of directly manipulating OUTA, INA, and DIRA. I wrote my own significantly faster one (and it's still sad how slow it is), but I don't have it on this computer and it didn't support all of the different modes - only the ones I needed (but it's pretty easy to change it). There might be other functions in simpletools that you can configure, but I doubt it. Unless you can find someone else's library that's faster than simpletools', your best bet is probably writing your own. If you need somewhere to start, there's a SPI_Spin.spin in the Spin library that comes with the Propeller Tool that you might be able to port to C.

    Here's the link to the Spin SPI library: http://obex.parallax.com/object/566. It says it's for a temperature sensor, but that's just the demo. You just want the SPI_Spin.spin in the zip file. It should be pretty easy to port to C. If you've never seen any Spin before, note that it uses indentation for blocks instead of curly brackets.
  • KyeKye Posts: 2,200
    edited 2014-09-02 07:09
    The fastest speed you can get is 20 MHz write and 10 MHz read with an 80 MHz system clock. You'll need to write the code in ASM using a cog counter to drive the clock. See the SPI code in this driver for an example: http://obex.parallax.com/object/16
  • DavidZemonDavidZemon Posts: 2,973
    edited 2016-01-13 14:30
    PropWare's SPI library currently maxes out at ~900kHz but I got a bunch of suggestions for improvement over the weekend to fix it up. The clock is completely configurable so you can run whatever frequency you like up to ~900kHz (I promise.... that number will get up to ~4MHz very soon).

    Here's the class documentation:
    http://david.zemon.name/PropWare/classPropWare_1_1SPI.xhtml

    Note: shift_*_fast and shift_*_sector are planned methods that have not yet been implemented (I think shift_*_fast just calls the normal shift_* assembly at the moment), but these are the methods that will be capable of achieving 4 MHz.

    David
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-09-02 19:43
    One of the simple routines I use is for reading OR writing and it's a simple loop that also assumes it's always 8-bits. Normally of course transfers are multiples of 8 bits so I always left justify my data and call it 4 times without reloading the data to get it to transmit the whole 32-bits. Same goes for reading pretty much. Since this SPIRD and SPIWR are implemented as instructions and runs in the same cog as my Tachyon VM I can't afford to use the counter method but this works at 4MHz and is very efficient for it's code size. I have dedicated registers for the I/O masks so they only need to be setup once.
    [FONT=courier new]' Simple fast, bare-bones SPI - transmits 8 bits MSB first -
    ' data must be left justified - data is not discarded
    ' Usage: $1234 16 SHL SPIWR SPIWR 'transmit 16 bits
    ' SPIWRX permits variable number of bits if spicnt is set directly with @SPICNT COGREG!
    ' SPIWR ( data -- data<<8 )
    ' SPIWRX could be an instruction if we manually set the spicnt beforehand
    SPIWRB      shl    tos,#24          ' left justify and write byte to SPI (2.8us)
    SPIWR       mov    spicnt,#8        ' code execution time of 2.25us + overhead
    SPIWRX      rol    tos,#1 wc        ' assume msb first (140208 update now rotates)
                muxc   OUTA,spiout      ' send next bit of data out
                xor    OUTA,spisck      ' toggle clock
                xor    OUTA,spisck      ' toggle clock
                djnz   spicnt,#SPIwrX
                jmp    unext
    
    
    ' Receive data and shift into existing stack parameter
    ' If MOSI needs to be in a certain state then this should be set beforehand
    ' Clock will simply pulse from it's starting state - normally low
    ' Useage:  0 SPIRD SPIRD SPIRD SPIRD     'read 32-bits as one long
    ' SPIRD ( data -- data<<8 )          ' 2.8us
    SPIRD       mov    spicnt,#8         ' always read back 8-bits
    SPIRDX      xor    OUTA,spisck       ' toggle clock
                test   spiinp,INA wc     ' read data from device
                rcl    tos,#1
                xor    OUTA,spisck       ' toggle clock
                djnz   spicnt,#SPIRDX
                jmp    unext
    
    [/FONT]
Sign In or Register to comment.