It has been sometime that I have updated my blog. I was busy with work and had a personal emergency in September. I had decided to restart work on my firmware where I had left off i.e. the SD card driver just before the emergency. It took almost 2 weeks after the emergency to stabilize and start working on it.
I had initially assumed that I had finished reading data from the SD card. Looking at where I left off I had finished very little. I had just started off with the initializations and that too it was not very complete. So I took upon the task of at least writing code for reading SD card data.
Experience on SD card data read:
I had to stabilize my initialization function of SD Card controller and it was a mess! I had to clean up a lot of code. Luckily I had written some code comments and could pick up from there. So the first step was to verify whatever I have written that is the steps of initialization.
- Initialization of the pins. This is multiplexed as GPIOs and SD Block controller pins. So it has to be set to configure as SD Block controller.
- Reset SD MMC :)
- Set the prescaler. For initialization I have set it to lowest possible value possible i.e. 100kHz. (The spec says a 400kHz but I did not want to take any chance.)
- Next step is to set the data timeout period which I have kept to pretty high value.
- I reset the FIFO
- I enable the clock and the SD Card controller comes alive.
Now the initialization starts off based on the SD Card specification i.e. sending various commands. I will not go in elaborate details of the steps as most of it is explained in the specification. I will explain the problems which I encountered.
- It is better to set-up a very slow clock. The clock setup during initialization is usually 400kHz but in my case I set it up as 100kHz.
- CMD55 and ACM41 needs to be retried. The response is pretty slow hence it is good to have this in a retry loop.
- Most of the verification of the whether the card is setup right can be done by parsing the CID (Card Identification) register. The PNM (Product Name) can be verified. I get a SD08G i.e. a Sandisk 8GB.
- To get the relative address I send a CMD3. This forms the RCA.
- I had significant problems in understanding of the spec here. After sending a CMD3 the card has to go to STBY (Standby) state. To check the state I need to send CMD13 which gets the present state but I was checking the state from the R1 response returned from CMD3. This response gives the state previous to sending the command. All thanks to
jnc100 from OSDev forums for point this out. Post here for reference.
- Previously I had ignored the state and when from CMD3 I send a CMD7 I was supposed to go to TRAN (Transfer) state and as seen in the previous point I was stuck wondering why I am still in STBY state. After a check from CMD13 response I was seeing the TRAN state. Yay!
- Next for the actual data transfer I set the SDI Block register a size of 512 which I take from RD_BL_LEN and WR_BL_LEN of CSD info.
- I send CMD17 with the block address being 0,1,2.. etc. After this I have to read the different registers to check if I am able to get data. I simply check if there is any data in the FIFO in the SDIFSTA register. It is a FIFO_RFDET bit. If there is data I read until count bytes.
- The read above is a single block read. Next I have to try reading multiple blocks etc. In the SDIDatCon register there is a doubt of block number. This I am assuming as how many blocks I am trying to read. Setting a 0 to the block number does not start any transfer which means this is not a block address. I had problems with this as I was setting it 0 thinking this is a block address and there was no transfer of data.
- I had made a mistake of sending CMD13 after CMD17 to check the status of CMD17. Turns out this is not a good idea as this interferes with CMD17.
Things to try next are
- Read multiple blocks and send CMD12 to stop transmission.
- Reading data in Word, Half word sizes.
- Reading data in 4 bit mode.
- Write and Erase blocks.
- Make good API's for read,write and erase.
Further plans include writing a simple FAT32 file system and keeping the firmware in there. This will help me in loading the firmware from the SD Card rather than from UART.
I spent nearly 2 weeks struggling with the read. While working on this I came across an article on Solo Programmers and the following quote by Paul Lutus felt very appropriate during this work:
A mistress of perfect consistency, the computer
rejects all but the flawless, offering no explanation. When the
acceptable is finally offered, the machine's acceptance is total,
unwavering and eternal.