I've been trying to do an SD card interface with the LPC1766 SPI peripheral for a while and right now I'm stuck in a problem that I couldn't find the answer anywhere.
The problem is: SDHC cards are not responding to write and read commands as expected.
Everything works fine on the initialization that was based on Chan's flowchart and on an NXP application note. I can differentiate the cards versions, read the OCR, CID, CSD and determine their sizes.
After that step I start writing single blocks every one second and reading it back to check the data integrity. On a Kingston SDHC 4 GB Class 4 card I can send a first write command but on the second one the card does not even answer (0x00 or 0x01) to the CMD24. With a SanDisk 4 GB Class 4 card the results are different, every command is answered by the card, but I get only zeroes when reading the data back (I'm sure I'm not writing zeroes). If I use SDSC cards, everything works fine.
I'm aware that SDHC are block addressed and not byte addressed and that I need to send ACMD41 with the CCS on for SDHC. I also know that the clock frequency is not an issue (using 400 KHz to start and then 20 MHz to write/read), because I just turned on the CRC checking and all cards are accepting the commands and data. If I stop calculating the CRC all cards reject commands and data.
How do you connect your SD card? Depending on the mode/state the SD(HC) card needs an external pull-up resistor. Without that you read zero, so that may be your problem.
Related
Recently, I bought a Nucleo-144 development board for the STM32F746. For the project I'm working on, I need to get consistent >3 MB/s write speeds to the SD card. Using STM32CubeIDE, I've been able to get SD 1-bit mode working with FatFS in both polling and DMA modes at full speed. However, switching to SD 4-bit mode, I start getting lots of IO errors relating to bad data CRCs while reading.
Details
In SD 4-bit polling mode, I can't even get a single block read to process correctly. Calling f_mount returns an IO error, and debugging it further reveals that the first call to HAL_SD_ReadBlocks, reading sector 0, fails with the error code SDMMC_ERROR_DATA_CRC_FAIL:
Inspecting the 512 byte data buffer it's read to from the card reveals that data is at least partially intact containing some strings you'd expect to see in the first sector:
Importantly, this buffer is corrupted in the exact same manner between each run of the software. If it was some kind of electrical interference problem, I'd expect to see different bytes being corrupted, but I don't. The buffer is identical between runs. Switching back to 1-bit mode and inspecting the data buffer, it's clearly in a lot better shape. The 4-bit buffer clearly has a lot of corrupted bits and bits that are missing entirely, offsetting everything. 4-bit mode is reading mostly junk, but consistently the same junk.
What I've Tried
Polling and DMA mode.
Both fail in a similar manner, although it's harder to debug DMA.
Decreasing the SDMMCCLK clock divider all the way down to 255, the highest divider (and lowest clock speed) it'll go.
On my older, cheaper, Lexar SD card read/writes in this mode work flawlessly (albeit very slowly).
On my newer, more expensive, Samsung SD card read/writes still fail with a SDMMC_ERROR_DATA_CRC_FAIL error. The data buffer appears much more intact, but it's clearly still garbage data.
Transfers with GPIO pull-ups applied to all SD pins (except clock) as well as without pull-ups.
No change, at least as far as I could tell.
Using multiple different SD cards.
Specifically, a Lexar "300x" 32 GB card and a Samsung "EVO Plus" 128 GB card.
As mentioned previously, decreasing the clock speed allowed one of my two cards to work.
However, my higher quality card still fails on the first read even at the minimum speed.
Wiring
Not sure how relevant this is, but figured I'd include it for sake of completion. This is how I have my SD card connected while prototyping. All of the cables are the same length, but perhaps they're interfering with each other even over such a short distance? I'm also using an Adafruit SD card breakout adapter for testing.
SD Card
GPIO Pin
CLK
PC12
D0
PC8
CMD
PD2
D3
PC11
D1
PC9
D2
PC10
Summary
It appears that with some cards, even at lower clock speeds, IO errors are incredibly common in SD 4-bit mode only. At higher clock speeds, all cards I'm able to test with start having IO errors in 4-bit mode. In SD 1-bit mode, however, even at the maximum clock speed I'm able to read and write fine.
I'd like to take advantage of the 4-bit mode for faster speeds. What am I doing wrong? Is it something electrical, like for example needing stronger pull-up resistors or shorter wires? Thanks, I really appreciate it!
I had similar issues on a H743ZI Nucleo. My code worked fine on two other H743 boards with onboard sdcard readers, but failed on the Nucleo with Adafruit breakout. I believe it was just due to signal integrity..
I see you tried dropping the clock divider down, but have you tried a slower SDMMC clock? This was what made the difference for me. Was failing at 48MHz, but fine at 24MHz and lower with 0 divider.
I'm using a USB-6356 DAQ board to control an IC via SPI.
I'm using parts of the NI SPI Digital Waveform library to create the digital waveform, then a small wrapper VI to transmit the code.
My IC measures temperature on an RTD, and currently the controlling VI has a 'push for single measurement' style button.
When I push it, the temperature is returned by a series of other VIs running the SPI communication.
After some number of pushes (clicking the button very quickly makes this happen more quickly in time, but not necessarily in number of clicks), the VI generates an error -200361, which is nominally FIFO buffer overflow on the DAQ board.
It's unclear to me if that could actually be the cause of the problem, but I don't think so...
An NI guide describing this error for USB-600{0,8,9} devices looks promising, but following the suggestions didn't help me. I substituted 'DI.UsbXferReqCount' for the analog equivalent, since my read task is digital. Reading the default returned 4, so I changed the property to write and selected '1', but this made no difference.
I tried uninstalling the DAQ board using the Device Manager, unplugging and replugging, but this also didn't change anything.
My guess is that additional clock samples are generated after the end of the 'Finite Samples' part for the Read and Write tasks, and that these might be adding blank data that overflows, but the temperatures returned don't indicate strange data, and I'd have assumed that if this were the case, my VIs would be unable to interpret the data read in as the correct temperature.
I've attached an image of the block diagram for the Transmit VI I'm using, but actually getting it to run would require an entire library of VIs.
The controlling VI is attached to a nearly identical forum post at NI forums.
I think USB-6356 don't have output buffers used for Digital signal. You can try it by NI-MAX, if you select the digital output, you may find that there is no parameters for Samples. It's only output a bool-value(0 or 1) in one time.
You can also use DAQ Assistant in LabVIEW, when you config Digital output, if you select N-Samples or Continuous samples, then push OK button, here comes a Dialog that tell you there is no buffer for lines that you selected.
I am using the STM32F4 microcontroller with a microSD card. I am capturing analogue data via DMA.
I am using a double buffer, taking 1280 (10*128 - 10 FFTs) samples at a time.
When one buffer is full I am setting a flag and I then look at 128 samples at a time and run an FFT calculation on it. All of this is running well.
The data is being sampled at the rate I want and FFT calculation is as I would expect. If I just let the program run for one second, I see that it runs the FFT approximately 343 times (44000/128).
But the problem is I would like to save 64 values from this FFT to the SD card.
I am using the HCC fat file system library.
Each loop of the FFT calculation I am copy the 64 values into an array.
After every 10 calculations I write the contents of this array to file and start again.
The array stores 640 float_32 values (10*64).
This works perfectly for a one-second test run. I get 22,000 values stored to the SD card.
But as I increase the time I start losing samples as it take the SD card longer to write. I need the SD card to store over 87 kbit/s (4 bytes * 64 * 343 = 87808) consistently. I have tried increasing the DMA buffer sample size and then the number of times it writes, but didn't find it helped.
I am using an 8G microSD card, class 4. I formatted the SD card to the default FAT32 allocation unit size 2048.
How should I organize the buffering of data to allow for this? I thought using fewer writes might help. Would a queue help? How would I implement this and would anyone have an example?
I saw that clifford had a similar problem and he was using a queue, How can I use an SD card for logging 16-bit data at 48 ksamples/s?.
In my case I got it to work by trying a large number of different cards - they vary a great deal. If I had enough RAM available for a longer buffer that would have worked too.
If you are not using an RTOS, the queue buffering option may not be available to you, or at least would be non-trivial to implement.
Using an RTOS queue, I suggest that you create a queue of messages each of length 64*sizeof(float_32), the number of messages in the queue will be determined by the ammount of card latency you need to deal with; a length of 343 for example, will sustain a card stall of 1 second, and will require 87Kb of RAM. The application will then have a high priority thread performing the FFT and placing data in the queue, while a low priority thread takes data from the queue and writes to the file.
You might improve performance further by accumulating multiple message blocks in your DMA buffer before initiating a write, and there may be some benefit in carefully selecting an optimum DMA buffer length.
Flash is very, very sensitive to overwrites. Writing 3kB and then a further 3kB may count as an overwrite of the first 4 kB. In your case, there's no good reason why you'd want such small writes anyway. I'd advise 16 kB writes (32 frames/write * 64 samples/frame * 4 bytes/sample). You'd need 5 or 6 writes per second, which should be well in spec of any old SD card.
Now it's quite likely that you'd get another 1280 samples it while writing; you'll have to deal with that on another thread. Should be no problem as the writing should block without using CPU (it's a low-level Flash delay)
The most probable cause of the problem might be the way you are interfacing the card through the library.
SD cards over the SPI protocol (which I assume being used here) can be read or written in 512 byte sector units, some SD commands making it possible to stream (to perform sequential sector access faster). An important element of the SD card SPI protocol are various delays, where you have to poll the card whether you could start an operation (such as writing data to a sector).
You should read the library's API to discover how its writing process might work. You will need to perform some regular action which in the end would poll the card to know whether the writing process could continue. Some cards might require a set number of accesses before becoming ready for an operation, some others might use timeouts for state transitions. It might not work well to have the function called relatively rarely (such as once in 2-3 milliseconds) anticipating the card getting ready meanwhile. You have to keep on nagging it whether it completed already.
Just from own experiences with SD interfacing.
I saw a lot of information about MMC/SD cards and I tried to make a library to read this (modifying the Procyon AVRlib).
But I have some problems here. I don't change the original code and tried here. My problem is about the initialization of an SD card. I have two here, a 256 MB and another 1 GB.
I send the init commands in this order: CMD0, CMD55, ACMD41, and CMD1.
But the 256 MB SD card only returns a 0x01 response for each command. I send the CMD1 a lot of times and the 256 MB SD card always returns only 0x01, never 0x00.
The 1 GB SD is more crazy... CMD0 returns with 0x01. Nice, but the CMD55 command responds with 0x05. At other times it responds with 0xC1 and also sometimes responds with 0xF0 with a 0x5F in the next interation...
Around the Internet there is information and examples, but it is a bit confused. Here in my project, I must use a 1 GB card and I'm trying with a microSD card with an SD adapter (I think that this is not the problem).
How do I fix this problem?
PS: My problem is like the problem in Stack Overflow question Initializing SD card in SPI issues, but the solution didn't solve my problem. The 1 GB SD card only returns 0x01 ever... :cry:
Why do you need CMD1? And did you read the note below it, that says "CMD1 is a valid command for the thin (1.4 mm) standard size SD memory card only if used after re-initializing a card (not after power on reset)."?
About the 1 GB card, ideas that come to mind:
After every command (send command, get reply), do you send 8 dummy bytes before making CS high?
The values returned seem weird (0x05 doesn't have busy bit set, so WTF?), maybe there's a hardware issue?
Does the card work otherwise?
Maybe this helps a bit:
SD Specifications Part 1 Physical LayerSimplified Specification
A simple explanation of MMC/SD usage over SPI is provided here. I have used the associated FAT file-system library too and it works well.
However, the solution may not work for some makes of cards. For such cards, you may have to edit the procedure/library. That may be why your 1 GB card acts differently -- it may be a different make of card. The SPI mode of certain cards may not be that popular for commercial equipment, and thus may be more deviated in specification by some card manufacturers.
If you bit bang the commands and clocks, you may have more control and confidence that those procedures are correct. That is useful because you need some solid ground to build on to progress bit by bit. I found that the <400 kHz 80 clocks was critical on one card, but could run at more than 2 MHz on another.
Try to progress one command at a time that is reliable for both cards.
I'm using a microSD card in an embedded design. The card is connected to a microcontroller using the SPI interface. It worked fine for all cards I've used before, but now my new card will not initialize. The card is a Transcend 2 GB microSD card (TS2GUSD).
After sending the initial clock train to switch to SPI mode, I do the following:
CMD0 (Argument 0, CRC 0x95) -> Response 0x01 -> OK
CMD8 (Argument 0x000001AA, CRC 0x87) -> Response 0x01 0x000001AA -> Means it's SDC V2+ card, the voltage range 2.7 V - 3.6 V is supported -> OK
Then I should send the ACMD41 command, but when sending the CMD55 (argument 0, CRC 0) that must precede CMD41, I get response 0x05 -> Illegal Command.
I've also tried to send CMD1 (for MMC cards), but it gives a similar illegal command response. The code works fine with my Sandisk 2 GB microSD card.
How do I fix this problem?
I seem to have found the issue. When I calculate the correct CRC for CMD55 and send that instead of a dummy CRC, the command is accepted (result 0x01). If you look at the physical layer specification in section 7.2.2, it explicitly says that:
The SPI interface is initialized in the CRC OFF mode in default. (except for commands CMD0 and CMD8).
This doesn't seem to be the case with this series of Transcend cards, thus violating the specification. Also in case of a CRC error the reply should be 0x09 instead of 0x05. I've tried to explicitly turn off CRC checking with CMD59, but that doesn't seem to help.
=> Calculating the correct CRC for (all?) commands makes the card work.
I'm in contact with Transcend support about this. If I learn something useful I'll you know here.
Note that I used other 2 GB Transcend cards before, but they were made in Taiwan, while the new one is made in Korea (and seems to be a Samsung card (MMAGR02GUDCA)).
I had almost the same issue. When sending ACMD41, I sent CMD55 followed by CMD41. The response for CMD55 was 0x01, indicating idle state and running the initialization process (this is normal, I think). CMD41 would respond with 0x05, indicating illegal command. It turns out that my particular card does the CRC check by default, even in SPI mode, and misreports CRC errors as illegal commands (i.e., it doesn't follow the SD spec). When I calculate the proper CRC, it works fine. Here is the CRC7 calculation code I used, it has worked well for me:
https://github.com/hazelnusse/crc7
Unless you have taken care to disable CRC checking, I think it is probably best to assume it isn't disabled and make sure you calculate the proper CRC for each command frame. From what I can tell, some cards disable it by default in SPI mode and others enable it, even though the SD specification states it should be disabled by default in SPI mode except for CMD8.
You said you used CRC 0 for the failing command. I assume that you meant that you sent the whole last byte as 0x00. Note that the CRC7 is only the first 7 bits of the last byte - the last bit called end bit should always be 1. So if you were sending 0x00 as the last byte, with 0 as the last bit, the failure would be understandable, and even the error code would make sense. If you send 1 as the last bit, it should work, ie. use something like 0x01 or 0xFF as the last byte.
It's normal, it's likely the internal charge-pump used to make erase voltage that takes longer than usual to be ready... you have to insist on the CMD55+ACMD41 combo until initialization finishes.
The CMD58 could also help you to check if you're supplying correct voltage levels (sometimes sockets have contact problems).
Sending CMD0 with chip select(0) alone does not initialize the card in SPI mode. This only sets SPI mode.
Card is not initialized until ACMD41 returns accepted. Then CRC is off by default.
Insert several dummy SPI cycles after CMD55 (0xFF sent+received) and before CMD41.
I had to do this for both my old test cards - 16MB Panasonic and Sandisk 64MB.
Note: I realize I'm quite late to the party, but I'm hoping it may help someone in future.