Kampis Elektroecke

AVR mit einer SD-Karte erweitern – Teil 3

Im letzten Teil des Tutorials bin ich etwas detaillierter auf die Kommunikation mit der SD-Karte eingegangen. Wir haben gelernt, wie wir einzelne, bzw. mehrere Blöcke einer SD-Karte lesen und schreiben, sowie wie wir bestimmte Status- oder Karteninformationen auslesen können. In diesem Teil des Tutorials werden diese Komponenten genutzt, um das FAT-Modul FatFs nutzen zu können.

Dieses Tutorial baut auf die FatFs-Version R0.13c von Elm Chan auf, welche hier heruntergeladen werden kann. In dem Verzeichnis source des heruntergeladenen Archivs befinden sich alle notwendigen Dateien um die FAT-Unterstützung für den Mikrocontroller zu realisieren. Unsere Aufgabe besteht darin, die Datei diskio.c entsprechend unseres Treibers für SD-Karten anzupassen.

Weiterhin ist noch eine Datei mit dem Namen ffconf.h abgelegt und wird zur Konfiguration des Dateisystems genutzt. Es wurden folgende Konfigurationspunkte geändert:

Konfiguration Neuer Wert Funktion
FF_USE_STRFUNC 1 Aktiviert Funktionen wie f_puts um Zeichenketten in Dateien zu schreiben oder aus Dateien zu lesen.
FF_CODE_PAGE 850 Codepage auf 850 (Latin 1) setzen
FF_USE_LFN 2 Lange Dateinamen unterstützen
FF_FS_TINY 1 Buffergröße verringern
FF_FS_NORTC 1 RTC deaktivieren (weil nicht vorhanden)

Die Funktionsprototypen der Funktionen, die der Anwender in der Datei diskio.c implementieren muss, sind bereits alle angelegt. Unsere Aufgabe besteht also darin die folgenden Funktionen zu schreiben:

Funktion Aufgabe
disk_initialize Speichermedium initialisieren
disk_status Status des Speichermediums auslesen
disk_read Einen oder mehrere Sektoren des Speichermediums auslesen
disk_write Einen oder mehrere Sektoren des Speichermediums schreiben
disk_ioctl Steuerung des Speichermediums

Zusätzlich zeigt Elm Chan, wie mehrere verschiedene Speichermedien mit dem Modul genutzt werden können indem jedes Medium eine eigene Laufwerksnummer bekommt:

In diesem Tutorial soll nur eine SD-Karte als Laufwerk benutzt werden. Die SD-Karte soll zudem die Nummer 0 bekommen.

Die erste Funktion, die wir implementieren wollen ist die Funktion disk_initialize, mit der das angeforderte Speichermedium initialisiert wird. Diese Funktion besitzt lediglich die Laufwerksbezeichnung als Übergabeparameter, welcher mittels einer switch-Anweisung ausgewertet werden muss:

Wenn das Laufwerk erfolgreich initialisiert worden ist, wird zudem noch eine entsprechende Statusvariable gesetzt. Diese Variable kann dann mit der Funktion disk_status abgefragt werden:

Als nächstes wird die Funktion disk_read implementiert. Diese Funktion übergibt, neben der Laufwerkskennung, einen Zeiger auf einen Datenbuffer, den angeforderten Sektor und die Anzahl an Sektoren, die gelesen werden sollen. Diese Informationen werden ausgewertet und die entsprechenden Funktionen des SD-Kartentreibers aufgerufen:

Bei der Funktion disk_write wird ähnlich vorgegangen:

Jetzt fehlt nur noch die Funktion disk_ioctl. Diese Funktion hat die Aufgabe allgemeine Informationen zu der SD-Karte, wie z. B. die Sektorgröße bereitzustellen. Das angeforderte Kommando wird als Übergabeparameter mit in die Funktion übergeben und muss dann ausgewertet werden. Die Funktion kder einzelnen Kommandocodes kann in der Dokumentation nachgelesen werden.

Bei dem Kommando GET_BLOCK_SIZE wird die Erase Block Size des Speichermediums zurückgegeben. Diese Information lässt sich bei SD-Karten mit Version 2 oder später aus dem Statusregister auslesen (siehe Tutorial Teil 2):

Das Kommando GET_SECTOR_COUNT fragt die Anzahl an Sektoren des Speichermediums ab. Diese Information kann dem CSD-Register der SD-Karte entnommen werden. Bei SD-Karten mit Version 2 oder später kann die Anzahl der Sektoren über das CSD-Register berechnet werden.

Mit Hilfe des Kommandos GET_SECTOR_SIZE wird die Größe eines Sektors des Speichermediums abgefragt. SD-Karten mit einer Version 2 oder später haben eine feste Sektorgröße von 512 Byte. Daher gibt dieses Kommando lediglich einen konstanten Wert zurück.

Das letzte Kommando namens CTRL_SYNC dient dazu um offene Schreiboperationen des Speichermediums zu beenden. Wenn das Gerät einen Cache hat, muss dieser Cache geleert und in den Speicher geschrieben werden. Bei der SD-Karte wird die Karte abgewählt, wodurch die SD-Karte alle offenen Operationen beendet:

Damit wären alle notwendigen Funktionen programmiert und die SD-Karte kann beschrieben werden. Dazu soll der folgende Codeschnipsel verwendet werden:

Ähnlich wie bei Windows besteht auch bei FatFs der Dateiname aus einer Laufwerksbezeichnung und dem eigentlichen Namen. In diesem Beispiel soll also die Datei File.txt auf dem Laufwerk mit der Kennung 0 gespeichert werden. Dies entspricht der SD-Karte.

Zu allererst wird die SD-Karte über die f_mount-Funktion eingebunden. Über den Parameter 1 wird das Speichermedium direkt eingebunden, sodass man direkt überprüfen kann ob die Speicherkarte erkannt wird.

Anschließend soll eine neue Datei mit dem Pfad 0:File.txt angelegt, mit dem Text Hello, World gefüllt und wieder geschlossen werden. Eine bereits vorhandene Datei wird dabei überschrieben.

Als letztes soll die erstellte Datei geöffnet, der komplette Inhalt ausgelesen und wieder geschlossen werden.

Wenn das Programm nun gestartet wird, wird die SD-Karte eingebunden, die Datei angelegt, beschrieben und ausgelesen und der Inhalt in dem Array ReadData gespeichert. Mit einem Kartenleser kann nun zusätzlich der Inhalt der SD-Karte überprüft werden.

Hat alles funktioniert? Wunderbar. Damit habt ihr euren AVR erfolgreich mit einer SD-Karte und einem FAT-Dateisystem ausgestattet.

Das komplette Projekt findet ihr in meinem GitLab-Repository.

Viel Spaß mit der SD-Karte :)
Daniel

Ein Kommentar

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.