SD-, SDHC- und MMC-Karten an AVR anschliessen

Page content

SD-Karten (von der SD Association spezifiziert) und die älteren MMC-Karten sind billige Massenspeicher mit geringem Stromverbrauch. Neben einem eigenen Protokoll (“native bus”) verstehen MMC- und SD-Karten auch eine Kommunikation mittels SPI. SPI spricht der AVR schon von Hause aus. Es ist daher nicht allzu schwer, eine solche Karte an den AVR anzuschließen.

Neben den SDSC-Karten (SC=Standard Capacity, normalerweise als SD-Karten bezeichnet) gibt es auch die elektrisch gleichen, aber software-technisch unterschiedlichen SDHC-Karten (HC=High Capacity) und seit 2009 SDXC-Karten. SDSC-Karten haben FAT12 oder FAT16-Filesystem. Mit FAT16 kann man bis 2GByte darstellen. Manche Hersteller bieten allerdings auch 4GB mit SD-Karten an. Mehr geht aber nur mit SDHC, die ein FAT32 Filesystem haben. SDHC ist bis 32GB spezifiziert, SDXC dann bis 2TB.

Neben den “normalen” SD-Karten gibt es auch MicroSD-Karten, die deutlich kleiner sind. Abgesehen von den Abmessungen sind sie aber genauso zu nutzen wie die großen SD-Karten. Mit einem einfachen SD-Adapter können MicroSD-Karten genauso wie SD-Karten verwendet werden.

Für unterschiedliche Anwendungsbereiche gibt es unterschiedliche Geschwindigkeitsklassen, von “Class 2” bis “Class 10” (2011). Die Zahl steht für die Transferrate in MByte/s beim Schreiben.

Einige Speicherkarten, von oben links im Uhrzeigersinn: SDHC, SDHC, SD, MMS (8MB), alte SD (16MB). Die beiden SDHC-Karten sind mit dem Symbol für die Geschwindigkeitsklasse “Class 2” versehen.

Eine MicroSD-Karte mit SD-Adapter

Hardware

Für das mechanische Anschließen der Karte kann man sich einen SD-Kartenslot fertig kaufen. Der Slot besitzt meist auch einen Pin, an dem man eine eingeschobene Karte erkennen kann. SD-Karten besitzen einen Schreibschutzschalter, den man abfragen kann. Wichtig sind die folgenden Pins:

SPI Funktion SD-Karte Pin-Nr. AVR Pin-Nr. (am Beispiel AT Mega 32) (Pin-Nr. Pollin-Board)
CS - Chip Select 1 SS - PB4 muss als Ausgabe-Pin konfiguriert werden, es kann aber ein beliebiger anderer Pin für das CS-Signal genutzt werden. Nur wenn SS aus Ausgabe-Pin konfiguriert ist, läuft der AVR als SPI-Master. z.B. 1 (=Port A, Pin0)
DI - Data In / CMD 2 MOSI - PB5 14
DO - Data Out / DATA 7 MISO - PB6 15
CLK - Clock 5 SCK - PB7 16
Ground 3 und 6 Beide Pins zusammenschalten! 39
Vcc 4 Vcc soll zwischen 2,7 und 3,6V liegen

Nach einem allgemein anerkannten Vorgehen wie bei Ulrich Radig beschrieben, kann die Vcc für die Karte aus 5V über den Spannungsabfall an zwei Dioden (je 0,7V) gewonnen werden. Die Pins CS, DI und CLK müssen über Spannungsteiler an den AVR angeschlossen werden, wenn dieser mit Spannungen >3,6V betrieben wird. Für 5V werden üblicherweise 1,8K Richtung AVR und 3,3K gegen Masse genommen. DO wird direkt auf den AVR-Eingang gelegt.

Pinbelegung, SD (oben) und MMC (unten)

Software

Das Thema SD-Kartenanschluss ist bereits vielfach von Null an angegangen worden. So gibt es fertige Bibliotheken und Anwendungen hierfür. Siehe hierzu ganz unten “Links”. Ich habe mir mehrere Bibliotheken angesehen und dann mit der Bibliothek von Roland Riegel experimentiert, weil diese gut dokumentiert ist auch schon von vielen Nutzern erfolgreich eingesetzt wurde.

Kommunikationsbetrachtung

Obwohl das Thema also ausführlich beackert ist, habe ich trotzdem ziemlich viel herumprobieren müssen, bis meine Karten liefen. Die Anbindung verhält sich bei unterschiedlichen Karten leider nicht immer gleich. Ich habe mir daher mit dem Logikanalysator die Kommunikation des AVR mit einer funktionierenden Karte mal genau angesehen.

Eine 2G Transcend SD-Karte wurde an einen AT Mega32, der mit 8Mhz Quarz betrieben wird, angeschlossen. Die SPI-Taktfrequenz wurde auf 125Khz eingestellt. Ein Logikanalysator wurde auf 2 Mikrosekunden asynchroner Takt eingestellt. Ein Bit ist dann 8 Mikrosekunden und damit 4 Takte des Analysators lang. Die Leitungen CS wurde auf Probe A0 (“GRPA00”), DI auf Probe A1 (“GRPA01”), DO auf Probe A2 (“GRPA02”) gelegt. CLK wurde auf Probe A03 (“GRPA03”) gelegt.

  1. Der AVR möchte die Karte initialisieren.

Die Karte wird während der Initialisierung mit einer SPI-Taktfrequenz von 400Khz angesprochen. Nach der Initialisierung wird üblicherweise auf einen deutlich höheren Takt umgeschaltet. Man muss die 400Khz nicht sklavisch einhalten, ich habe 62,5Khz und 125Khz probiert, beides ging, ich vermute dass man die 400Khz nicht deutlich überschreiten darf. Nach Initialisierung kann man den SPI-Takt z.B. auf 2Mhz hoch schalten.

Der AVR wählt die Karte aus (CS auf 0) und sendet das Kommando “Go Idle State”/“CMD0” an die Karte.

Auf dem folgenden Bild wurde der Trigger des Analysators auf “CS geht auf 0” gesetzt. Der Triggermoment t=0 wird durch die gestrichelte rote Linie (“CURSOR1”) dargestellt. Man sieht, dass unmittelbar nach dem Trigger Taktsignal vom AVR gesendet werden. Während aller 8 Taktzyklen hält der AVR seinen Ausgang MOSI (“GRPA01”) auf 1. Im Ergebnis sendet der AVR ein 0xff. Dies ist korrekt, da vor dem Senden oder Lesen von der SD-Karte ein paar Taktzyklen zur Synchronisation von Master und Slave durch den Master gesendet werden. Im Code von Roland Riegel findet man dies in sd_raw.c, Funktion sd_raw_send_command_r1() wieder:

response = sd_raw_send_command_r1(CMD_GO_IDLE_STATE, 0);

Im Code wird die Synchronisation dadurch erreicht, dass sd_raw_rec_byte() ein 0xff sendet und ein “Dummy Byte” von der Karte liest. Die Karte hat im Moment nichts sinnvolles zu senden und sendet acht 0-Bits, also 0x00. Die gültigen Bit-Werte werden übrigens übernommen, wenn die Takt-Flanke von 0 auf 1 geht (“rising edge”).

Als nächste Bitfolge wird 0100.0000, also 0x40 an die Karte gesendet. Die durchgezogene Rote Linie (“CURSOR2”) steht genau auf dem 8. Bit dieses Bytes.Dies entspricht dem zu sendenden CMD0 (=0x00), geodert mit 0x40. Danach sendet der AVR viermal 0x00. Nur eines dieser vier Bytes ist komplett auf dem Bild zu sehen.

Auf dem folgenden Bild bin ich auf der Zeitachse nach rechts gegangen, man kann nun die letzten zwei 0x00-Bytes ganz sehen. Die 4 Bytes sind übrigens ein 32 Bit Argument zum Kommando CMD0, wobei das Argument den Wert 0 hat.

Nach den vier Argument-Bytes wird ein CRC-Byte gesendet. Dieses hat für die gesendete Bytefolge 0x40,0x00,0x00,0x00,0x00 den Wert 0x95. Tatsächlich lässt sich dieser Wert auch als Bitfolge 1001.0101 aus dem Bild ablesen (dritte komplette 8Bit-Folge im Bild, am Takt leicht erkennbar).

Als Antwort sendet die Karte nun ein 0xff. Der Cursor steht genau auf dem ersten Bit dieses Bytes. Solange die Karte noch keine Antwort komplett hat, sendet sie 0xff als Fülsel. Danach kommt die “echte” Antwort, eine 0x01. Im Code von Roland Riegel findet man hierzu:

if(!(response & (1 << R1_IDLE_STATE))) break;

D.h. das Kommando CMD0 wurde von der Karte akzeptiert, wenn sie ein 0x01, wie in unserem Falle, zurücksendet. Nach Verarbeiten von CMD0 ist die Karte nicht mehr im “native” Mode und benötigt am Ende der Kommandos nun keine CRC-Bytes mehr.

CMD0 mit SPI

  1. Der AVR wartet darauf, dass Karte sich initialisiert hat.

Die Karte benötigt eine gewisse Zeit für ihre Initialisierung. Wenn sie fertig ist, antwortet sie auf das Kommando “Send Op Cond” / CMD1 als Antwort 0x00.

Im folgenden Bild wurde CMD1 gesendet, sowie die folgenden vier Argument-Bytes mit 0x00. Das CRC-Byte entfällt nun. Auch hier kann man erkennen, dass die Karte zunächst ein 0xff-Byte schickt. Danach schickt sie bis die Initialisierung fertig ist, 0x01. Das Ende der Initialisierung, d.h. die abzuwartende Antwort auf CMD1 ist 0x00.

SPI CMD1 command

Im folgenden Bild habe ich das Eintreffen der Antwort 0x00, auf CMD1, abgewartet. Da es etwa 60ms dauerte, bis die Karte die korrekte Antwort schickt, habe ich den Trigger hier anders definiert, somit stimmt die angegebene Zeit (Cursor Delta) von 0,1ms hier nicht mehr. Der Cursor steht direkt auf dem letzten Takt des Bytes 0x00.

SPI CMD1 end of init

  1. Die SD-Karte ist fertig initialisiert. Man kann nun Lese- und Schreibkommandos zur Karte schicken.

Hier das Ergebnis des Lesens einer SD-Karte mit FAT16, Sektor 0 (Boot-Sektor):

0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
10 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
20 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
30 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
40 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
50 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
60 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
70 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
80 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
90 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
A0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
B0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
C0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
D0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
E0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
F0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
100 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
110 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
120 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
130 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
140 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
150 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
160 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
170 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
180 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
190 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
1A0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
1B0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 ................ 
1C0 - 04 00 06 1c dc cc ff 00 00 00 01 d3 3b 00 00 00 ....���....�;... 
1D0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
1E0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
1F0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa ..............U�

Ich kann mit meiner Hardware und Software nicht jede Karte erkennen. Hier eine Aufstellung, was zur Zeit funktioniert:

Typ Hersteller Name Größe Filesystem Lesbar mit simpler Hardware und Roland Riegels FAT16-Bibliothek Speed Faktor Kommentar
MMC Palm PalmPak Card 8M FAT12 Hardwaremäßig erkannt, wegen FAT12 nicht lesbar Karte ist als “Rest” eines Palms übrig geblieben.
SDSC Palm Palm Backup Card 16M FAT16 Nein, CMD0 wird falsch beantwortet Karte ist als “Rest” eines Palms übrig geblieben.
SDSC PNY Technologies/ Toshiba SD-M01G 1G FAT16 Nein, CMD0 wird falsch beantwortet
SDSC Transcend 6451AG 2G 02DS 2G FAT16 Ja
SDHC SanDisk TS4GSDHC6 4G FAT32 Nein, CMD0 wird falsch beantwortet Class 2
SDHC extrememory SDHC4GB 4G FAT32 Nein, CMD0 wird falsch beantwortet Class 2
SDHC Transcend TS4GSDHC6 4G FAT32 Ja Ultraspeed Class 6, MLC
SDHC Transcend TS16GSDHC6-S5W (TS-RDS5W) 16G FAT32 Ja Ultraspeed Class 6

Die fehlerhafte Bearbeitung von CMD0 durch die Karte ist am Beispiel der extrememory-Karte hier zu sehen. Ich habe den Verdacht, dass die Karte zwar die erwartete Antwort schickt, aber vorher 1 Bit verschluckt wird, so dass das Alignment der Bits im Byte falsch ist und so die erwartete Antwort auf CMD0 (0x01) nicht gelesen wird, statt dessen wird 0x03 gelesen. Warum das so sein könnte ist mir aber völlig unklar. An alle Leser: Falls mir da jemand helfen kann, wäre ich glücklich(er)!

FAT32 Bibliothek

Da ich mehr als 2GB Daten verwalten muss (in einem MP3-Player), bin ich später auf SDHC-Karten übergegangen. Die Bibliothek von Roland Riegel unterstützt leider nur FAT16. Ich bin nach Analyse der verfügbaren Bibliotheken auf die FatFs von Elm Chan gegangen. Unterhalb des Filesystem-Layers verwende ich eine Mischung aus der sd_mmc-Schicht von Roland Riegel und der mmc-Schicht von Elm Chan, da Roland Riegels Bibliothek in der von mir genutzten Version keine HDSC unterstützte. Nachteil: Die Bibliothek von Elm Chan unterstützt leider keine langen Dateinamen.

Geschwindigkeit von SD-Karten

Der über die Speed Rate/Class gegebene Wert ist ein Minimalwert, d.h. die Karte kann in vielen Situationen schneller sein. Erst seit der Existenz des Standards SDHC gibt es diese Geschwindigkeitsklassen.

Der AVR schreibt nicht sonderlich schnell auf die Karte, so dass normalerweise die Geschwindigkeit der Karte “nicht so wichtig” ist. Trotzdem hier auch ein paar wahllose Messungen, die ich durchgeführt habe. Unter Linux kann man -wenn der momentane Inhalt der Karte egal ist- mittels

  • Schreiben: dd count=1k bs=1M if=/dev/zero of=/media/my-sd-card/test.img

  • Lesen: dd count=500 bs=1M if=/media/my-sd-card/test.img of=/dev/zero

die reale Schreibgeschwindigkeit prüfen. (“my-sd-card” steht dabei für den tatsächlichen Namen der gemounteten Partition der SD Karte. Auf der Karte muss dabei 1GB (1k*1M) frei sein. Vor dem Lesetest muss der Schreibtest ausgeführt werden und die Karte kurz vom Rechner unmounted/entfernt werden).

Karte Speed Rate ClassAufdruck Lesen [MB/s] Schreiben [MB/s]
SDHC extrememory Allround, 4GB 2 20,1 11,2
SDHC SanDisk, 4GB 2 10,8 6,1
SD PNY, 1GB (ohne) 8,5 2,7
SD Noname? “SD Platinum “, 1GB (ohne) 14,9 5,1