SD Cards and FAT32 - Part 4


Working on my 6502 computer I have gathered a significant amount of wisdom around working with SD Cards and FAT32. I am documenting all this as much for myself as others.

Writing a sector

CMD24 is used to write a single block to the SD Card.

Send CMD24 with the address to write and the SD Card will respond with R1.
Send the Data Start Token of $FE, then 512 bytes of data.
The card will send a data response token. (see below)
Then the card will send $00 until the internal write has finished and the card is ready for more commands.

Data Response Token

Bits 7,6,5 are all undefined.
Bit 4 is always 0.
Bits 3,2,1 are the status bits.
Bit 0 is always 1.

Status bits 010 - Data Acepted.
Status bits 101 - CRC error.
Status bits 110 - Write error.

Masking off the upper bits and taking in to account the bit 0, you get this:
5 - Data Acepted.
11 - CRC error.
13 - Write error.

Pseudocode


Write_SPI($FF)        ; Always send an $FF byte before a CS change
SetCS(Low)            ; Sets the CS line low
Write_SPI($FF)        ; Always send an $FF byte after a CS change

Write_SPI($FF)        ; Always send an $FF byte before a command

Write_SPI($58)        ; CMD24 - Note we OR command number with $40
Write_SPI($00)        ; CMD24 - Address (MSB)
Write_SPI($00)        ; CMD24 - Address
Write_SPI($00)        ; CMD24 - Address
Write_SPI($00)        ; CMD24 - Address (LSB)
Write_SPI($FF)        ; CMD24 - No CRC needed.

Result = Read_SPI     ; Read the R1 result byte
While(Result == $FF)  ; Wait till returned byte is not $FF
  Result = Read_SPI   ; Read the R1 result byte
If (Result != $00) then Error   ; Return an error

Write_SPI($FE)        ; Send start data marker.

For I=0 to 511 do     ; Write the 512 bytes.
  Write_SPI(Data[I])  ; Write a data byte.
Next                  ; End of the for loop.

DataResponse = Read_SPI     ; Read the Data Response code
If (DataResponse != $05) then Error   ; Return an error

Result = Read_SPI     ; Read the R1 result byte
While(Result == $00)  ; Wait till returned byte is not $FF
  Result = Read_SPI   ; Read the R1 result byte

Write_SPI($FF)        ; Always send an $FF byte before a CS change
SetCS(High)           ; Sets the CS line high
Write_SPI($FF)        ; Always send an $FF byte after a CS change

What’s next?

In part 5 we will start work on reading a file system.