SPI blues - need a guru's eye
Erlend
Posts: 612
in Propeller 1
Some time back i wrote my own SPI driver because the only one I could find on OBEX was providing SHIFTIN and SHIFTOUT routines, but nothing in the fashion of: rxData:= Shift(txData. How I understand the principle of SPI, data is read in as it is written out. Therefore I wrote a SPI library to provide that ( rx:= Transfer(tx)). This excersise was a stretch for me at my skill level, so I was quite proud too.
Now I supect there is a bug hidden in there. I am at present working at getting up and running with a powerSTEP01 stepper motor controller, and the first or last '1' bit goes missing when writing to the chip, depending on SPI mode.
Needless to say I would want that bug in my SPI code to be killed, but to get on with talking to the chip I would like if there is some other SPI object with the same functionality that I can use.
Thanks,
Erlend
Now I supect there is a bug hidden in there. I am at present working at getting up and running with a powerSTEP01 stepper motor controller, and the first or last '1' bit goes missing when writing to the chip, depending on SPI mode.
Needless to say I would want that bug in my SPI code to be killed, but to get on with talking to the chip I would like if there is some other SPI object with the same functionality that I can use.
Thanks,
Erlend
Comments
I know some of the timing diagrams seem to indicate read/write which only leads to this confusion. Figure 28 is fairly typical, send a command byte then with the MOSI low just read the 3 data bytes etc.
Thanks, but isn't iMode & %10 having the same effect? I tried your suggestion, but the bug is still there.
Erlend
Agree, but some chips do behave as per SPI (duplex), ( e.g. the one that got me started on SPI, the nRF24L01+).
I would prefer to do the SPI comms similar across different chips.
Erlend
iMode & %10 just clears the LSB. For mode 0/1, iIdleCLK will be %00. For mode 2/3, iIdleCLK will be %10. When you assign OUTA[PINclk], it is only to iIdleCLK[0], which is always zero.
* CLK is Idle High.
* Write on the falling edge
* Read on the rising edge
I think the problem you are running into is that you are performing the write too early (as if PHA=0). Try the following modification:
Do you remember what command(s) in the MCP2515 use full-duplex SPI?
This isn't about the MCP2515, it's about code and my belief that sometimes it's not worth having a "this object does everything in every possible circumstance" object when few lines of code will do the trick.
Ah, now I see. Thanks!
Erlend
Yes, that is a perspective I sometimes need - each time I get hung up in developing 'the ideal code' instead of just something that gets the job done. Thanks for that PRI, I will put it into my toolbox, for sure.
Erlend
Seairth,
I am very grateful for that you have taken the time to review my code and suggest how to fix the bugs! With the modifications you have suggested, it works nicely. I will have to wait for a moment when my head is clear (at least clearer...) to write up the SPI mode 3 timing diagram and step through the old and new code - to fully understand what your changes do.
Erlend
I think that's why @JonnyMac's comment is worth paying attention to. In SPI, there are only four timings (the four modes). Any one of them is easy to understand on their own. It's when we try to come up with an algorithm that covers all four timings that things get difficult. However! We are interacting with hardware that will only ever make use of one of those timings. It will never change. All we need is enough code to handle that one timing scenario. This leads us toward the idea that it can be easier (at least, in this case) to have four separate code snippets, each of which are simple and understandable, that we choose from. And, as an added benefit, it will be faster (if only marginally), which is often an important design factor for this sort of work.