Jste zde

Řešení pro zápis na pamětové karty (SD), MCU Atmega16

sdkarta.gif

Projekt řeší možnosti zápisu a čtení dat z paměťové karty SD při řízení mikrokontrolérem Atmega16 a vznikl v rámci předmětu MMIA - mikropočítače pro přístrojové aplikace na Ústavu radioelektroniky VUT v Brně

Obsah:

  1. Realizace
  2. Závěr
  3. Literatura

Realizace

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
101 - Data was rejected, CRC Error
110 - Data was rejected, Write Error

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.

 

Programová část:

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;
}
 

Závěr

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í.

Literatura

  • [1] SanDisk. Secure Digital Card Product Manual - Revision 1.7, Září 2003.
  • [2] SD Card Association. http://sdcard.org/.
Hodnocení článku: 

Komentáře

Dobry den, sd karty (v spi rezimu , vicemene jen jako nahradu za mmc) ve svych amaterskych navrzich pouzivam taky. Nicmene - pokud budu chtit takove zarizeni vyrabet a prodavat - nevztahuji se na mne licence SD Association? :-/

Dobry den, nezajimal se nekdo z Vas o moznosti zpracovani dat dale na PC? Tzn. vyjmout kartu z embedded systemu (kde se data zapisovaly jednoduse jako bajty na urcite adresy - bez filesystemu) vlozit do ctecky karet na PC a pomoci nejakeho driveru je zpristupnit operacnimu systemu. Napsani driveru pro windows bude asi dost slozite, linux by mohl byt alternativou. Mozna ze se timto jiz nekdo zabyval a existuje hotove reseni. Myslim ze by to byl znacny prinos, v mnoha aplikacich by tim mohla odpadnout nutnost nejakeho rozhrani pro stahovani dat ze systemu.

Dobry den, nezajimal se nekdo z Vas o moznosti zpracovani dat dale na PC? Tzn. vyjmout kartu z embedded systemu (kde se data zapisovaly jednoduse jako bajty na urcite adresy - bez filesystemu) vlozit do ctecky karet na PC a pomoci nejakeho driveru je zpristupnit operacnimu systemu. Napsani driveru pro windows bude asi dost slozite, linux by mohl byt alternativou. Mozna ze se timto jiz nekdo zabyval a existuje hotove reseni. Myslim ze by to byl znacny prinos, v mnoha aplikacich by tim mohla odpadnout nutnost nejakeho rozhrani pro stahovani dat ze systemu.

ako funguje procedura write? Konkretne cast:

//zápis dat z chars[512] na kartu

dakujem