Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Trying to write SPI SD Card reader in verilog, getting weird data from CMD17

Status
Not open for further replies.
Newbie level 4
Joined
Jun 22, 2023
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
125
Hello all, I'm doing a simple noisemaker for a Lattice MachXO3 board using 16-bit digital audio samples, and after faffing around with tiny EEPROMs to store the samples, I decided to dive into micro SD. I eventually want to get to the point where an end user can just toss .WAV files onto the root of a FAT formatted micro SD (from a desktop OS), and then be able to select from those in-circuit using a character LCD or something. It's a slightly weird use case for micro SD, since I only really want to read 2 bytes at a time (one 16-bit sample).

Anyways, at the current point of prototyping, I have a lot of known factors (the circuit is ALWAYS 3.3V, the card is ALWAYS the same generic 2GB card formatted in FAT16), so I can make a number of assumptions.

I've successfully gotten to the point where I fully initiate the card (74 SCLKs -> CMD0 -> CMD8 -> ACMD41 -> CMD16) with SCLK at 400kHz until after the ACMD41 returns 0x00 R1 response, then I clock it up to 6 MHz. I've also successfully done CMD9, CMD10, and CMD58 just to be able to check the CSD, CID, and OCR registers and they all look fine too. For now, I'm setting BLOCK_LEN to 512 with CMD16 for max FAT compatibility.

However, when I finally go to issue the CMD17 to read a single block, I get a good R1 response (0x00), maybe 300-400 SCLKs later, I get the 0xFE token and...instead of data from the card, I get 0x55AA repeated 16 times, followed by what seems to be 480 bytes of random data and the CRC16. However, it's the SAME random data every time I issue the CMD17, regardless of what address I put in it. Of course I get the invalid address bit set in the R1 response if my address is not aligned to multiples of 512, but other than that, it doesn't matter if I use address 0x00000000, 0x00000200, or 0x01EA3400, it's 0x55AA 16 times followed by the same data. If I try setting the BLOCK_LEN smaller, I get the exact same data, but just less of it.

I understand 0x55AA is a common test pattern, and also significant as being the last two bytes as a signature of FAT, but I'm not aware of anywhere it's supposed to appear 16 times in a row at the beginning of a 512 byte block. There isn't any significance that I can tell to the rest of the "data". There aren't any particular patterns I can recognize, there isn't any English in it when you convert to ASCII, even after trying inverting bits, byte swapping, etc. More curiously, if I try a different micro SD card, it does the same thing, but the "junk data" is different. Also repeatable, but different than the 1st card. Still starts with 16 0x55AAs though. The 1st card is formatted FAT16 and has two .WAV files on it. The 2nd card is factory new, and had never even been plugged into anything until now.

At some point soon, I think I'm just going to try using a known software library and get this working on an Arduino, so I can look at the SPI with a logic analyzer and see what's different from my implementation, but I was curious if anyone here has come across this, or had any insight. What even is this data?!

For completeness, here is what I'm reading off the card:
Code:
55 aa 55 aa 55 aa 55 aa 55 aa 55 aa 55 aa 55 aa
55 aa 55 aa 55 aa 55 aa 55 aa 55 aa 55 aa 55 aa
49 e2 6a a9 21 76 51 fe d2 81 1f 60 1f 7b b1 bc
6c 10 1a 7f 39 05 f5 8b 0b c8 ef 3e 9b 41 7d d9
64 d3 78 77 59 5a d5 d5 1d 4f 82 65 b8 93 c4 fc
41 e2 e2 d0 41 d6 bc c8 9c b9 be 42 e0 2e 9b 54
dd e8 52 4e a5 ea 83 47 04 3e 98 68 9a c4 98 28
76 50 0d 58 ae a3 85 e7 3f 2d 76 a7 02 db 47 1a
fc ce 2c 54 15 98 fe 69 eb 72 ff ff a5 58 57 56
fc 72 a1 56 c9 8d 3b 54 64 5f 8d ff 71 3b fe 4d
bd 7b d1 e7 2f ff a3 ad 33 e1 4e 44 da 56 55 47
dd 30 b4 fc be 61 1c 12 a2 2c e0 da eb d7 41 3d
20 73 cd bc b0 f5 89 e2 12 3a ae ec 53 34 87 43
3b ed 0a e2 ce ab bf eb 24 15 18 7a ab d3 ed 90
23 91 4b 62 a6 dd 7g 42 a2 97 f4 ab c7 59 b8 85
a0 b0 cd 64 c6 15 a6 82 5c f1 b8 4d f1 88 91 43
b9 25 17 01 22 2c 3b 85 40 f9 ca c9 95 d3 41 4c
94 e3 e4 e2 c9 ec 1a 89 0c e2 bd 61 f2 02 0e e9
e2 be 63 e2 27 13 93 8c 4e b7 58 55 a5 c2 a3 58
d2 ea 53 b8 b1 72 94 45 15 d1 50 6a 1d 3c 71 32
e2 98 19 59 45 8f bf 1e 6e ae 1d bc da 4c 24 19
f2 f0 9c 7d bf 9a 29 d3 73 33 05 19 62 bb 54 1e
74 fe bc d4 a4 05 b2 fa 2d 99 38 76 2f a4 ad f2
51 6b 39 e2 b5 b6 40 4b 38 12 6d 65 23 16 2d 15
02 78 b5 7c 61 35 55 19 55 0e 4a 99 a3 7f d6 b4
4b 06 53 63 f1 29 a0 03 33 1c fd 7f 87 d4 c6 90
0e c2 8c 3b 9a 8b d9 fc b6 a6 e2 53 40 45 32 df
ce 77 0b 5f a0 0d 5c bf c5 0c b5 ee 39 7e c8 0d
26 e9 87 67 7a 57 a3 b1 5b 40 46 92 c6 ee 1a 6b
70 88 f0 0a 27 33 45 0n 1e 0a 64 62 cb ed 47 e3
6a 1b 7c 3a 2e c6 54 97 15 a7 80 d9 c7 7b f6 af
fd 31 7c ca 85 e3 93 9a 5d 97 3b 19 dc b9 44 be

CRC16: b3 3b
 
Last edited by a moderator:

An update:
As I mentioned I had planned to do in the previous post, over the weekend I found a mature microcontroller project that uses SD over SPI, compiled and deployed it, verified functionality, and recorded the SPI signals with a logic analyzer. I used it with the same 2GB generic card, and I was successfully able to read the root directory from the UART console. It saw the two .WAV files as I expected. I was also able to read a file out, and the bytes read just as I expected them to, and no sign of the weird data.

When I look at the SPI, there are indeed some notable differences that I can try to implement, but to be honest, I'm hard-pressed to say what exactly is causing the difference in behavior. Here is what I observed:

- Naturally, since it's a microcontroller, the SCLKs all come in visible groups of 8 with clock-stretching, unlike my FPGA implementation which has constant steady SCLKs whenever CS is asserted. This is expected, and almost certainly not significant in terms of why I'm getting my weird result.
- They send several hundred SCLKs with CS high at the beginning before any CMDs. All documentation says "send at least 74 SCLKs" in this manner, so natually MY design sends exactly 74. Theirs does like 500 though.
- There are several null bytes added. Meaning the uP toggles SCLK 8 times with MOSI kept high. There is one of these right after CS assert before each CMD. This one I kind of understand because I think the software is really trying to clock in MISO to make sure it's idle and ready. There's also one after every de-assert of CS, meaning it happens while CS is high. I don't really understand the point of that one. The REALLY mystifying one to me though, is that before each CMD17 there are TWO of these null bytes, so it toggles SCLK 16 times before sending the CMD.
- The initialization routine reads the CSD and OCR registers (with CMD9 and CMD58) while at the slower SCLK of 400 kHz, even after getting the 0x00 R1 response from ACMD41. It also sets the block length (with CMD16) at the slower speed too. Basically everything is slow speed literally up until it starts sending the CMD17s. That seems FINE, but everything I've read indicates that you should also be fine to run at the higher SCLK after getting the 0x00 R1 response.
- I also noticed the OCR got read twice. Once before ACMD41 and again after. Seems a bit redundant, but the software can verify the idle bit in the OCR changing from before to after I guess.
- Their initialization includes a CMD59 that turns on the CRC checking, and sure enough every CMD it sends calculates and transfers a valid CRC with every CMD. Everything I've read says that without invoking CMD59, SPI mode defaults to not requiring CRC checking, and it's fine to run without it

So far, I just real quick tried adding the two null bytes before my CMD17s, and sadly that didn't change anything. I guess I'll just try changing my design one thing at a time until it literally gives the same signals with the same timing if necessary, and figure out which little thing is making the difference here. I'm obviously hoping most of all that it's not actually necessary to implement CRC.
 

As no one else has replied to you I thought that I would have a go at sorting out your problem. I think that your problem is due to the address that you are sending to the SD card being 512 times the sector number you want to read. There are various SD card standards notably in this case version 1 and version 2 you should read and understand both versions. The standard version 1 normally applies to SD cards less than 2GB and version 2 to SD cards greater than 2GB, 2GB cards are normally version 2 but they could be version 1.
The SD card version that you have written the software for is for version 1 SD cards. to test if the SD card is version 1 or 2 you should issue a command 8 and if you get an illegal command then the SD card is version 1 and if you get a valid response then it is version 2. If you were to try your software with a small SD card (much less than 2GB) then I think your software will work.
CMD16 is not needed in either case as 512 is the default sector size and for version 2 SD cards the sector size must be 512 bytes. The address sent to the SD card for version 1 cards must have the bottom 9 bits set to zero whereas for version 2 SD cards the address starts at bit zero.
The CRC is not required for commands apart from cmd0, and cmd8 and it is recommended to include the CRC for the encryption commands.
 

As no one else has replied to you I thought that I would have a go at sorting out your problem. I think that your problem is due to the address that you are sending to the SD card being 512 times the sector number you want to read. There are various SD card standards notably in this case version 1 and version 2 you should read and understand both versions. The standard version 1 normally applies to SD cards less than 2GB and version 2 to SD cards greater than 2GB, 2GB cards are normally version 2 but they could be version 1.
The SD card version that you have written the software for is for version 1 SD cards. to test if the SD card is version 1 or 2 you should issue a command 8 and if you get an illegal command then the SD card is version 1 and if you get a valid response then it is version 2. If you were to try your software with a small SD card (much less than 2GB) then I think your software will work.
CMD16 is not needed in either case as 512 is the default sector size and for version 2 SD cards the sector size must be 512 bytes. The address sent to the SD card for version 1 cards must have the bottom 9 bits set to zero whereas for version 2 SD cards the address starts at bit zero.
The CRC is not required for commands apart from cmd0, and cmd8 and it is recommended to include the CRC for the encryption commands.

First off, thank you for taking the time and effort to read through my problem, think it through, and give a response. I really appreciate it! It sounds like you have some relevant experience to share, as well.

So, if I'm understanding you correctly, if it's "version 2" then address should be block address and not byte address then? I'm pretty sure my card is in fact version 2 because I am sending the CMD8 as part of my initialization, and it is giving a valid R1 (a 0x01 when done before ACMD41 and an 0x00 when done after, I've tried it both ways).

While testing, I have for the most part just tried to read at address 0, but I have tried a few others too. I will note that I get an error on CMD17's R1 when I send an address that isn't a multiple of 0x200 (512 decimal), which leads me to believe that the addressing is in fact byte addressing, not block addressing, for this card. On the FPGA design when I send a (valid) address of any kind, the response is ALWAYS the bytes from my first post, regardless of the address sent. On the uP implementation however, address 0 returns exactly what I expect, which is four hundred something bytes of 0s (as the card is not formatted bootable with bootstrap code), a single 16-byte partition record, and the 0x55 0xAA signature.

Something else I tried just for fun was setting the block size to 2 bytes, since after all I ultimately want to just read one 16-bit audio sample at a time in the end. The card will let me do it, and will then let me try to read addresses that are multiples of 2 with CMD17, which indeed will only return 2 bytes, and those bytes are always 0x55 0xAA, the first two bytes from my first post, no matter what address I use.

I'll also note that since my previous post, I have changed my FPGA design to mimic the CMD sequence I saw from the uP implementation, including the CRC, but sadly, I'm still getting the same mysterious data back. The only difference in the electrical signals being generated are now just a few of the dummy bytes and the uP's clock stretching.

I hadn't thought this significant until just now, but I am using a different microSD breakout board with the FPGA than I am with the uP. I'd normally dismiss worrying about that out of hand, since the boards both LOOK like they just break the card pins straight out with just some current limiting resistors and decoupling capacitors added. But just now I looked up the page for the board I'm using with the FPGA (can't seem to share links, but it's the micro SD breakout from SB components)
and it has some odd bullet points that claim things like "4 bit ADPCM format support" and "FAT file system SD carrier support". That's probably just marketing nonsense, right? They wouldn't have hid some processor under the card socket that's futzing around with the data...right? This issue's made me so crazy I think I need to try swapping out the breakouts, ha ha!

Also, I like your suggestion of trying a smaller card. I'll have to see if I can get a hold of a few. Looks like 128 MB cards are decently available. Is that a good size to try?
 

I just tried connecting the uP to the other breakout, and it's no different. Works just fine. Oh well, so much for my crackpot theory about them hiding a processor somewhere eh?

By the way, I looked closely at the logic analyzer output this time, and the OCR is reading 00 FF 80 00, which I believe translates to "card is ready, accepts any voltage range from 2.7V to 3.6V" and most importantly, bit 30 is 0, indicating that despite accepting CMD8, the card is indeed byte addressable, not block addressable.

I think my next step is to double check the voltage making it to the card. The MachXO3 FPGA board I'm using has six banks of I/O that can be constrained to different voltage levels for logic, and each bank also has a power pin that can be used to power other devices. I'm using bank 0, which I've constrained to 3.3v, so this should be fine. But if I'm being honest, I'm not super confident how much juice these pins can really deliver. The whole board is powered from USB that I'm fairly sure is not negotiating PD. I wouldn't think this would be a problem, but that's the state I'm at now, sadly.

After that, I can only think to try and make my SPI signals match the ones I read from the uP in even the more minor ways.
 

Hi,

The problem with your posts is they are too lenghty.
Better focus on one item, post schematic, draft, diagrams, photos...

Klaus
 

First off, thank you for taking the time and effort to read through my problem, think it through, and give a response. I really appreciate it! It sounds like you have some relevant experience to share, as well.

So, if I'm understanding you correctly, if it's "version 2" then address should be block address and not byte address then? I'm pretty sure my card is in fact version 2 because I am sending the CMD8 as part of my initialization, and it is giving a valid R1 (a 0x01 when done before ACMD41 and an 0x00 when done after, I've tried it both ways).

While testing, I have for the most part just tried to read at address 0, but I have tried a few others too. I will note that I get an error on CMD17's R1 when I send an address that isn't a multiple of 0x200 (512 decimal), which leads me to believe that the addressing is in fact byte addressing, not block addressing, for this card. On the FPGA design when I send a (valid) address of any kind, the response is ALWAYS the bytes from my first post, regardless of the address sent. On the uP implementation however, address 0 returns exactly what I expect, which is four hundred something bytes of 0s (as the card is not formatted bootable with bootstrap code), a single 16-byte partition record, and the 0x55 0xAA signature.

Something else I tried just for fun was setting the block size to 2 bytes, since after all I ultimately want to just read one 16-bit audio sample at a time in the end. The card will let me do it, and will then let me try to read addresses that are multiples of 2 with CMD17, which indeed will only return 2 bytes, and those bytes are always 0x55 0xAA, the first two bytes from my first post, no matter what address I use.

I'll also note that since my previous post, I have changed my FPGA design to mimic the CMD sequence I saw from the uP implementation, including the CRC, but sadly, I'm still getting the same mysterious data back. The only difference in the electrical signals being generated are now just a few of the dummy bytes and the uP's clock stretching.

I hadn't thought this significant until just now, but I am using a different microSD breakout board with the FPGA than I am with the uP. I'd normally dismiss worrying about that out of hand, since the boards both LOOK like they just break the card pins straight out with just some current limiting resistors and decoupling capacitors added. But just now I looked up the page for the board I'm using with the FPGA (can't seem to share links, but it's the micro SD breakout from SB components)
and it has some odd bullet points that claim things like "4 bit ADPCM format support" and "FAT file system SD carrier support". That's probably just marketing nonsense, right? They wouldn't have hid some processor under the card socket that's futzing around with the data...right? This issue's made me so crazy I think I need to try swapping out the breakouts, ha ha!

Also, I like your suggestion of trying a smaller card. I'll have to see if I can get a hold of a few. Looks like 128 MB cards are decently available. Is that a good size to try?
As your SD card does not give an illegal command response to a CMD8 instruction then it is a version 2 SD card and the change sector size will not work which is why you are getting an error with CMD17, even if you have a version 1 SD card in which you can change the sector size it is not recommended that you do so for various reasons.
As it is a version 2 card then when you set the sector to read with CMD17 the address should start at bit 0, for a version 1 card the address starts at bit 10 with the bottom 9 bits being set to zero.
Another gotcha that you should be aware of is that different manufacturers implement the SD card standard in slightly different ways, some manufacturers require no pause between instructions whereas others require an 8-clock period dummy read between instructions. The solution is to always have an 8-clock dummy read before every instruction.

I have included the correct initialization drawing for an SD card note that you don't have to repeat the CMD58 command but get the CCS flag the first time you issue it.




SDcard.jpg
 

Hi,

The problem with your posts is they are too lenghty.
Better focus on one item, post schematic, draft, diagrams, photos...

Klaus

yeah, I see your point. I wanted to include everything I’ve already tried (which will always be a lot before I go to the internet), but it’s understandable that most people just won’t want to read all that. Are you the mod that’s been reviewing my posts before they go live? My condolences.

As your SD card does not give an illegal command response to a CMD8 instruction then it is a version 2 SD card and the change sector size will not work which is why you are getting an error with CMD17, even if you have a version 1 SD card in which you can change the sector size it is not recommended that you do so for various reasons.
As it is a version 2 card then when you set the sector to read with CMD17 the address should start at bit 0, for a version 1 card the address starts at bit 10 with the bottom 9 bits being set to zero.
Another gotcha that you should be aware of is that different manufacturers implement the SD card standard in slightly different ways, some manufacturers require no pause between instructions whereas others require an 8-clock period dummy read between instructions. The solution is to always have an 8-clock dummy read before every instruction.

I have included the correct initialization drawing for an SD card note that you don't have to repeat the CMD58 command but get the CCS flag the first time you issue it.




View attachment 183572
I’m not actually getting an error with the CMD17. The R1 response is 0x00. In fact, great news: I have actually solved my mystery!

It’s a bit embarrassing to admit, but it turns out there was an open circuit in the power delivery, and somehow just enough was leaking from the data lines that it was giving about 2.7 V to the card (enough to initialize and get good responses), which then was dipping lower as soon as I sent the CMD17 to read data (confirmed with oscilloscope).

it was so hard to figure out because I was still getting good R1 response and there’s an LED that was lighting up on the breakout. I’m almost positive that the data I was getting was a memory dump from the embedded microcontroller in the card.

Now that I’m powering the circuit properly, I’m reading exactly what I expected.

Maybe I’ve got a real unicorn of a card on my hand, but I appear to be able to issue a CMD8 and get a valid response AND I can set my block size, and CMD17 will be addressed by byte and return the appropriate number of bytes followed by a CRC16.

I’ve only really been focused on getting this specific card working first, but this chart will be handy for when I expand the design to be able to work with more cards at some point.

Thanks again for your input, friend.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top