Accessing SD cards via SPI bus

There are various examples of accessing standard SD cards via the SPI bus (Microchip has one in their example code) but getting to the basics of how to implement your own is tricky!

Here is a simple how-to, I've tried to show WHY you have to do certain things to make it clear what is happening....

- I'm assuming you have the SD card correctly connected onto the SPI bus and the chip select line (I'll call it CARD_CS) also setup correctly.

[SPI BASICS]
The SPI bus clock only runs while data is being clocked in/out. Data moves in both directions at the same time so if you clock 'out' byte 0xB3 you're 'in' buffer will change to whatever is on the input bus. If the device you are talking to did not send anything back at that time, the value will be 0x00.

The SD card keeps things simple by (normally) not sending anything back until you have finished sending it a commend. This avoids the need to handle 'in' and 'out' comms at the same time...

As SPI comms does not have start/stop bytes, the SD card is synchronised to the change of the CARD_CS line. It is critical that the line is raised (un-selected) after every command, even if there is only one device on the bus. This is how the SD card recognises the start of a command.

[SD Card SPI commands]
Standard commands are 6 bytes long
Byte[1] = Command byte [01xxxxxx] where xxxxxx is the command number. The first to bytes are fixed for most commands
Byte[2..5] = Address bytes
Byte[6] = CRC byte. (I have used hard-coded CRC values for the command that require them)

Most command return an 'R1' format response, this is a single byte where 0x00 is the 'passed' state. the LSb is the 'idle' flag that we monitor during setup. The others are the various errors that can occurr while processing a command.

To send a command:
Drive the CARD_CS low
Send the command byte
Send the address bytes
Send the CRC byte (or 0xFF if it is not required)
Read the response byte(s)
Drive the CARD_CS high

[Starting Up]

- As the card does not have a constant clock, we need to feed it 'extra' clocks at various times so it can run internal processes. At power up the card needs 80 clocks to initialise:

Select the SD card by driving CARD_CS low
Send 0xFF to the card 10 times (10 bytes * 8 clocks per byte)
Un-select the SD card by driving CARD_CS high

- On power up, the SD card is in SDIO mode. We need to switch it into SPI mode. This can ONLY be done at power up and you cannot switch back to SD mode later without power cycling. Sending command 0 with the CARD_CS line driven low is a signal to enter SPI mode.

Send command 0 (0x40) with an empty address field, the CRC for this is 0x95:
Send: (0x40, 0x00, 0x00, 0x00, 0x00, 0x95)
Read the next byte, the result should be 0x01 to show the card is now 'idle'

- The card is now idle and must be activated. Command 1 is used for this and must be run constantly until the 'idle' flag in the response is no longer set

Send command 0 (0x41) with an empty address field, the CRC for this is 0xF9:
Send: (0x41, 0x00, 0x00, 0x00, 0x00, 0xF9)
Read the next byte, the result should be 0x01 or 0x00. Keep looping until 0x00 is returned, normally takes 2-5 loops but some cards may be a lot longer. I limit at 255 attempts.

- The card is now ready for use. Some smaller cards allow you to change the number of bytes that are written in sequence. Larger cards are fixed to 512 bytes at a time. As such, the safest way is to select 512 bytes as your block size as this will work with any card. command 16 (0x56) makes this selection. CRC byte can now be 0xFF as (for some reason I don't understand everyone says you can stop using the CRC now....it seems to work ok...!)

Send command 16 with the block size (512) in the address field
Send: (0x56, 0x00, 0x02, 0x00, 0x00, 0xFF)
The response should be 0x00

- You can now read/write data to the card. I'll add details of that when I've got the bugs sorted out in my code!....

Comments

Popular posts from this blog

JTAG Progromming on a PIC

Using Plink.exe from C# (accessing a linux PC)

Evohome problems on Danfoss RAS-C2 valves