Beim Speichern von Daten auf einem ESP8266 begegnen wir häufig denselben Schlüsselbegriffen: EEPROM, SPIFFS, LittleFS und RTC Memory. Jede dieser Methoden bietet eine Möglichkeit, Daten auf dem Gerät zu sichern. Eine Variante schauen wir uns heute genauer an: Das LittleFS Dateisystem auf dem ESP8266.
Mit dem LittleFS Dateisystem können wir auf den Flash-Speicher zugreifen als wäre es ein Dateisystem auf dem Computer. Wir können Dateien und Verzeichnisse anlegen, Dateien lesen und auch Dateien schreiben. Das Beste an der ganzen Sache ist: die gespeicherten Dateien überleben sowohl einen Deep Sleep als auch einen Reboot. Die Daten die gespeichert werden, sind in einem nicht flüchtigen Speicher hinterlegt. Dem Little File System.
Zum Kapitel springen Allgemeines
Die Speicherkapazität des LittleFS hängt vom spezifischen ESP8266-Modell ab. Der D1 Mini bietet beispielsweise eine FS-Kapazität von bis zu 3MB, während der ESP01-S maximal 512KB erreicht – was für zahlreiche Projekte aber auch völlig ausreichend ist.
In diesem Tutorial beschäftigen wir uns mit dem LittleFS eines ESP8266 D1 Mini.
Die Größe des Dateisystems kann mithilfe der Arduino IDE eingestellt werden. Geht dazu über das Menü der IDE auf folgenden Punkt:
Arduino IDE
└── Werkzeuge
└── Flash Size
├── 4M (FS:2MB OTA:~1019KB)
├── 4M (FS:3MB OTA:~512KB)
├── 4M (FS:1MB OTA:~1019KB)
└── 4M (FS:none OTA:~1019KB)
Die Angaben zu den Flash Size-Optionen bieten Informationen zur Aufteilung des Speichers zwischen dem Dateisystem, den Platz für Over The Air Updates und der verbleibenden Kapazität für den Programmcode selbst.
Die Auswahl der richtigen Speicheraufteilung sollte immer auf basierend auf dem aktuellen Projekt getroffen werden. Werden keine Over The Air Updates benötigt, so kann man diese Kapazität beispielsweise so niedrig wie möglich halten. Hat man dazu noch einen sehr kleinen Programmcode, so könnte man die Größe des LittleFS voll ausschöpfen falls nötig.
Zum Kapitel springen Programmcode
Um auf die Funktionen des LittleFS zugreifen zu können, wird eine Bibliothek benötigt. Diese Bibliothek ist aber bereits standardmäßig installiert und kann sofort verwendet werden. Ich möchte an dieser Stelle direkt mit einem Beispiel zur Verwendung des Dateisystems starten. Das Beispiel öffnet eine Datei und liest deren Inhalt aus. Sollte die Datei nicht vorhanden sein, wird die Datei erstellt und mit einem Inhalt versehen:
// Code by cooper.bin@makesmart.net
// Filesystem-Libary einbinden
#include "LittleFS.h"
// Name der Datei die wir speichern und auslesen möchten
const char* dateiname = "meine.txt";
void setup() {
delay(1000);
Serial.begin(115200);
Serial.println();
Serial.println("ESP gestartet");
// Dateisystem initialisieren
if( LittleFS.begin() ){
Serial.println("Dateisystem: initialisiert");
}else{
Serial.println("Dateisystem: Fehler beim initialisieren");
}
// Dateisystem formatieren
//LittleFS.format();
// Öffnen der von uns definierten Datei nur mit Leserechten
// r - Read - nur Leserechte
// w - Write - Schreibrechte
// Vorhandensein der Datei überprüfen und öffnen
File file = SPIFFS.open(dateiname, "r");
if ( !file ) {
// Die Datei ist nicht vorhanden
Serial.println("Die Datei " + String(dateiname) + " existiert nicht!");
// Datei mit Schreibrechten öffnen, wird erstellt wenn nicht vorhanden
file = LittleFS.open(dateiname, "w");
if ( file ) {
Serial.println("Datei " + String(dateiname) + " wurde erstellt!");
// Daten in die Datei schreiben
file.print("Der Inhalt meiner Datei.");
// Schließen der Datei
file.close();
}
} else {
// Die Datei ist vorhanden
Serial.println("Die Datei " + String(dateiname) + " wurde geöffnet!");
// Inhalt der Datei in eine String-Variable lesen
String fileContent = "";
while ( file.available() ) {
fileContent += (char)file.read();
}
// Ausgabe des Dateiinhalts
Serial.println(fileContent);
// Schließen der Datei
file.close();
}
}
void loop() {
delay(20000);
// Hier wird einfach nur der Inhalt der Datei in Dauerschleife ausgegeben
File file = LittleFS.open(dateiname, "r");
// Inhalt der Datei in eine String-Variable lesen
String fileContent = "";
while ( file.available() ) {
fileContent += (char)file.read();
}
// Ausgabe des Dateiinhalts
Serial.println(fileContent);
// Schließen der Datei
file.close();
}
Die Ausgabe im seriellen Monitor sieht wie folgt aus:
ESP gestartet
Dateisystem: initialisiert
Die Datei meine.txt existiert nicht!
Datei meine.txt wurde erstellt!
Der Inhalt meiner Datei.
Zum Kapitel springen Erläuterungen des Programmcodes
Zum Kapitel springen Dateisystem initialisieren
Das Dateisystem muss vor der Verwendung immer initialisiert werden. Ansonsten kann weder Lese- noch Schreibzugriff erfolgen. Diese Initialisierung erfolgt am besten direkt im Setup, so hat man danach an jeder Stelle im Programmcode zugriff auf das Dateisystem.
if( LittleFS.begin() ){
Serial.println("Dateisystem: initialisiert");
}else{
Serial.println("Dateisystem: Fehler beim initialisieren");
}
Zum Kapitel springen Das File-Objekt
In dem Beispiel wird der Name der Datei in einer Variable gespeichert. Mithilfe dieser Variable erstellen wir ein neues File-Objekt mit dem Namen file
. Über dieses Objekt greifen wir dann auf die einzelnen Funktionen der Bibliothek zu:
const char* dateiname = "meine.txt";
// Öffnen der von uns definierten Datei
// r - Read - nur Leserechte
// w - Write - Schreibrechte
File file = LittleFS.open(dateiname, "r");
Zum Kapitel springen Datei anlegen
Beim ersten Start existiert die Datei noch nicht. Die Verfügbarkeit einer Datei lässt sich mit dem soeben erstellten file-Objekt überprüfen.
if ( !file ) {
// Die Datei ist nicht vorhanden
Serial.println("Die Datei " + String( dateiname ) + " existiert nicht!");
// Datei mit Schreibrechten öffnen, wird erstellt wenn nicht vorhanden
file = LittleFS.open( dateiname, "w" );
if ( file ) {
Serial.println("Datei " + String( dateiname ) + " wurde erstellt!");
// Daten in die Datei schreiben
file.print( "Der Inhalt meiner Datei." );
// Schließen der Datei
file.close();
}
}
In diesem Teil wird die Datei meine.txt
angelegt, da sie zuvor noch nicht existiert hat. Gleichzeitig wird der Text Der Inhalt meiner Datei.
in ihr abgespeichert.
Nach einem Neustart des ESPs wird der Codeabschnitt übergangen. Die Datei liegt dann bereits vor und die Bedingung der If-Abfrage wird dementsprechend nicht erfüllt.
Zum Kapitel springen Datei lesen
Für die weitere Verwendung des Dateiinhalts kann der nachfolgende Codeabschnitt sowohl im Setup als auch in der Loop-Funktion eingesetzt werden.
File file = LittleFS.open(dateiname, "r");
// Inhalt der Datei in eine String-Variable lesen
String fileContent = "";
while ( file.available() ) {
fileContent += (char)file.read();
}
// Ausgabe des Dateiinhalts
Serial.println(fileContent);
// Schließen der Datei
file.close();
Zum Kapitel springen Dateiupload vom PC auf den ESP8266
Es ist bereits möglich, Dateien auf dem ESP8266 zu lesen und zu schreiben. Doch wie verfährt man mit Dateien, die auf dem PC vorhanden sind und auf den ESP8266 übertragen werden sollen? Ein praktisches Beispiel ist das Speichern von Konfigurationsdateien direkt vom PC auf den ESP8266, die anschließend im Programm verwendet oder angepasst werden können. Ein weiterer Anwendungsfall könnte das Hochladen von HTML- und CSS-Dateien für einen Webserver sein. Dies ermöglicht es, die Dateien am PC zu bearbeiten und zu gestalten, bevor sie auf das Dateisystem des ESP geladen werden, von wo aus der Webserver sie dann ausliefern kann.
Produktempfehlungen und -suche in Verbindung mit dem Amazon Partnerprogramm:
¹ Angaben ohne Gewähr. Bei einem Kauf über den Link erhalten wir eine Provision.
Es gibt sowohl für die Arduino Legacy IDE Version 1.8.x als auch für die neue Arduino IDE 2.x ein Plugin, mit welchem man Dateien auf den ESP8266 hochladen kann. Solltest du noch die Version 1.8x verwenden, kannst du dir eine Anleitung dazu direkt im Git-Repository anschauen. Die Suche nach einem Plugin für die neue Arduino IDE 2.x war etwas schwieriger, aber ich bin fündig geworden. Mit dem Plugin arduino-littlefs-upload lassen sich auch mit der Arduino IDE 2.x Dateien hochladen. Es wird dabei mindestens die Arduino IDE Version 2.2.1 benötigt.
Zum Kapitel springen Plugin in der Arduino IDE installieren
Zuerst muss die aktuelleste Version des arduino-littlefs-upload Plugin heuntergeladen werden. Genauer gesagt brauchen wir eine .vsix
Datei. Über den Link kann diese Datei direkt heruntergeladen werden. Zum aktuellen Zeitpunkt ist die Version 1.1.4 die aktuellste.
Die Datei muss nun in den Plugin-Order der Arduino IDE kopiert werden. Je nach System ist der Ordner an einem anderen Ort gespeichert:
- Windows:
C:\Users\${BENUTZERNAME}\.arduinoIDE\plugins\
- MacOS:
~/.arduinoIDE/plugins/
- Linux :
~/.arduinoIDE/plugins/
Wie im Repository angemerkt, muss der Ordner unter Umständen erstellt werden, falls er noch nicht existiert. Das war auch bei mir der Fall. In den Ordner wird dann die .vsix
Datei kopiert. Anschließend sollte die Arduino IDE neugestartet werden um die Installation des Plugins abzuschließen.
Zum Kapitel springen Dateien hochladen
Mit geöffneter Arduino IDE kann man mit der Tastenkombination [Strg] + [Shift] + [P]
auf Windows und Linux bzw. [⌘] + [Shift] + [P]
auf MacOS das Command-Menü aufrufen. Dort sollte nun ein neuer Eintrag Upload LittleFS to Pico/ESP8266/ESP32
zu finden sein.
Wenn man diesen Befehl direkt ausführt, wird in der Konsole der Arduino IDE folgende Meldung ausgegeben:
LittleFS Filesystem Uploader
ERROR: No data folder found
Grund dafür ist die Art und Weise, wie die Dateien auf den ESP8266 geladen werden. Man muss im Ordner des Sketches einen neuen Ordner namens data
anlegen. Alle Dateien in diesem Ordner werden dann beim Ausführen des Befehls auf den ESP hochgeladen. Wenn der Ordner nicht vorhanden ist, können logischerweise keine Dateien hochgeladen werden.
Produktempfehlungen und -suche in Verbindung mit dem Amazon Partnerprogramm:
¹ Angaben ohne Gewähr. Bei einem Kauf über den Link erhalten wir eine Provision.
Sobald dieser Ordner erstellt wurde, kann der Upload des Ordners erneut ausgeführt werden.
Building LittleFS filesystem
[...]
Uploading LittleFS filesystem
[...]
Auto-detected Flash size: 4MB
Compressed 2072576 bytes to 2161...
Writing at 0x00200000... (100 %)
Wrote 2072576 bytes (2161 compressed) at 0x00200000 in 0.1 seconds (effective 269555.0 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
Completed upload.
Die hochgeladenen Dateien können genauso behandelt werden, wie bisher im Tutorial besprochen. Wenn man im Ordner data
nun eine Datei mit dem Namen meine.txt
erstellt und hochlädt, kann diese direkt vom ESP ausgelesen werden.
12:01:29.530 -> ESP gestartet
12:01:29.530 -> Dateisystem: initialisiert
12:01:29.530 -> Die Datei meine.txt wurde geöffnet!
12:01:29.530 -> Diese Datei wurde von meinem PC auf den ESP8266 hochgeladen! Nice!
Zum Kapitel springen Vorteile des LittleFS
Ein wesentlicher Nutzen des LittleFS liegt in der Fähigkeit, Konfigurationen dauerhaft zu speichern und dabei die Organisationsstruktur durch Verzeichnisse zu nutzen. Entweder sind diese bereits auf dem ESP abgelegt oder werden später über ein Webinterface oder eine ähnliche Schnittstelle geändert. Diese Konfigurationen bleiben auch nach Neustarts erhalten.
Ein weiterer Pluspunkt von LittleFS ist seine Robustheit und Effizienz im Vergleich zu SPIFFS. Die verbesserte Handhabung der Flash-Abnutzung und die Unterstützung von Metadaten für Dateien erweitern die Funktionalität erheblich und machen es ideal für Anwendungen, die eine höhere Datenintegrität erfordern.
Zum Kapitel springen Nachteile des LittleFS
Während LittleFS viele Vorteile bietet, nutzt es wie SPIFFS den Flash-Speicher des ESP8266, der für umfangreichere Daten geeignet ist, jedoch eine begrenzte Anzahl von Schreib- und Lesezyklen hat. Das kann ein Nachteil sein, besonders im Vergleich zum RTC-Speicher, der von dieser Einschränkung nicht betroffen ist.
Der Zugriff auf den Flash-Speicher kann energieintensiver sein als der Zugriff auf den EEPROM oder den RTC-Speicher, was in batteriebetriebenen Anwendungen ein Nachteil sein kann. LittleFS bietet zwar eine verbesserte Effizienz im Vergleich zu SPIFFS, aber die grundsätzlichen Herausforderungen des Flash-Speichers bleiben bestehen.
Abschließend lässt sich sagen, dass das LittleFS trotz einiger Nachteile im Vergleich zu Alternativen wie EEPROM und RTC-Speicher eine wertvolle Ressource darstellt. Die Fähigkeit ein einfaches Dateisystem direkt auf dem Flash-Speicher zu implementieren, bietet eine flexible und benutzerfreundliche Möglichkeit zur Datenspeicherung und -verwaltung. Dies ist besonders nützlich für Anwendungen die eine Vielzahl von Konfigurationsdaten benötigen, welche über das einfache Key-Value-Speichern hinausgehen.