Obsługa kart pamięciowych SD. cz.4.pdf
(
1359 KB
)
Pobierz
098-102_karty_SD_cz4.indd
KURS
Obsługa kart pamięciowych
SD, część 4
Przechodzimy do części
niewątpliwie praktycznej
- opisu procedur. W artykule
pokazujemy jak obsłużyć karty
SD za pomocą mikrokontrolera
LPC2148, a dzięki napisaniu
wszystkich procedur w języku
C przeniesienie ich na inne
mikrokontrolery nie będzie
kłopotliwe.
Dołączanie kart SD do mikrokon-
trolerów jest stosunkowo proste. Po-
trzebny jest mikrokontroler wyposażo-
ny w sprzętowy interfejs SPI, ale może
on być realizowany także programowo.
Dodatkowo mogą być przydatne 2 li-
nie I/O do wykrywania obecności karty
w gnieździe i protekcji zapisu.
Do testów komunikacji z kartą
wybrano moduł ZL9ARM z modu-
łem dipARM wyposażonym w pro-
cesor LPC2148 (obydwa urządzenia
dostarczyła firma
www.kamami.pl
).
Dołączenie karty SD do modułu
ZL9ARM jest łatwe ze wzgledu na
to, że został on wyposażony w złą-
cze kart SD (
rys.
15
).
Karta jest zasilana napięciem
+3,3 V i sterowana liniami interfej-
su SSP skonfigurowanego do pracy
w trybie SPI Master. Wszystkie linie
interfejsu są buforowane układem
(U3) 74LVC541. Do konfiguracji inter-
fejsu karty są wykorzystywane zworki
JP4 (MMC_EN) i JP12 (CS). Zworka
JP4 musi być tak ustawiona, żeby
na wyprowadzeniach 1 i 19 układu
U3 był stan niski (zwarte 1 i 2 JP4).
Zworka JP12 musi łączyć linię P0.21
z wyprowadzeniem 5 U3 (zwarte 2 i 3
JP12). Zworka JP16 SSEL nie jest tu
wykorzystywana, a linia P0.20 musi
być ustawiona jako wejście.
Wszystkie procedury opisane w ar-
tykule zostały zweryfikowane w prak-
tyce z wykorzystaniem kart Toshiba
SD-M512 o pojemności 512 MB i Pre-
tec 256 MB High Speed.
Przed wywołaniem właściwych
procedur komunikacyjnych trzeba zde-
finiować kody komend, odpowiadają-
ce im potwierdzenia oraz znaczniki
określające, czy po otrzymaniu po-
twierdzenia komendy trzeba odbierać
jakieś dane. Mimo iż w trybie SPI
wyłączono sprawdzanie poprawności
CRC, to dla każdej z komend zosta-
ły wyliczone sumy kontrolne i po
włączeniu sprawdzania CRC można
z nich korzystać. Wszystkie niezbędne
definicje umieszczono w pliku
sd.h
,
pokazano je na
list.
1
.
Procedura
SendSDCCmd
wysyła do
karty SD kompletną komendę
i zwraca bajt potwierdzenia
R1 lub 2 bajty potwierdze-
nia R2. Jeżeli wykonywana
komenda nie wymaga kolej-
nych danych (NODATA), to
transakcja jest kończona wy-
słaniem dodatkowych 8 cykli
zegarowych i przejściem syg-
nału MMC_CS w stan wy-
soki. W przypadku, kiedy są
spodziewane dodatkowe dane
(MOREDATA), sygnał MMC_
CS pozostaje w stanie niskim.
Wysyłanie komendy roz-
poczyna się wymuszeniem
stanu niskiego na wejściu CS
karty SD. Pierwszy argument funk-
cji zawiera numer komendy, który
jest indeksem wiersza dwuwymiaro-
wej tablicy
CmdTab
. Numerom wier-
szy odpowiadają nazwy symboliczne
komend zdefiniowane na list. 1. Na
przykład komendzie GO_IDLE_STA-
TE odpowiada wiersz zerowy tablicy
CmdTab
, a symbolicznie jest to
cmd-
Go_IDLE_STATE
(definicja
enum
). Ko-
lejne elementy wiersza
CmdTab
są
zwracane przez funkcje pokazane na
list.
2
.
Funkcja
get_cmd(cmd)
zwraca zero-
wy element wiersza określonego przez
cmd
, czyli kod komendy.
Drugi argument funkcji
SendSDC-
Cmd
zawiera 4-bajtową liczbę będącą
Rys. 15. Sposób buforowania karty SD/MMC
98
Elektronika Praktyczna 3/2008
KURS
List. 1. Definicje z pliku nagłówkowego
sd.h
#define SDC_FLOATING_BUS 0xFF
#define SDC_BAD_RESPONSE SDC_FLOATING_BUS
#define SDC_ILLEGAL_CMD 0x04
#define SDC_GOOD_CMD 0x00
#define BLOCKLEN_64 0x0040
#define BLOCKLEN_128 0x0080
#define BLOCKLEN_256 0x0100
#define BLOCKLEN_512 0x0200
//definicja typow potwierdzen
#define R1 0x00
#define R1b 0x01
#define R2 0x02
#define R3 0x03
#define NODATA 0x00
#define MOREDATA 0x01
//definicje znacznikow
/* Data Token */
#define DATA_START_TOKEN 0xFE
#define DATA_MULT_WRT_START_TOK 0xFC
#define DATA_MULT_WRT_STOP_TOK 0xFD
//definicje kodow potwierdzen
/* Data Response */
#define DATA_ACCEPTED 0x05 //0b00000101
#define DATA_CRC_ERR 0x0b //0b00001011
#define DATA_WRT_ERR 0x0d //0b00001101
// definicje kodów komend: 6 młodszych bitów numer komendy, bit B6 ma wartość 1
#define GO_IDLE_STATE 0x40 //0 mlodsze 6-bitów numer komendy
#define SEND_OP_COND 0x41 //1
#define SEND_CSD 0x49
//9
argumentem wysyłanej ko-
mendy. Następnie wysyła-
ny jest bajt CRC. Można
tu wysłać dowolna liczbę,
ale funkcja
get_crc(cmd)
zwraca wcześniej wyliczo-
ną prawidłowo wyliczoną
wartość CRC. Po wysła-
niu kompletnej komen-
dy procedura oczekuje na
typ potwierdzenia zapisa-
ny w
CmdTab
i zwracany
funkcją
get_rsp(cmd)
. Jeżeli
jest to potwierdzenie R1
lub R1b, to host próbu-
je odczytać 256 razy po-
twierdzenie z karty. Jeżeli
odczytane potwierdzenie
ma wartość inną niż 0xFF,
to próba odczytania po-
twierdzenia z karty kończy
się sukcesem. Jeżeli przez
256 prób nie udało się
odczytać potwierdzenia, to
procedura jest kończona
i zwracany jest bajt 0xFF.
Po odczytaniu bajtu R1
program sprawdza, czy
potwierdzenie jest typu
R1b i jeżeli tak, to cyklicz-
nie sprawdza stan linii
MMC_DO karty odbierając
z niej dane interfejsem SPI.
W trakcie odczytywania in-
terfejsem SPI na linię ze-
garową karty wysyłany jest
przez cały czas przebieg
zegarowy. Zapobiega to
permanentnemu przejściu
ustawieniu danych karty
w stan niski. Testowanie li-
nii kończy się, kiedy linia
przechodzi w stan wysoki,
lub po upłynięciu okre-
ślonego czasu (wykonaniu
określonej liczby spraw-
dzeń). Dla potwierdzenia
R2 host wysyła 8 taktów
zegara, po tym odczytuje
z karty 2 bajty i zapisuje
w zmiennej
int res_out
.
Kiedy nie są spodzie-
wane kolejne dane (NO-
DATA), to procedura koń-
czy transakcję wysyłając
na linię zegarową 8 cykli
zegara i wymuszając na
linii CS stan wysoki. Dla
komend, w których są spo-
dziewane kolejne dane (na
przykład zapisanie bloku
danych) transakcja nie jest
kończona – linia MMC_CS
pozostaje w stanie niskim.
#define SEND_CID 0x4a
//10
#define STOP_TRANSMISSION 0x4c //12
#define SEND_STATUS 0x4d
//13
#define SET_BLOCKLEN 0x50 //16
#define READ_SINGLE_BLOCK 0x51 //17
#define READ_MULTI_BLOCK 0x52 //18
#define WRITE_SINGLE_BLOCK 0x58 //24
#define WRITE_MULTI_BLOCK 0x59 //25
#define TAG_SECTOR_START 0x60 //32
#define TAG_SECTOR_END 0x61 //33
#define UNTAG_SECTOR 0x62 //34
#define TAG_ERASE_GRP_START 0x63 //35
#define TAG_ERASE_GRP_END 0x64 //36
#define UNTAG_ERASE_GRP 0x65 //37
#define ERASE 0x66
#define SD_APP_OP_COND 0x69 //ACMD41
#define LOCK_UNLOCK 0x71 //49
#define APP_CMD 0x77 //55
#define READ_OCR 0x7a //58
#define CRC_ON_OFF 0x7b //59
/*definicja symbolicznych nazw komend używanych w wywolaniu procedury wyslania komendy */
enum
{
cmdGO_IDLE_STATE,
cmdSEND_OP_COND,
cmdSEND_CSD,
cmdSEND_CID,
cmdSTOP_TRANSMISSION,
cmdSEND_STATUS,
cmdSET_BLOCKLEN,
cmdREAD_SINGLE_BLOCK,
cmdREAD_MULTI_BLOCK,
cmdWRITE_SINGLE_BLOCK,
cmdWRITE_MULTI_BLOCK,
cmdTAG_SECTOR_START,
cmdTAG_SECTOR_END,
cmdUNTAG_SECTOR,
cmdTAG_ERASE_GRP_START,
cmdTAG_ERASE_GRP_END,
cmdUNTAG_ERASE_GRP,
cmdERASE,
cmdLOCK_UNLOCK,
cmdSD_APP_OP_COND,
cmdAPP_CMD,
cmdREAD_OCR,
cmdCRC_ON_OFF,
cmdSD
};
/*--------------------------------------------------------------------------------------
definicja tablicy zawieracej kod komendy, sume kontrolna, typ potwierdzenia
oraz znacznik kontynuacji odbierania danych
---------------------------------------------------------------------------------------*/
const unsigned char CmdTab[23][4] =
{
//cmd crc response
{GO_IDLE_STATE, 0x95, R1, NODATA},
{SEND_OP_COND, 0xF9, R1, NODATA},
{SEND_CSD, 0xAF, R1, MOREDATA},
{SEND_CID, 0x1B, R1, MOREDATA},
{STOP_TRANSMISSION, 0xC3, R1, NODATA},
{SEND_STATUS, 0xAF, R2, NODATA},
{SET_BLOCKLEN, 0xFF, R1, NODATA},
{READ_SINGLE_BLOCK, 0xFF, R1, MOREDATA},
//38
Elektronika Praktyczna 3/2008
99
KURS
List. 1. c.d.
{READ_MULTI_BLOCK, 0xFF, R1, MOREDATA},
{WRITE_SINGLE_BLOCK, 0xFF, R1, MOREDATA},
{WRITE_MULTI_BLOCK, 0xFF, R1, MOREDATA},
{TAG_SECTOR_START, 0xFF, R1, NODATA},
{TAG_SECTOR_END, 0xFF, R1, NODATA},
{UNTAG_SECTOR, 0xFF, R1, NODATA},
{TAG_ERASE_GRP_START, 0xFF, R1, NODATA},
{TAG_ERASE_GRP_END, 0xFF, R1, NODATA},
{UNTAG_ERASE_GRP, 0xFF, R1, NODATA},
{ERASE, 0xDF, R1b, NODATA},
{LOCK_UNLOCK, 0x89, R1b, NODATA},
{SD_APP_OP_COND, 0xE5, R1, NODATA},
{APP_CMD, 0x73, R1, NODATA},
{READ_OCR, 0x25, R3, NODATA},
{CRC_ON_OFF, 0x25, R1, NODATA}
};
//definicje kodow bledow
typedef enum
{
sdcValid=0, // wszsytko poprawnie
sdcCardInitCommFailure, // nie ustanowioni polaczenia z karta
sdcCardNotInitFailure, // karta nie przeszla fazy incjalizacji
sdcCardInitTimeout, // timeout inicjalizacji karty
sdcCardTypeInvalid, // nie mozna zdefiniowac karty
sdcCardBadCmd, // karta nie rozpoznala komendy
sdcCardTimeout, // timeout w czasie sekwencji zapisu odczyty lub kasowania
sdcCardCRCError, // wystapil blad CRC w czasie odczytu, dane powinny byc odrzucone
sdcCardDataRejected, // blad CRC danych przesylanych
sdcEraseTimedOut // timeout kasowania danych
}SDC_Error;
List. 2. Funkcje zwracające parametry komendy
char get_cmd(char sd_cmd)
{
return(CmdTab[sd_cmd][0]);//kod komendy
}
char get_crc(char sd_cmd)
{
return(CmdTab[sd_cmd][1]);//bajt CRC
}
char get_rsp(char sd_cmd)
{
return(CmdTab[sd_cmd][2]);//typ potwierdzenia
}
char get_tdata(char sd_cmd)
{
return(CmdTab[sd_cmd][3]);//kolejne dane
wystawiany jest stan wy-
soki i wysyłanych jest 80
cykli zegarowych na linię
MMC_SCLK. Po włączeniu
zasilania karta komuniku-
je się z hostem za pomocą
magistrali SDBus (z jedną
linią danych D0) i żeby ją
przełączyć w tryb SPI trze-
ba wysłać komendę CMD0
zerowania karty przy sta-
nie niskim na wejściu CS.
Ponieważ karta jest w try-
bie SDBus, to przy wysyłaniu CMD0
konieczne jest wysłanie prawidłowej
sumy CRC, bo inaczej komenda zosta-
nie odrzucona. Po przejściu w tryb SPI
sprawdzanie CRC zostaje wyłączone.
Jeżeli potwierdzenie R1 komendy
CMD0 będzie miało wartość 0xFF
(same jedynki), to oznacza, że karta
w ogóle nie przyjęła komendy. Karta
może również być zajęta. Odpowiada
wtedy potwierdzeniem z ustawionym
bitem
Busy
. W obu przypadkach funk-
cja
MediaInitialize
kończy działanie
zwracając kod błędu różny od zera
(
list.
4
).
Karta odpowiada prawidłowo na
komendę CMD0 potwierdzeniem R1
z wyzerowanymi wszystkimi bita-
mi. Wtedy można wysłać komendę
CMD1 SEND_OP_COND inicjalizująca
kartę. Trzeba pamiętać, że część kart
zamiast komendy CMD1 wymaga ko-
mendy ACMD41.
Ponieważ po zerowaniu karty może
być ona zajęta przez pewien czas, to
komenda CMD1 jest wysyłana wiele
razy, aż do otrzymania potwierdze-
Funkcja
SendSDCCmd
(
list.
3
)
zwraca kod potwierdzenia: dla po-
twierdzeń R1i R1b jeden bajt, a dla
potwierdzenia R2 dwa bajty.
Funkcja
MediaInitialize
wykonuje
inicjalizację karty. Zgodnie z wyma-
ganiami standardu na linii MMC_CS
List. 3. Funkcja wysyłająca komendę do karty SD
unsigned int SendSDCCmd(unsigned char cmd, unsigned int
address)
{
char resp;
unsigned char res_byte_l=0,res_byte_h=0,index;
unsigned int res_out;
unsigned int timeout = 8;
SDC_CS_0 //CS=0
Write_SPI(get_cmd(cmd)); //wyslij kod komendy
Write_SPI(address>>24); //najstarszy bajt argu-
mentu
Write_SPI(address>>16); //kolejne bajty argumentu
Write_SPI(address>>8);
Write_SPI(address); //najmlodszy bajt argu-
mentu
Write_SPI(get_crc(cmd)); //wyslij CRC
resp=get_rsp(cmd); //typ odpowiedzi karty
if(resp==R1 || resp==R1b)
{
while(timeout!=0)
{res_byte_l=ReadMedia(); //czekaj na odpowiedz
rozna od 0xFF
if(res_byte_l!=0xff)
break;
timeout--;}
}
else
if(resp == R2)
{ReadMedia();
res_byte_l = ReadMedia();
res_byte_h = ReadMedia();}
if(resp == R1b) //dodatkowo czekaj na
zwolnienie linii danych dla R1b
{
res_byte_l = 0x00;
for(index =0; index < 0xFF && res_byte_l == 0x00; in-
dex++)
{timeout = 0xFFFF;
do
{res_byte_l = ReadMedia();
timeout--;
}while((res_byte_l == 0x00) && (timeout !=
0));
}
}
if(get_tdata(cmd)==NODATA) //nie sa spodziewane
kolejne dane
{SDC_CS_1 //CS=1
Write_SPI(0xff);}
if(resp == R1 || resp == R1b)
return(res_byte_l); //potwierdzenie 1 baj-
towe
if(resp == R2) //poteirdzenie 2 bajto-
we, lub 3 bajtowe
{res_out=res_byte_h;
res_out=res_out<<8;
res_out=res_out|res_byte_l;
return(res_out);}
}
100
Elektronika Praktyczna 3/2008
KURS
List. 4. Funkcja inicjalizacji karty do pracy z magistralą w trybie SPI
#define SDC_CS 1<<21
#define SPI_SEL 0x00100000
#define SDC_CS_1 IOSET0|=SDC_CS; //definicje makr sterowania linią CS
#define SDC_CS_0 IOCLR0|=SDC_CS;
unsigned int MediaInitialize(void)
{
unsigned short timeout=0;
unsigned int CSDstatus=0;
unsigned int resp=0;
IO0DIR|=SDC_CS; //linia CS wyjsciowa
status=0;
SDC_CS_1 // makro CS=1
delay_ms(100);
for(timeout=0; timeout<10; timeout++) //karta wymaga 80 cykli zegra przy inicjalizacji
Write_SPI(0xff);
SDC_CS_0 //CS=0 SC aktywny
delay_ms(10);
resp = SendSDCCmd(cmdGO_IDLE_STATE,0x0); //wyslij komende CMD0 reset karty (adres 0)
if(resp == SDC_BAD_RESPONSE)//odpowiedź 0xFF
{status = sdcCardInitCommFailure; //nic nie odebralismy z karty
goto InitError;}
if(resp != 0x01) //nie ma błedu,ale karta zajęta (BUSY)
{status = sdcCardNotInitFailure; //nic nie odebraliśmy z karty
goto InitError;}
timeout = 0x1FFF; //reset karty poprawny - wysylamy CMD1 procedura inicjalizaci karty
(adres 0)
do{resp = SendSDCCmd(cmdSEND_OP_COND,0x0); //CMD1
timeout--;
}while(resp != 0); //&& timeout != 0); //probujemy 4096 razy az mnie czas lub otrzymamy potwierdzenie 00
if(timeout == 0) //nie otrzymalismy potwierdzenia
{status = sdcCardInitTimeout; //nie odebralismy nic z karty - blad przekroczenia czasu
goto InitError;
}
else
{CSDstatus=CSDRead(); //odczytaj rejestr CID - CMD2
if(CSDstatus==0);
else
{status=sdcCardTypeInvalid;
goto InitError;}
}
resp=SendSDCCmd(cmdSET_BLOCKLEN,BLOCKLEN_512); //ustawienie długości sektora do odczytu na 512 bajtow
if(resp!=0)
{status = sdcCardInitTimeout; //nie odebralismy nic z karty - blad przekroczenia czasu
goto InitError;}
for(timeout = 0xFF; timeout > 0; timeout--)
{resp=SectorRead(0x0,msd_buffer);
if(resp==0)
break;}
if(timeout == 0)
{status = sdcCardNotInitFailure;
goto InitError;}
return(status);
InitError:
SDC_CS_1 //karta nieaktywna
return(status);
}//end MediaInitialize
List. 4. Funkcja odczytania pojedynczego bloku danych z karty
unsigned int SectorRead(int sector_addr, unsigned char *buffer)
{
int index;
unsigned short resp=0;
unsigned char data_token;
resp = SendSDCCmd(cmdREAD_SINGLE_BLOCK,(sector_addr << 9));
if(resp != 0x00)
{
status = sdcCardBadCmd;
}
else
{
index = 0x2FF;
do
{
data_token = ReadMedia();
index--;
}while((data_token == SDC_FLOATING_BUS) && (index != 0));
if((index == 0) || (data_token != DATA_START_TOKEN))//0xFE
status = sdcCardTimeout;
else
{
for(index = 0; index < SDC_SECTOR_SIZE; index++)
buffer[index] = ReadMedia(); //czytanie 512 bajtow danych
ReadMedia(); //CRC
ReadMedia();
}
}
SDC_CS_1 //koniec transakcji
Write_SPI(0xff);
return(status);
}//end SectorRead
nia R1 z wyzerowanymi bitami. Jeżeli
takiego potwierdzenia nie otrzyma-
my po wysłaniu 4096 razy komendy
CMD1, to funkcja
MediaInitialize
jest
kończona i zwraca błąd przekroczenia
czasu inicjalizacji.
Prawidłowe wykonanie komen-
dy CMD1 kończy funkcję inicjalizacji
i można wysłać do karty komendy
odczytania rejestru CSD i dla pewno-
ści ustawić długość bloku dla odczytu
karty na 512 bajtów. Funkcją
MediaI-
nitialize
kończy się próba prawidło-
wego odczytania bloku o długości 512
bajtów. Jeżeli się powiedzie, to funk-
cja zwraca wartość zero oznaczającą
poprawne zainicjowanie karty.
Funkcja
SectorRead
(
list.
5
) odczy-
tuje pojedynczy blok danych (sektor)
o długość 512 bajtów i zapisuje go do
bufora
msd_buffer
w pamięci RAM mi-
krokontrolera. Adres początkowy blo-
ku musi być wielokrotnością długości
bloku danych. Argument
sector_addr
Elektronika Praktyczna 3/2008
101
KURS
zawiera numer bloku danych, a nie
fizyczny adres jego początku. Adres
fizyczny jest wyliczany przez pomno-
żenie numeru bloku przez 512 (prze-
sunięcie o 9 bitów w lewo).
W pierwszym kroku po wysłaniu
komendy READ_SINGLE_BLOCK spo-
dziewane jest odebranie zerowego po-
twierdzenia R1. Jeżeli je otrzymamy,
to są odczytywane dane cyklicznie
z karty, aż do odebrania bajtu startu
DATA_START_TOKEN równego 0xFE.
Potem można już odczytać 512 baj-
tów danych z karty i dodatkowo 2
bajty sumy kontrolnej CRC. Transak-
cja kończy się wysłaniem 8 cykli ze-
garowych na linię SCLK i przejściem
linii CS w stan wysoki.
Funkcja zapisująca pojedynczy blok
danych (
list. 6
) rozpoczyna się od
wysłania komendy WRITE_SINGLE_
BLOCK. Argumentem komendy jest
adres początkowy bloku danych wy-
liczony na podstawie numeru bloku
danych w taki sam sposób jak w pro-
cedurze odczytania bloku danych.
Jeżeli karta odeśle potwierdzenie R1
z wyzerowanymi wszystkimi bitami, to
wysyłanych jest 8 cykli zegarowych
na linię SCLK i bajt startu (0xFE)
DATA_START_TOKEN. Następnie host
wysyła 512 bajtów bloku danych i 2
bajty CRC, a karta potwierdza ich
prawidłowe przyjęcie wysłaniem bajtu
Data Response
o wartości 0x05.
Stan zajętości karty w czasie za-
pisywania bloku danych w pamięci
Flash jest testowany przez cykliczne
odczytywanie danych z karty. Trwa
to tak długo, aż odczytywane dane
będą różne od zera. Testowanie linii
MMC_DO przez odczytywanie danych
z karty (a nie testowanie stanu linii
portu) powoduje, że na linię zegaro-
wą jest wysyłany niezbędny sygnał
zegarowy. Jeżeli zapisywanie zostało
wykonane prawidłowo, to procedura
zwraca wartość zerową, w przeciwnym
wypadku zwraca kod błędu różny od
zera.
Funkcja
CSDRead
(
list.
7
) wysy-
ła komendę SEND_CSD z zerowym
argumentem i czeka na zerowe po-
twierdzenie R1. Jeżeli je otrzyma, to
oczekuje na bajt startu 0xFE dokład-
nie tak samo, jak przy odczytywaniu
bloku danych. W następnym kroku
jest odczytywanych 16 bajtów rejestru
CSD, 2 bajty sumy CRC i karta koń-
czy transakcję.
Tomasz Jabłoński, EP
tomasz.jablonski@ep.com.pl
List. 6. Procedura zapisująca pojedynczy blok danych
unsigned int SectorWrite(short sector_addr, unsigned char *buffer)
{
int index;
unsigned char data_response;
unsigned char resp;
resp = SendSDCCmd(cmdWRITE_SINGLE_BLOCK,(sector_addr << 9));
if(resp != 0x00)
status = sdcCardBadCmd;
else
{
Write_SPI(0xff);
Write_SPI(DATA_START_TOKEN); //wyślij data start token
for(index = 0; index < 512; index++) //wyślij 512 bajtów danych
Write_SPI(buffer[index]);
Write_SPI(0xff); //wyślij 2 bajty CRC
Write_SPI(0xff);
index=16;
while(index>0)
{data_response = ReadMedia(); //czytaj odpowiedź
if((data_response & 0x0F) == DATA_ACCEPTED)
break;}
if(index==0)
{
status = sdcCardDataRejected;
}
else
{index = 0;
do //czekaj na koniec zapisu
{data_response = ReadMedia();
index++;
}while((data_response == 0x00) && (index != 0));
if(index == 0) //nie wykryto końca zapisu
status = sdcCardTimeout;
}
}
SDC_CS_1 //CS=1
Write_SPI(0xff);
return(status);
} //end SectorWrite
List. 7. Procedura odczytu rejestru CSD
unsigned int CSDRead()
{
unsigned short index, timeout=0x2ff;
unsigned int resp;
unsigned char data_token;
SDC_CS_0
Write_SPI(SEND_CSD);
Write_SPI(0);
Write_SPI(0);
Write_SPI(0);
Write_SPI(0);
Write_SPI(0xaf);
do//czekaj na odpowiedz
{resp = ReadMedia();
timeout--;}
while((resp == 0xFF) && (timeout != 0));
if(resp != 0x00)
status = sdcCardBadCmd;
else//komenda zostala zaakceptowana
{
index = 0x2FF;
do//czekaj na data token (0xFE)
{
data_token = ReadMedia();
index--;
}while((data_token == SDC_FLOATING_BUS) && (index != 0));
for(index = 0; index < CSD_SIZE; index++)//zerowanie bufora CSD
csd_buffer[index] = 0;
if((index == 0) || (data_token != DATA_START_TOKEN))//nie odebrano
data token
status = sdcCardTimeout;
else
{
for(index = 0; index < CSD_SIZE; index++)//czytaj 16 bajtow CSD
csd_buffer[index] = ReadMedia();
}
ReadMedia();
ReadMedia();
}
SDC_CS_1
Write_SPI(0xff);
return(status);
}//end CSDRead
102
Elektronika Praktyczna 3/2008
Plik z chomika:
comel
Inne pliki z tego folderu:
Obsługa kart pamięciowych SD, cz.1.pdf
(1270 KB)
Obsługa kart pamięciowych SD, cz.2.pdf
(626 KB)
Obsługa kart pamięciowych SD, cz.3.pdf
(1972 KB)
Obsługa kart pamięciowych SD. cz.4.pdf
(1359 KB)
Inne foldery tego chomika:
! Inteligentny dom materiały
!!!Proteus!!!
-=Evil Genius Books=-
●ELEKTRONIKA
01 - Esp8266
Zgłoś jeśli
naruszono regulamin