Shop OBEX P1 Docs P2 Docs Learn Events
Full-Duplex SPI? — Parallax Forums

Full-Duplex SPI?

K2K2 Posts: 693
edited 2011-12-05 16:52 in Propeller 1
SPI is inherently full-duplex, but this fact is rarely exploited, it seems. I was unable to find anything SPI-related in OBEX that implemented simultaneous Tx and Rx. Doesn't seem like it would be too difficult to modify one of the existing SPI engines for this - seems like it would just involve sampling MISO one half clock after asserting MOSI. Before attempting such a modification, though, I wanted to check to see if anyone knew of such a piece of code already in existence.

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2011-05-26 20:08
    I'm not aware of actual code but I had some idle thoughts [post=991372]here[/post]. It isn't including any clock generation, just getting the bits in and out.
  • K2K2 Posts: 693
    edited 2011-05-26 20:24
    Thanks, kuroneko. I didn't see that exchange when it happened so I'm grateful you brought it to my attention. It looks like there is a lot of great information and ideas to digest there. I'm a bit chagrined to discover that Duane posted practically the same question just a month ago. I wish I was better at getting useful information from the Forum search feature.

    BTW, what a great job you did recently in discovering the bug in Clock.spin! You constantly amaze me.

    (I just finished a long project at work. I'm very excited to get back to the Prop. What a great platform! The more I use IAR EWARM, the more I love PropTool and the Propeller.)
  • Mike GreenMike Green Posts: 23,101
    edited 2011-05-26 20:29
    Many SPI devices don't use the full-duplex capability of the protocol. One exception is the Memory Stick Datalogger in SPI mode. Even there, it doesn't use the full-duplex capability much.
  • K2K2 Posts: 693
    edited 2011-05-26 20:42
    Thanks, Mike. It looks like DataloggerSPI.spin would be a great starting point if only the crucial parts were written in PASM.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-05-27 02:27
    K2, I decided I didn't really need full-duplex SPI after all. The only time my device used full-duplex was to output the status register as the first byte was written to the device. I just held the MOSI lines high while reading since the device wanted $FFs written as it was read from.

    Post #9 of this thread has the driver I wrote.

    I will probably revisit the driver again soon to see if I can apply the things I just learned writing a driver for 23K256 SRAM chips.

    I'll post my driver for these chips later today. I also wrote a driver that uses eight of these SRAM chips in parallel (I'll also post this later today).

    I'm sure there are other drivers for the 23K256 chips out there; I just wanted to see if I could write one myself. Compared with other SPI devices, these chips are very simple to communicate with.

    I learned something about sharing the MOSI and MISO lines yesterday when working on this driver. It turned out to be important to release the data line as soon as possible after clocking out the last bit of data prior to reading from the chips. If I left the data lines high after the last bit for a couple of instructions, it would conflict with the chips outgoing data and I'd get erroneous reads. This wasn't a problem when using only one chip but it was a problem when using eight chips at once.

    Duane
  • lonesocklonesock Posts: 917
    edited 2011-05-27 09:15
    I wrote a full-duplex SPI driver for some ADC chips I use at work. Here's my strategy:

    - set Counter A to NCO mode, single pin output on the Data Out line (Data In on the SPI chip)
    - set Counter B to NCO mode, single pin output set to the clock line
    - set the data to be written out into PHSA, and left shift it to the 1st bit out is in bit 31 (which means the NCO mode drives the data out line to the value of that bit)
    - start clock line by setting PHSB to a good initial value, and setting FRQB such that the clock pin toggles at the correct period (either 8 clocks for the unrolled loop, or 12 clocks for the djnz loop)
    - now do the following for however many bits you need:
    test maskSDO, ina wc
    rcl  phsa, #1
    
    - stop your clock line by setting FRQB to 0 (note, you may have to do this after the final "test", but before the final "rcl" to make sure you don't send out an extra clock)

    That's basically it.

    Jonathan
  • K2K2 Posts: 693
    edited 2011-05-27 11:40
    @Duane: I think you're right on target. Most of the time there is no need for full-duplex performance. In fact, most SPI Slaves aren't designed to operate full-duplex even if you wanted to. Unfortunately I've got one of the few Slaves out there that not not only handles simultaneous Tx and Rx, but requires it - it is fundamental to its operation.

    Your code looks like an excellent place to start on FD SPI, partly because it implements just the basics. In many SPI examples, there are massive amounts of code I would have to excise before moving forward. And that's often problematic because of all the dependencies.

    fwiw, I was born in Poky (but grew up elsewhere). I'm happy to see such an active prop head in the area!

    @ Jonathan: Near as I can tell, you have outlined the perfect high performance FD SPI in a Prop. As my humble first attempt grows up, it will be hugely educational to follow each step you've sketched out. Other than implementing canned solutions from Phil and kuroneko, I've done little with regard to the ancillary timing hardware that the Prop provides, so I don't yet understand the full picture of what you are proposing - but it's the perfect opportunity to change that.
  • LawsonLawson Posts: 870
    edited 2011-05-27 16:27
    lonesock wrote: »
    I wrote a full-duplex SPI driver for some ADC chips I use at work. Here's my strategy:

    - set Counter A to NCO mode, single pin output on the Data Out line (Data In on the SPI chip)
    - set Counter B to NCO mode, single pin output set to the clock line
    - set the data to be written out into PHSA, and left shift it to the 1st bit out is in bit 31 (which means the NCO mode drives the data out line to the value of that bit)
    - start clock line by setting PHSB to a good initial value, and setting FRQB such that the clock pin toggles at the correct period (either 8 clocks for the unrolled loop, or 12 clocks for the djnz loop)
    - now do the following for however many bits you need:
    test maskSDO, ina wc
    rcl  phsa, #1
    
    - stop your clock line by setting FRQB to 0 (note, you may have to do this after the final "test", but before the final "rcl" to make sure you don't send out an extra clock)

    That's basically it.

    Jonathan

    You sneaky son of a mother! That "rcl phsa, #1" line is inspired. (definitely going in my bag of tricks)

    If you want less voodoo involved with setting up the clock on counter B, set the CTRx up the same as Lonesock suggested. Set FRQB to 1 and add "ABSNEG PHSB, #4" inside the loop whenever you want a clock pulse. (4 [clocks] long in this case) One instruction slower per bit, but better for first cut code as there are fewer things to go wrong.

    Lawson
  • K2K2 Posts: 693
    edited 2011-05-31 11:05
    Ultimately wrote the code from the ground up rather than pare back an existing SPI object. The educational benefits were worth it and the code is really small and simple. It does just what is needed and nothing else. What a great platform the Prop is!

    I'm starting to appreciate the brilliance of the ideas advanced by lonesock and Lawson. They are speed enhancements, for sure, but they also produce elegant and simple code, and make better use of the available hardware. It has been a great education. Many thanks to the great foruministas here!
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-05-31 11:17
    K2, So did you use the Prop's counters in your driver?

    I need to learn how to do that too.
  • K2K2 Posts: 693
    edited 2011-05-31 12:47
    Duane Degn wrote: »
    K2, So did you use the Prop's counters in your driver?

    Yes. I wrote a few lines of bit-banging code (figuring I'd complete the first version that way, and later worry about improvements) and decided instead to reread lonesock's instructions. By then, his approach seemed do-able in an incremental way, using a scope to examine what was going on with the SCLK and MOSI lines. I never would have started out that way without 1) confidence that it can be done and 2) an excellent outline of how to do it. I don't have all the kinks worked out of RX yet, not because of any show-stoppers, but simply because the top-level SPIN portion is also being fleshed out as the PASM SPI engine becomes more functional.
  • MasterCMasterC Posts: 39
    edited 2011-12-05 16:52
    Hi K2,

    By any chance, did you ever publish this full duplex SPI object to the OBEX? It sounds like you went about it in the most optimal way, and I think it would give lots of people a head start with faster SPI code. I'm about to do the same thing...but how many of us should really re-invent this wheel?
Sign In or Register to comment.