Electronic – SD Card SPI Interface Issue – Read Operation Returns 0x3F/0xFF instead of 0x7F/0xFE

sdspi

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.

Best Answer

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.