0
\$\begingroup\$

I am interfacing an SD card through SPI using an AVR microcontroller (more specifically it is the Uzebox console).

I can successfully initialize the card with turning CRC check ON with CMD59 (so I have a proven working CRC7 algorithm), and can read sectors from it (dumping the data read by CMD17 gives correct results: I see what is on the card proper).

What I can't seem to get working is a CRC check for the data sectors using the CRC bytes received from the card.

I currently have three SDSC cards which I verified to behave in the following manner with my algorithm:

  • Two of the cards give the same value for both CRC bytes, neither corresponding the result of CRC-CCITT with either 0x0000 or 0xFFFF start value (tested with multiple sectors, the values change according to the data of the sector, but the two bytes are always the same).

  • The third card seems to have no CRC at all, providing 0x0000 on these bytes.

The SPI transmission code for those final bytes seem correct, I did some steps to verify that I indeed read what I want to including that I really do two SPI transactions for the two bytes.

Anyone have any idea what could be happening there? Or should I just forget about those CRC bytes? (maybe the cards just not implement them or do it incorrectly in SPI mode)

\$\endgroup\$
2
  • \$\begingroup\$ Did you verify you turned CRC checking on successfully? What happens when you send a broken CRC? Does the card care? \$\endgroup\$
    – JimmyB
    Commented Jul 31, 2017 at 12:16
  • \$\begingroup\$ I did so with a command after CMD59: it appears to react to bad CRC7 there (Elite Pro 256Mb 94110-925.A00LF 20456871). I didn't try sector writes though. \$\endgroup\$
    – Jubatian
    Commented Jul 31, 2017 at 12:36

2 Answers 2

1
\$\begingroup\$

So, regarding the two "CRC-delivering cards": It's kind of hard to debug this without any example data and CRC, but the most common problem one encounters is that the generator polynomials are "meant" the other way around, ie. whether \$x^0\$ corresponds to the first or the last bit.

Checking is easy: just have test data that you have both in original and reversed bit order, and see what makes sense.

Now, you've tested with 0xFFFF and 0x0000 already, which are symmetrical. At least for 0x0000, the result of a polynomial should definitely be zero, shouldn't it? What are you expecting, what are you getting?

Reference:

http://users.ece.utexas.edu/~valvano/EE345M/SD_Physical_Layer_Spec.pdf , p. 54f

\$\endgroup\$
4
  • \$\begingroup\$ Thanks, I had the docs, what I passed over in it was that it contained a test sequence (page 44). By that I discovered that indeed I had the CRC bit order reversed. Another thing I got to dicover is that contrary to my expectations, I still got to mess up with the behavior of an AVR flag, so now I see that the cards deliver the "right" CRC in Little Endian order (This particular detail is missing even from the specs as far as I see!). I will revise the code and see what happens with the other card. \$\endgroup\$
    – Jubatian
    Commented Jul 30, 2017 at 14:23
  • \$\begingroup\$ OK, I guess done for now. I have the code working, two cards report CRC which I can check, the third have it fixed 0x0000. Guess it is necessary to be prepared for this case too, then (and verify data if necessary by for example re-reading). \$\endgroup\$
    – Jubatian
    Commented Jul 30, 2017 at 14:50
  • \$\begingroup\$ It would actually be interesting to hear what make, model and capacity the non-CRCing card is. Haven't read the standard closely enough, but I don't think it's an optional feature, and that would be a reason to not use that card \$\endgroup\$ Commented Jul 30, 2017 at 16:26
  • \$\begingroup\$ Elite Pro 256Mb with a nice China Export (CE) marking. 94110-925.A00LF 20456871. Why I am somewhat concerned is that it is a "consumer" product (hobbyist, but rather on this side), there is no much control over what kind of SD cards it might have to deal with. \$\endgroup\$
    – Jubatian
    Commented Jul 31, 2017 at 12:25
0
\$\begingroup\$

Here are algorithms which I found correctly calculating CRCs.

The SD Command CRC:

/* CRC7 table (for SD commands) */
static unsigned int sd_crc7_table[256];

(...)

/* Running CRC7 calculation for a byte. */
static unsigned int sd_crc7_byte(unsigned int crcval, unsigned int byte)
{
 return sd_crc7_table[(byte ^ (crcval << 1)) & 0xFFU];
}

(...)

/* Generate CRC7 table */
for (byt = 0U; byt < 256U; byt ++){
 crc = byt;
 if ((crc & 0x80U) != 0U){ crc ^= 0x89U; }
 for (bit = 1U; bit < 8U; bit ++){
  crc <<= 1;
  if ((crc & 0x80U) != 0U){ crc ^= 0x89U; }
 }
 sd_crc7_table[byt] = (crc & 0x7FU);
}

(...)

crcval = 0x00U;
crcval = sd_crc7_byte(crcval, first_byte);
(...)
crcval = sd_crc7_byte(crcval, last_byte);
crc_byte = (crcval << 1) | 0x01U;

The SD Data CRC:

/* CRC16 table (for SD data) */
static unsigned int sd_crc16_table[256];

(...)

/* Running CRC16 calculation for a byte. */
static unsigned int sd_crc16_byte(unsigned int crcval, unsigned int byte)
{
 return (sd_crc16_table[(byte ^ (crcval >> 8)) & 0xFFU] ^ (crcval << 8)) & 0xFFFFU;
}

(...)

/* Generate CRC16 table */
for (byt = 0U; byt < 256U; byt ++){
 crc = byt << 8;
 for (bit = 0U; bit < 8U; bit ++){
  crc <<= 1;
  if ((crc & 0x10000U) != 0U){ crc ^= 0x1021U; }
 }
 sd_crc16_table[byt] = (crc & 0xFFFFU);
}

(...)

crcval = 0x0000U;
crcval = sd_crc16_byte(crcval, first_byte);
(...)
crcval = sd_crc16_byte(crcval, last_byte);
crc_byte_0 = crcval >> 8;
crc_byte_1 = crcval & 0xFFU;

The crc_byte and crc_byte_0 and crc_byte_1 values may be used to provide the necessary CRC data towards the card or for comparison when reading (data sectors). For the data sectors, crc_byte_0 comes first (so CRC is Big Endian on the card).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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