ESP32 mit SPIFFS - eine Speicher Katastrophe

Ich nutze verschiedene ESP32 Kits für eine Art Datenlogger, der die Daten in das Flash per spiffs schreibt. Geht, aber mit sehr verschiedenem Ergebnis. Habe das dann genauer geprüft, und die Ergebnisse sind katastrophal. spiffs ist für diesen Zweck völlig unbrauchbar, wie ich gleich zeige.

Nun brauche ich eine Alternative. Wer kann helfen?

Mein Test bestand aus dem Schreiben von ca. 50 Byte, 1x pro Sekunde, per file open, write, flush, und close, stets als append in eine Datei. Die Gesamtdatei habe ich per wifi an meinen Desktop geschickt, und dort ausgewertet. Das Ergebnis sieht man im Attachment.

Die magenta-farbige Linie (linke Y-Achse) zeigt den Füllgrad des Flash in %. Die anderen Kurven zeigen Timings in milliseconds (rechte Y-Achse). Die hellbraune Kurve schwankt zwischen den minimalen und maximalen Dauern eines Speichervorgangs von den ca 50Byte. Bis zu einem Füllgrad von ~45% scheint alles in Ordnung, dann aber explodieren die Zeitdauern bis zu 2.5 Sekunden für 50Byte! Das haben die Römer schneller in ihre Marmorplatten gemeißelt :wink: .

Weiterhin sieht man, dass die Füllgrad Kurve abflacht, d.h. es wir gar nicht mehr gespeichert! Und in der Tat, auch 12h später ist nicht ein einzelnes zusätzliches Byte abgespeichert worden, und die ESP es jede Sekunde erneut probiert hatte. Es gab dabei nicht einmal eine Fehlermeldung von SPIFFS, das so tat, als sei gespeichert worden!

Spiffs kann hier also nur genutzt werden, solange der Füllstand kleiner als 64% ist. Dabei sind also noch 490 kilobyte frei, die nicht ausreichen, um einen einzigen 50Byte Record zu speichern?

Das rot-schwarze Gekrümel an der Nulllinie ist im unteren Bild vergrößert. Es zeigt die Dauer für das Einlesen von 100 Byte am Anfang (rote Linie) und am Ende (schwarze Linie) der Datei. Rot dauer nur wenige ms, Schwartz schwankt zwischen 50 ms und ~0ms in einem merkwürdigen Sägezahnmuster, und gelegentlichen Ausreißern bis <150ms.

Das Lesen wäre ja ok, aber das Schreiben - oder besser: Nicht-Schreiben! - macht spiffs völlig unbrauchbar.

Was wärte denn eine Alternative? Und wie installiert man die?

Der Sketch für diesen Test wäre noch interessant.
Wieviele Daten willst/musst Du denn speichern?
Davon abhängig sind die Alternativen. Z.B. SD, FRAM

Gruß Tommy

Der Sketch ist ein Riesenpaket, das ein bisschen gehackt wurde, um die Daten zu erzeugen.

Der Speicherbedarf ist mindestens 1 MB. Der auf dem Flash per default für spiffs reservierte Bereich ist 1374kB. Ich überlege aber auch die Nutzung von ESPs mit größerem Falsh.

Eine externe SD sollte möglichst vermieden werden. Die Datenrate wird dann 128 Byte 1x pro Minute sein. Das reicht dann für 5d Laufzeit pro 1MB.

Aber unzuverlässiges Speichern ist natürlich ein klares No-Go.

Hallo,

wenn ich es richtig verstanden habe: alle Sekunde ca. 50 Byte als Append ins SPIFFS?
Da spiele ich mal mit rum, einfach, weil ich das SPIFFS auch auf dem ESP32 gern benutze, allerdings bisher nicht in dieser Art. Allerdings ist bei den ESP32-Jungs da in letzter Zeit auch mehrmals intern umgebaut worden...

Gruß aus Berlin
Michael

Ich habe noch ein paar Tests gemacht, die das bisher gesagte bestätigen, und eher größere Probleme aufzeigen.

Da ich fürchte, dass dieser Test mich längere Zeit begleiten wird, habe ich den Sketch geschrumpft und hier auch angehängt. Dazu gleich mehr.

Ich habe 3 ESP32 Kits, WROOM, WROVER und PICO, und jetzt die beiden anderen getestet. Diesmal records von ca 250 byte Länge, und wieder jede Sek gespeichert. Im Ergebnis gerät wieder die Speicherzeit aus dem Ruder, und erreicht sogar 4sec (!) für einen ~250 byte record.

Und erneut fällt das Speichern komplett aus wenn der Füllstand ca 70% erreicht. Die Bilder enden nach einer Laufzeit von etwa 70min. Der Sketch lief aber noch eine gute Stunde weiter, in der aber nicht ein einziger Record gespeichert wurde, obwohl noch gut 400kilobyte Platz im Filessytem verfügbar waren!

SPIFFS meldete aber keinen Fehler!!!

Zu dem flashtestA Sketch: geschrumpft auf die für diesen Test nötigen Funktionen. Es braucht WiFi; dazu im flashtest2.ino die eigene ssid und passwort eintragen. Wenn es läuft wird im Serial Terminal angezeigt, welche IP es hat. Diese IP im Browser eingeben, und die Seite /log anklicken. Die Daten aus dem Browser Fenster können dann als *.csv Datei gespeichert und ausgewertet werden. Nur die ersten 7 Werte sind relevant (der Rest war nur um den Record größer zu machen).

Jedes Spreadsheet Programm sollte funktionieren; ich habe dazu mein GeigerLog Programm benutzt (Open Source, hier: GeigerLog download | SourceForge.net.

Im SerialTerminal können Kommandos zum Anzeigen, Löschen, etc gegeben werden, sieh Code am Ende von flashtest2.ino.

flashtestA.zip (8.26 KB)

 if (success) {msg += " with " + String(text.length()) + " bytes";} // write

Diese Zeile scheint mir logisch falsch zu sein.

Denn sie zeigt nur, wieviel Byte du schreiben willst/wolltest, nicht wieviel wirklich geschrieben wurden.

Dieses ist exakter(wenn ich mich nicht derbe irre)

 if (success) {msg += " with " + success + " bytes";} // write

Auch schreibst du in das FileHandle, ohne geprüft zu haben, ob es gültig/aufnahmebereit ist.

@combie: die Zeile ist so gewollt und auch logisch korrekt. SPIFFS behauptet ja, erfolgreich geschrieben zu haben, ergo sollte dies genaus so geschrieben sein.

Die Variable success is übrigens 'bool', damit ist Dein Vorschlag doch eher der Kategorie "derbe" zuzuordnen :wink:

Eines der Probleme von SPIFFS ist aber, dass es behauptet, etwas geschrieben zu haben, es aber doch nicht getan zu haben. Indirekt wird das über den Füllstand nachgewiesen, und das Abflachen der magenta Kurve zeigt genau dieses Problem!

Auch das filehandle wird geprüft, siehe FFat.open(logfile, FILE_APPEND); und Folgezeilen. Aber das hat nie einen Failure gegeben.

Die Hauptproblme von SPIFFS sind Unzuverlässigkeit und Schreibdauer.

Welch ein Unterschied ein Filesystem macht: anbei das gleiche Experiment mit einem FFat Filesystem. Jeweils ca 50 Byte anfangs alle 3 sec gespeichert, dann jede sec. Keine Speichervorgang brauchte mehr als 330ms. Ein Speichern bis zu 2x pro sec sollte möglich sein.

Das Speichern ging bis zu 100% Flash Füllstand!

Das Lesen von 100 bytes am Anfang (unteres Bild, rot) und am Ende (schwarz) war ebenfalls stets zuverlässig unter 3 bzw 4 ms.

Ebenso konnte ich im Upload über Wifi statt ca 80kB/s mit SPIFFS nunmehr mit FFAT stets >90kB/s erreichen.

Kleiner Wermutstropfen bei aller Begeisterung:

nachdem 100% Füllstand erreicht waren, schrieb der Sketch weiter, und zwar OHNE Fehlermeldung von ffat. Im Bild sieht man das nicht, weil ja nichjts mehr gespeichert wurde. Nun ja, das lässt sich abfangen.

Ein Weiteres : links im Bild sieht man ein Gap von ca 20 min. In dieser Zeit war die Speicherung korrumpiert, nur Gibberisch im Flash. Ein ffat Problem, oder mein Fehler (Formatierung?). Wird sich zeigen.

Ich hatte gehofft, von der Community zu erfahren, wie man LittleFS für die ESP 32 installiert. Kann niemand helfen?

Die Variable success is übrigens 'bool', damit ist Dein Vorschlag doch eher der Kategorie "derbe" zuzuordnen :wink:

Das darfst du tun!
Allerdings liefert .print() keinen Boolean, sondern die Anzahl geschriebener Byte.
Das kastrieren auf bool ist dein Werk.

und auch logisch korrekt.

Ja?

Auch das filehandle wird geprüft, siehe FFat.open(logfile, FILE_APPEND); und Folgezeilen. Aber das hat nie einen Failure gegeben.

Von FFat ist da nichts zu sehen.
Eine Illusion?

    // open file for append

ostart = micros();
    File    filehandle = SPIFFS.open(logfile, FILE_APPEND);
    ostop  = micros();

msg += " size:" + String(filehandle.size());
   
    // writing
    wstart = micros();
    bool success = filehandle.print(text);

Da schreibst du stumpf in das File, ohne vorher zu prüfen ob das öffnen überhaupt geklappt hat.
Und dann kastrierst du den Rückgabewert auch noch.

Welch ein Unterschied ein Filesystem macht:

Das stimmt!
SPIFFS unterstützt wear leveling.
(mit allen Vor- und Nachteilen.)

Die anderen auch?


Ach was solls...
Ich bin dann mal wech hier....

Du könntest ohne Overhead direkt mit der EEProm Library Lesen und Schreiben..

Ich benutze zum Lesen eine eigene Datenpartition mit Flash Maxspeed, schreiben müsste damit auch gehen.

Hier habe ich das mal so ungefähr dargestellt, man mapped über einen Transparent Layer eine Partition auf einen Pointer.

Allerdings liefert .print() keinen Boolean, sondern die Anzahl geschriebener Byte.
Das kastrieren auf bool ist dein Werk.

In der Tat eine sehr hilfreiche Info, danke! Die Kastration hatte ich aus irgendwelchen Beispielen übernommen.

Das Wear-Levelling hilft mir nichts, wenn SPIFFS gar nicht erst schreibt. FFat (im Code nur SPIFFS durch FFat ersetzen) schreibt wenigstens, und so weit ich bisher sah, zuverlässig. Und angeblich hat es ebenfalls wear-levelling.

Schuppeste:
Hier habe ich das mal so ungefähr dargestellt, man mapped über einen Transparent Layer eine Partition auf einen Pointer.
/166021-esp32-tutorial-partition-mapping[/url]

Verstehe erstmal Bahnhof. Meine EEPROM Partition ist doch auf 4k begrenzt, was zu klein ist, und nach meinem bisherigen Verständnis nicht erweiterbar.

Oder geht das doch?

ullix:
Oder geht das doch?

Jaein man kann die EEPROM.h einbinden, dann hat man die Funktionen für nativen SPI Zugriff und kann esp_partition_write und esp_partiton_read benutzen.

Nun ist LittleFS schließlich doch für Arduino verfügbar geworden (kann über den Lib Manager installiert werden). Meine Messungen, die ich oben für SPIFFS und FFAT bereits dargestellt habe, habe ich jetzt um LittleFS ergänzt. http://https://github.com/lorol/LITTLEFS

Genau wie FFat erlaubt LittleFS den ganzen Flash Speicher zu beschreiben, wohingegen für SPIFFS bei ~65% Füll-Level Schluss ist. Dabei bleibt die Schreibdauer für einen Record konstant niedrig, während sie bei SPIFFS auf 2.6 SEKUNDEN explodiert.

Die längsten Schreibdauern sind dabei bei LittleFS mit max 220ms sogar deutlich kürzer als bei FFat mit 330ms.

Wenn jetzt noch die behauptete "Power-loss resilience" ( https://github.com/ARMmbed/littlefs )zutrifft, sind alle Wünsche erfüllt!

@ullix: Danke für deine Übersicht.

In meiner Applikation möchte ich ein Log-File zu Servicezwecken einbinden.
Bis jetzt habe ich unter SPIFFS Geräte-HTML-Seiten abgelegt.

Frage: Ist ein Wechsel von spiffs auf LITTLEFS "problemlos" möglich? Hast du dazu Erfahrungen?

@westfreund: Also, “problemlos” ist wohl sogar noch eine übertrieben schwierige Bezeichnung. Einfach folgendes einsetzen:

  #define SPIFFS LITTLEFS
  #include <LITTLEFS.h>

und schon läuft es!

Ich hatte in meinem Datenlogger ja FFat eingesetzt, da SPIFFS völlig unbrauchbar ist, wie oben beschrieben. Von FFat ist der Umstieg schwieriger, aber wirklich nur ein klitzeklein bisschen!

Die “Power-loss resilience” habe ich jetzt auch mal geprüft. Ich hab mich wirklich angestrengt, aber es einfach nicht geschafft, ein “korruptes” File System zu erzeugen :o . Hier beschrieben: https://github.com/lorol/LITTLEFS/issues/5

Phänomenal!