Ladislav Havel, UREL, FEEC, VUT Brno
xhavel22
stud.feec.vutbr.cz
projekt zveřejněn také na www.hw.cz
Popis pinů SD karty [1]

| Pin | Name | Function (SD Mode) | Function (SPI Mode) |
| 1 | DAT3/CS | Data Line 3 | Chip Select/Slave (SS) |
| 2 | CMD/DI | Command Line | Mater Out Slave In (MOSI) |
| 3 | VSS1 | Ground | Ground |
| 4 | VDD | Supply Voltage | Supply Voltage |
| 5 | CLK | Clock | Clock (SCK) |
| 6 | VSS2 | Ground | Ground |
| 7 | DAT0/DO | Data Line 0 | Master In Slave Out (MISO) |
| 8 | DAT1/IRQ | Data Line 1 | Unused or IRQ |
| 9 | DAT2/NC | Data Line 2 | Unused |
Datové protokoly (módy) SD karty
Jednobitový protokol je synchronní sériový protokol s jedním datovým vodičem, jedním vodičem pro hodinový signál a jedním vodičem pro řízení. Čtyřbitový protokol je téměř identický s prvním protokolem, rozdíl je v paralelní čtyřbitové datové sběrnici. Oba tyto SD módy mají zabezpečený datový přenos pomocí CRC. Čtyřbitový SD mód má pro každý ze čtyřech datových vodičů nezávislý 16-i bitový CRC. Třetí protokol je protokol (mód) SPI. Tento protokol vychází z komunikace pomocí SPI (Serial Peripheral Interface).
Řízení komunikace [1]
Řízení je prováděno pomocí jednoduchého send-response protokolu. Řídící rámce jsou rozděleny na CMDXX (hlavní řídící rámce) a ACMDXX (aplikační řídící rámce), kde XX je číslo příslušného řídícího rámce (Command). Řídící rámec začíná datovou sekvencí 01, následovanou šesti bity řídícího příkazu a čtyřmi bajty argumentu řídícího příkazu (Command). Poté následuje 7-i bitový CRC se stop bitem 1.
| First Byte | Bytes 2-5 | Last Byte | |||
| 0 | 1 | Command | Argument (MSB First) | CRC | 1 |
Každý řídící rámec (řídící příkaz) má odpovídající odezvu. Tyto odezvy jsou rozděleny pro SPI mód na typy R1, R2, R3.
R1:
| Byte | Bit | Meaning |
| 1 | 7 | Start Bit, Always 0 |
| 6 | Parametr Error | |
| 5 | Address Error | |
| 4 | Erase Sequence Error | |
| 3 | CRC Error | |
| 2 | Illegal Command | |
| 1 | Erase Reset | |
| 0 | In Idle State |
R2:
| Byte | Bit | Meaning |
| 1 | 7 | Start Bit, Always 0 |
| 6 | Parametr Error | |
| 5 | Address Error | |
| 4 | Erase Sequence Error | |
| 3 | CRC Error | |
| 2 | Illegal Command | |
| 1 | Erase Reset | |
| 0 | In Idle State | |
| 2 | 7 | Out of Range, CSD Service |
| 6 | Erase Parameter | |
| 5 | Write protect Violation | |
| 4 | Card ECC Failed | |
| 3 | Card Controller Error | |
| 2 | Unspecified Error | |
| 1 | Write Protect Erase Skip, Lock/Ulock failded |
|
| 0 | Card Locked |
R3:
| Byte | Bit | Meaning |
| 1 | 7 | Start Bit, Always 0 |
| 6 | Parametr Error | |
| 5 | Address Error | |
| 4 | Erase Sequence Error | |
| 3 | CRC Error | |
| 2 | Illegal Command | |
| 1 | Erase Reset | |
| 0 | In Idle State | |
| 2-5 | All | Operating Condition Register, MSB First |
Každá část komunikace (blok dat, čtení nebo zápis) začíná startovním rámcem s hodnotou 11111110, následován blokem dat, typicky o velikosti 512 bajtů, vše je zakončeno 16-i bitovým CRC. Při každém zápisu na kartu (po zápisu bloku dat) je generován Write Status rámec o délce jedno bajtu. Při chybném přečtení dat z karty je generován Read Error rámec.
Write Status Rámec:
| Bit | Meaning |
| 7 | Unused |
| 6 | Unused |
| 5 | Unused |
| 4 | 0 |
| 3-1 | 010 - Data was accepted |
| 0 | 1 |
Read Error Rámec:
| Bit | Meaning |
| 7 | 0 |
| 6 | 0 |
| 5 | 0 |
| 4 | Card locked |
| 3 | Out of Range |
| 2 | Card ECC Failed |
| 1 | Card Controller Error |
| 0 | Unspecified Error |
Nejdůležitější SD řídící příkazy:
| Command | Argument | Type Response | Popis |
| CMD0 | None | R1 | Tell the card to reset and enter its idle state. |
| CMD16 | 32-bit Block Length | R1 | Select the block length. |
| CMD17 | 32-bit Block Address | R1 | Read a single block. |
| CMD24 | 32-bit Block Address | R1 | Write a single block. |
| CMD55 | None |
R1 |
Next command will be application-specific (ACMDXX). |
| CMD58 | None | R3 | Read OCR (Operating Conditions Register). |
| ACMD41 | None | R1 | Initialize the card. |
Inicializace SD karty
Inicializace začíná v nastavení hodinového signálu SPI na 400kHz, což je vyžadováno pro kompatibilitu většiny SD a MCC paměťových karet. Poté musí být vysláno 74 taktů hodinového signálu z MCU (master). Pak kartu resetujeme příkazem CMD0 při aktivovaném CS vstupu karty (CS při úrovni L). CRC bajt pro příkaz CMD0 a nulový argumet příkazu je 0x95. Následují příkazy CMD55 a ACMD41. Je-li poté idle bit v úrovni L inicializace je dokončena a očekávají se další řídící rámce. Příkazem CMD58 můžeme například zjistit zda-li karta podporuje stejné napájecí napětí jako MCU, které je typicky v rozsahu 2,7V až 3,6V. Hodinový signál SPI nastavíme na maximální povolenou hodnotu.
Připojení SD karty k MCU:
#define DI 6 // Port B bit 6 (pin7): data in (data from MMC) #define DT 5 // Port B bit 5 (pin6): data out (data to MMC) #define CLK 7 // Port B bit 7 (pin8): clock #define CS 4 // Port B bit 4 (pin5): chip select for MMC
Inicializace SPI:
void ini_SPI(void) {
DDRB &= ~(_BV(DI)); //vstup
DDRB |= _BV(CLK); //výstup
DDRB |= _BV(DT); //výstup
DDRB |= _BV(CS); //výstup
SPCR |= _BV(SPE); //SPI enable
SPCR |= _BV(MSTR); //Master SPI mode
SPCR &= ~(_BV(SPR1)); //fosc/16
SPCR |= _BV(SPR0); //fosc/16
SPSR &= ~(_BV(SPI2X)); //rychlost neni dvojnásobná
PORTB &= ~(_BV(CS)); //CS SD karty enable
}
Funkce k posílání a příjmu jednoho bajtu po SPI:
char SPI_sendchar(char chr) {
char receivedchar = 0;
SPDR = chr;
while(!(SPSR & (1<<SPIF)));
receivedchar = SPDR;
return (receivedchar);
}
Funkce k posílání příkazového rámce Command:
char Command(char cmd, uint16_t ArgH, uint16_t ArgL, char crc ) {
SPI_sendchar(0xFF);
SPI_sendchar(cmd);
SPI_sendchar((uint8_t)(ArgH >> 8));
SPI_sendchar((uint8_t)ArgH);
SPI_sendchar((uint8_t)(ArgL >> 8));
SPI_sendchar((uint8_t)ArgL);
SPI_sendchar(crc);
SPI_sendchar(0xFF);
return SPI_sendchar(0xFF); // vrátí poslední přijatý bajt
}
Inicializace karty:
void ini_SD(void) {
char i;
PORTB |= _BV(CS); //CS SD karty disable
for(i=0; i < 10; i++)
SPI_sendchar(0xFF); // posíláme 10*8=80 hodinových pulzů 400 kHz
PORTB &= ~(_BV(CS)); //CS SD karty enable
for(i=0; i < 2; i++)
SPI_sendchar(0xFF); // posíláme 2*8=16 hodinových pulzů 400 kHz
Command(0x40,0,0,0x95); // reset
idle_no:
if (Command(0x41,0,0,0xFF) !=0)
goto idle_no; //idle = L?
SPCR &= ~(_BV(SPR0)); //fosc/4
}
Zápis na kartu:
Funkce vrací hodnotu 1 pokud dojde k chybě, pokud proběhne zápis v pořádku funkce vrátí 0.
int write(void) {
int i;
uint8_t wbr;
//Nastavení módu zápisu 512 bajtů
if (Command(0x58,0,512,0xFF) !=0) {
//Zjištění hodnoty response bajtu 0 = bez chyb
return 1;
//vrácená hodnota 1 = chyba
}
SPI_sendchar(0xFF);
SPI_sendchar(0xFF);
SPI_sendchar(0xFE);
//doporučené vysílání zakončovací sekvence dle [2]
//zápis dat z chars[512] na kartu
uint16_t ix;
char r1 = Command(0x58,0,512,0xFF);
for (ix = 0; ix < 50000; ix++) {
if (r1 == (char)0x00) break;
r1 = SPI_sendchar(0xFF);
}
if (r1 != (char)0x00) {
return 1;
//vrácená hodnota 1 = chyba
}
//doporučená kontrolní smyčka dle [2]
SPI_sendchar(0xFF);
SPI_sendchar(0xFF);
wbr = SPI_sendchar(0xFF);
//write block response a testování na chybu
wbr &= 0x1F;
//nulování nejvyšších tří neurčitých bitů, 0b.0001.1111
if (wbr != 0x05) { // 0x05 = 0b.0000.0101
//chyba zápisu nebo chyba CRC
return 1;
}
while(SPI_sendchar(0xFF) != (char)0xFF);
//čekáme na dokončení operace zápisu na kartu
return 0;
}
Čtení z karty:
Funkce vrací hodnotu 1 pokud dojde k chybě, pokud proběhne zápis v pořádku funkce vrátí 0.
int read(void) {
int i;
uint16_t ix;
char r1 = Command(0x51,0,512,0xFF);
for (ix = 0; ix < 50000; ix++) {
if (r1 == (char)0x00) break;
r1 = SPI_sendchar(0xFF);
}
if (r1 != (char)0x00) {
return 1;
}
//čtení z karty proběhne po přijetí startovacího rámce
while(SPI_sendchar(0xFF) != (char)0xFE);
for(i=0; i < 512; i++) {
while(!(SPSR & (1<<SPIF)));
chars[i] = SPDR;
SPDR = SPI_sendchar(0xFF);
}
SPI_sendchar(0xFF);
SPI_sendchar(0xFF);
return 0;
}
Doplnění kódu:
#include <avr/io.h>
#include <avr/iom16.h>
#include <avr/interrupt.h>
#define FOSC 6400000
char chars[512];
int main(void) {
ini_SPI();
ini_SD();
sei();
write();
read();
return 0;
}
MCU pracuje s kmitočtem oscilátoru 6,4 MHz. Funkce pro čtení a zápis jsou doplněny o kontrolní smyčku, dle doporučení [2]. Pro čtení z karty je možné využít sériové rozhraní USART a nastavit vyšší prioritu pro přerušení, tak aby nedošlo ke ztrátě dat při čtení a jejich současnému zpracování.
[1] SanDisk. Secure Digital Card Product Manual - Revision 1.7, Září 2003.
[2] SD Card Association. http://sdcard.org/.