Alle Schaltpläne, derer ich im Netz der Netze habhaft werden konnte, verwenden zur Kommunikation mit einer SD-Karte ausschließlich das 1-Bit Protokoll, gleichwohl eine SD-Karte durchaus auch in einem 4-Bit Mode betrieben werden kann. Neuere Modelle sogar in einem 8-Bit Mode. Hier eine
Seite, die sich ausgiebig mit dem 1-Bit Mode auseinander setzt. Und hier noch eine
Seite eines Controllers von TI, der auch 4-Bit und 8-Bit Modi unterstützt.
Gerade für Atmel-Prozessoren bietet sich der 1-Bit serielle Modus aber an, da hier der Microcontroller direkt über das SPI-Interface mit der Karte kommunizieren kann. Natürlich gibt es auch Überlegungen, die Karte im 4-Bit Modus zu betreiben, um damit höhere Geschwindigkeiten zu erreichen, allerdings hat die Sache (wie so viele) einen Haken: Beim Schreiben in die Karte verlangt diese zum Sicherstellen der Richtigkeit der Daten eine Prüfsumme. Diese Prüfsumme ist eine CRC16 mit einem Initialwert von 0 und einem XOR-Wert von 0x1021. Offenbar bereitet den Prozessoren das Berechnen dieser CRC bei einer 4-Bit Übertragung noch erheblich mehr Probleme, als das bitweise Übertragen und CRC-Berechnen, sodass unterm Strich keine nennenswerte Geschwindigkeitssteigerung zu erzielen ist.
Wie berechnet man überhaupt eine CRC? Zunächst einmal ist eine CRC16 oder CRC32 oder wie auch immer nur eine Rechenvorschrift, wie das Multiplizieren oder das Dividieren. Es gibt nicht
die CRC16 oder
die CRC32. Für die Berechnung einer CRC braucht man zusätzlich einen Startwert (den Seed) und das Polynom.
Für die CRC8 für die SD-Karten Kommandos sind das beispielsweise Startwert 0 und Polynom x⁷ + x³ + 1, oder auch 10001001. Für die CRC16 für die Datenübertragung zur SD-Karte sind dies Startwert 0 und Polynom 0x1021. Die CRC32 für Netzwerk-Verbindungen hat zum Beispiel das Polynom 0x04C11DB7. Die eigentliche Berechnung der CRC geschieht bitweise wie folgt:
1. Das CRC Register wird mit dem Startwert initialisiert.
2. Jedes eintreffende Bit wird mit dem höchsten Bit des CRC-Registers verglichen.
3. Sind diese beiden Bits identisch, wird das CRC-Register um 1 nach links geschoben und an die rechte Stelle kommt eine 0.
4. Sind diese beiden Bits nicht identisch, wird zunächst das CRC-Register um 1 nach links geschoben und an die rechte Stelle kommt eine 0, und anschließend wird das CRC-Register mit dem Polynom verXORt.
5. Gehe zurück zu 2. solange Daten vorhanden sind. Andernfalls steht nun im CRC-Register die Prüfsumme.
Nun hat die SD-Karte ja zwei Kommunikationspfade, nämlich den 1-Bit breiten Kommandokanal, und den 1-, 4-, oder 4-Bit breiten Datenkanal. Über ersteren wird eine auf 7 Bit abgeschnittene CRC8 benutzt, aber dem Datenkanal die CRC16. Die hauptsächliche Kommunikation auf dem Kommandokanal besteht aus der Initialisierung und den Kommandos zum Senden oder Empfangen von Daten. Da es sich hier zum einen nur um wenige Bytes handelt (die Kommandos sind 6 Bytes lang, die Antworten meistens ebenso, bis auf eine 17 Byte lange Ausnahme), und zum anderen die meisten Kommandos nur während und zur Intialisierung der Karte ausgetauscht werden, kann diese Arbeit getrost dem Prozessor überlassen werden, zumal eine CRC8 noch bequem von einer 8-Bit CPU zu bewältigen ist.
Bei der Betrachtung des Datenkanals fällt aber auf, dass hier hauptsächlich Sektoren zu 512 Bytes übertragen werden, und das mehrmals nacheinander. Hier macht sich beim Schreiben die Rechenzeit für die CRC16 deutlich bemerkbar. Beim Lesen könnte diese Rechenzeit theoretisch entfallen, wenn man denn die von der SD-Karte empfangenen Daten nicht auf Richtigkeit prüfen will.
Eine Idee, mit der gerade liebäugele, ist (mal wieder) die Verwendung eines CPLD. Nicht nur als Portexpander für den Prozessor, damit der überhaupt mit der SD-Karte kommunizieren kann, sondern auch als on-the-fly CRC16 Rechner. Das ist nicht allzu schwierig, da sich CRC-Routinen gut in Hardware realisieren lassen.
Schwieriger hingegen ist die Einhaltung des genauen Protokolls für die SD-Karten. Allein die Initialisierungs-Sequenz hat schon manchen Programmierer an den Rand des Wahnsinns gebracht, da auch jede Karte (MMC, SD, SDHC) anders initialisiert werden will.
Gesetz dem Fall, man hat es mit einer SD-Karte zu tun, dann muss man erst mal Daten-, Kommandoleitung und das CardSelect-Signal auf 1 legen und mindestens 74x an der Clock-Leitung rütteln, bis die Karte "wach" ist. Sodann darf man die Karte mit dem CMD0 Kommando zurücksetzen. Mit dem CMD5 Kommando fragt man nun solange nach, bis die Karte meldet, dass sie bereit ist. Das kann bei älteren und größeren Modellen schon mal eine Sekunde dauern. Nun kann man mit den Kommandos CMD2 und CMD3 die Kartenspezifikationen ermitteln, also Hersteller, Geschwindigkeit, Busbreite, usw. Sind diese Informationen alle beisammen, ist die Initialisierung abgeschlossen und die weitere Kommunikation beschränkt sich auf den Datentransfer.
Die Kommandos, die der Mikroprozessor an die Karte sendet, sind während der Initialisierung also immer identisch. Insofern spricht einiges dafür, die Bytesequenz der Kommandos komplett, also inklusive der Prüfsumme, im Programmcode zu hinterlegen. Für die weiteren Kommandos geht das leider nicht. Zum Schreiben und Lesen von Daten gibt es jeweils zwei Befehle. Einer der beiden Befehle initiiert die Übertragung für einen Block, der andere eine ganze Reihe von Blöcken. Die Blockgröße liegt bei SDHC-Karten bei 512 Bytes, bei SD-Karten kann sie mit dem CMD16 festgelegt werden.
Wenn beispielsweise mit dem CMD17 ein einzelner Block angefordert wird, dann empfängt man 512 Byte Daten inkl. Prüfsumme, und meldet dann mit dem CMD12 das Ende der Übertragung. Soweit, so einfach. Werden mit dem CMD18 eine ganze Reihe Blöcke angefordert, so sendet die SD-Karte solange Daten, bis der Prozessor einer CMD12 sendet. Was hier nicht unter den Tisch fallen darf ist, dass auf jedes Kommando auch eine Reaktion, eine Antwort auf dem Kommandokanal gesendet wird. Das bedeutet, dass nach einem CMD17 oder CMD18 sowohl auf dem Kommandokanal, also auch auf dem Datenkanal empfangen werden muss.
Jetzt mal ganz ehrlich: Wer sich sowas ausgedacht hat, sollte sich am Tag des Jüngsten Gerichtes dafür verantworten müssen!
Mehr und mehr komme ich zu der Einsicht, dass die Verwendung einer SD-Karte eher was für Masochisten ist. Es gibt nämlich eine Alternative, ohne Bitschiebereien, ohne Kommandosequenzen, ohne Prüfsummen: CompactFlash Karten. Diese Karten sind genauso preiswert zu bekommen wie SD-Karten, aber wesentlich angenehmer anzuschließen. Ich werde mal in dieser Richtung forschen, aber ich denke, einfach als
das hier geht es nun wirklich nicht mehr.