2
\$\begingroup\$

I have written an SPI driver for SD cards (in micropython). There was nothing available for my specific hardware (a pycom.io LoPy SoC), so I started by studying a long list of drivers, written in python and C, and the variety of approaches was staggering. Many had useless/unecessary code, "plain wrong" code, or code that might work on some cards but not others. Needless to say, the variety of different SD cards and their loose adherence to the standard does not make this an easy task.

In any case, out of the dozen or so SD cards (all microSD) I have for testing (various brands, speeds, and sizes), all but two work perfectly. Both are different brands, speeds, and sizes, but they behave (badly) in exactly the same way. Both initialize correctly, returning all the expected "meta" data, but when doing the first data read, they fail and fail consistently.

In SPI mode, reading a "sector" is started by sending a CMD17 in the normal way (same code in my driver that sends all other commands), then reading one byte at a time, waiting for a "token" that marks the start of the data (in this case, the token is 0xFE). For all of my working cards, I consistently get 0xFE as the second byte (the first byte is almost always 0x7F, but that's supposed to be irrelevant--the SD spec only cares about the first 0xFE). But on the two failing cards, I consistently get 0x3F followed by 0xFF. The code fails, because no 0xFE was ever seen. But the interesting thing here is that 0x3F/0xFF is 0x7F/0xFE shifted by one bit. That's why I feel like this is a hardware problem.

I've read just about everything I can get my hands on regarding SD over SPI. I've looked at the signals with a scope (nothing unusual to report). My circuit is powered by a high-quality bench supply and has sufficient bulk and decoupling capacitance, and has very short wires. I've also tested the two cards that fail on my PC's SD card slot, and they work as expected. Yet, the issue I describe is 100% consistent.

So the question is what to look at next? I've been at this for days, and I'm out of ideas at the moment.

\$\endgroup\$
  • 4
    \$\begingroup\$ Post timing(scope)/simulation pictures against SPI clock. Which edge of the SPI clock you use to set control lines for SD-card? You should know that SD-card samples data at rising edge, thus the best way is to set control and data on previous clock's falling edge. \$\endgroup\$ – Anonymous May 24 '17 at 17:10
  • \$\begingroup\$ @Anonymous Thank you for the idea, but I've checked logic levels and clocking extensively. All looks good (and in fact, the failing cards are indeed sending what I'm getting, with very clean signals). \$\endgroup\$ – eric May 24 '17 at 23:37
4
\$\begingroup\$

I figured it out. The issue has to do with these two cards being sensitive to my releasing the CS line between issuing the read command (CMD17) and starting to "poll" for the token. All other cards work fine (and in fact, all other SD SPI driver implementations that I can find do release CS between the command and the poll). I went back and reviewed the SD SPI documentation, and I have to say it's not very specific on this point. In any case, the modified driver not only works on the two cards that were failing, but my entire stack of test cards.

To clarify: My original driver (based on my interpretation of the SD spec and looking at other drivers I could find) treated CMD17 like a normal command: assert CS, send the command sequence, read back the response byte, and then deassert CS. For CMD17, the next step would assert CS again, then start looking for the "data token". This actually worked on most of my test cards, but not on two of them. The change treats CMD17 (as well as other read and write commands) specially, so it leaves CS asserted after sending the command and looking for the "data token"; it works perfectly on all cards I have.

\$\endgroup\$
  • \$\begingroup\$ +1. Thank you for putting in the effort to answer your own question. But please tweak this answer to explicitly state: what exactly did you do to the CS line between the read command and polling for the token to get it to work? Are you saying you now always inactivate the CS line (raise high) between the read command and polling? \$\endgroup\$ – davidcary May 25 '17 at 2:13
  • \$\begingroup\$ Seems he was deactivating CS for some time after issuing CMD17, and then activating it back to check for data token. Datasheet for Samsung SD-cards says: The CS signal must be continuously active for the duration of the SPI transaction (command, response and data). This info is missing in simplified sdcard specification available for download at sdcard.org. \$\endgroup\$ – Anonymous May 25 '17 at 4:58
  • \$\begingroup\$ I never did this way, and while it seems it is possible - not forbidden by the protocol, and not covered by first-hand documentation at all, there's great chance that communication will get out of sync (this is what OP experienced). Section 7.2 of SD-specifications part 1 says Every command or data block is built of 8-bit bytes and is byte aligned to the CS signal thus it is a very good question when to deactivate CS not to break this 8-bit-sequence counter within the card. \$\endgroup\$ – Anonymous May 25 '17 at 5:11
  • \$\begingroup\$ @Anonymous Good info from the Samsung datasheet. But ironically, my Samsung cards work fine either way (keep CS asserted the whole time or deassert it between the command the data). \$\endgroup\$ – eric May 26 '17 at 3:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.