ESP
DIYer
32
LAB

Moderní mikrokontrolér v rukou „bastlíře“

Kam (zase) se soubory? Aneb LittleFS…

V dnešním textu si ukážeme, jak lze v prostředí Arduino IDE nahrávat soubory do souborového systému LittleFS na modulu ESP32. LittleFS (Little File System) je malý, ale spolehlivý souborový systém navržený speciálně pro mikrokontrolery a jejich flash paměť. Možná již víme, že na modulu ESP32 lze část paměti flash využít jako úložiště – takový velmi malý „harddisk“ (spíše něco jako SD karta). Na modulech ESP32 se k ukládání souborů do interní flash paměti používají různé vestavěné (embedded) souborové systémy. Dva nejčastější jsou SPIFFS, kterému jsme se věnovali v článku Kam se soubory? Aneb SPIFFS v ESP32, a cíl našeho dnešního zájmu – systém LittleFS.

Ve výchozím nastavení oba tyto souborové systémy využívají přidělené místo přibližně 1,5 MB v integrované paměti flash (záleží však na zvoleném partition schématu, tj. rozdělení paměti). K čemu se to hodí? Může se to využít například pro uložení souborů přímo do paměti čipu (např. konfigurace, HTML stránky nebo logy).

SPIFFS je starší souborový systém navržený pro malé flash paměti v embedded zařízeních. Jeho nevýhodou je například horší výkon při zápisu a celkově menší robustnost. Tento systém se dnes spíše opouští a nahrazuje modernějším a spolehlivějším LittleFS, který je obecně doporučován pro nové projekty na ESP32. Jelikož jsme si o možném využití flash paměti jako úložiště poměrně podrobně říkali v článku o SPIFFS, dnes se zde zaměříme především na to, jak novější systém LittleFS na modulu ESP32 nastavit a jak do něj nahrát soubory. Článek pochopitelně doplníme jednoduchými ukázkami kódu, které ukáží základní práci s tímto souborovým systémem.

Souborový systém LittleFS

Jak jsme již v úvodu uvedli, LittleFS (Little File System) je moderní, spolehlivý souborový systém navržený pro mikrokontrolery a jejich flash paměť. Na rozdíl od staršího SPIFFS podporuje skutečné adresáře, je odolnější vůči poškození dat při výpadku napájení a podporuje lepší wear leveling, což znamená rovnoměrnější opotřebení flash paměti. Na ESP32 lze část interní flash paměti využít právě jako souborový systém. Ve výchozím nastavení při použití standardního partition schématu v Arduino IDE, je pro LittleFS rezervováno přibližně 1,5 MB. To je dostatek pro uložení konfigurací, HTML stránek pro webserver, logů nebo dalších drobných souborů.

Nastavení LittleFS v Arduino IDE

Nyní se podíváme, jak si LittleFS můžeme přidat do svého projektu na ESP32 a začít s ním pracovat. Pro práci se souborovým systémem využijeme knihovnu LittleFS, která poskytuje jednoduché a přehledné rozhraní pro čtení, zápis i správu souborů přímo v interní flash paměti mikrokontroleru. V Arduino IDE můžeme knihovnu nainstalovat z oficiálního správce knihoven nebo z GitHubu (viz dále). Pokud používáte Arduino IDE verze 2 a vyšší, není potřeba nic dalšího instalovat díky vestavěné podpoře LittleFS.

Pokud budeme používat doplněk ESP32 filesystem uploader, získáme možnost pohodlně nahrávat soubory do LittleFS – viz poslední část tohoto článku.

Po instalaci knihovny stačí ve svém programu připojit knihovnu LittleFS pomocí příkazu:

#include <LittleFS.h>

a inicializovat souborový systém LittleFS zavoláním funkce

LittleFS.begin();

Tím získáme okamžitý přístup k souborům uloženým v interní flash paměti a můžeme začít vytvářet aplikace, které ukládají konfigurace, webové stránky nebo logy přímo na čip.

První použití LittleFS

Ukážeme si jednoduchý příklad, který vypíše seznam souborů v LittleFS a ukáže, kolik místa zabírají. Program zatím pravděpodobně ukáže, že soubory nejsou přítomny, ale po jejich nahrání bude výpis hned zajímavější.

  1. Otevřeme Arduino IDE.
  2. Pokud používáme Arduino IDE verze 1, nainstalujme knihovnu z oficiálního správce knihoven nebo z GitHubu (LittleFS od autora lorol). V Arduino IDE verze 2 je již podpora implementována.
  3. V prostředí Arduino IDE vytvoříme následující program.

Tento program je ideální jako první test toho, zda je LittleFS na ESP32 funkční a kolik místa je k dispozici pro soubory.

#include <LittleFS.h>

void setup() {
   Serial.begin(115200);

   // Inicializace LittleFS
   if (!LittleFS.begin()) {
      Serial.println("Chyba při inicializaci LittleFS!");
      return;
   }

   Serial.println("LittleFS je připraven!");

   // Vypis informaci o velikosti a zaplneni LittleFS
   Serial.print("LittleFS celkem: ");
   Serial.print(LittleFS.totalBytes());
   Serial.print(" bytu, vyuzito: ");
   Serial.print(LittleFS.usedBytes());
   Serial.println(" bytu.");
}

void loop() {
   // Zatím nic
}

Program nejdříve inicializuje LittleFS a zkontroluje, zda se tato inicializace podařila.

if (!LittleFS.begin()) {
    Serial.println("Chyba při inicializaci LittleFS!");
    return;
}

Následně vypíše na sériový monitor informace o celkové kapacitě (metoda totalBytes()) a využitém prostoru v interní flash paměti ESP32 (metoda usedBytes()).

Z našeho pohledu jsou tedy zatím zajímavé příkazy knihovny LittleFS.
LittleFS.begin() – inicializuje souborový systém (vrátí true); pokud se to nepodaří, vrátí logickou hodnotu false.
LittleFS.totalBytes() – vrací celkovou kapacitu přidělenou LittleFS (hodnota je v bytech).
LittleFS.usedBytes() – vrátí, kolik paměti je aktuálně obsazeno soubory.

Test programu

Použijeme nový modul ESP32, nebo při překladu programu v menu Nástroje nastavíme volbu Erase All Flash Before Sketch Upload na hodnotu Enabled. Tím máme zaručeno, že v modulu neexistuje žádný souborový systém (ať již SPIFFS nebo LittleFS) nebo nahrané soubory z našich předchozích experimentů.

Program přeložíme, spustíme a podíváme se do seriového monitoru – viz obr. č. 1 (výstup v červeném rámečku).

Chyba při inicializaci

Obrázek č. 1 – Chyba při inicializaci LittleFS při prvním spuštění.

Náš „slavný“ program skončil chybou! Jak je to možné?

Pojďme se na to podívat podrobněji. Příkaz LittleFS.begin() se pokusil inicializovat souborový systém. ALE! Pokud souborový systém ještě není vytvořený (prázdná flash nebo nový modul), vrátí se hodnota false a program skončí chybovou hláškou. Na „čistém“ ESP32 program selže, protože FS ještě neexistuje.

Nyní zkusíme přidat do příkazu LittleFS.begin() parametr true. Získáme tedy:

if (!LittleFS.begin(true)) {
    Serial.println("Chyba při inicializaci LittleFS!");
    return;
}

Metoda begin(true) zkusí inicializovat souborový systém (FS) a pokud ještě není připravený, automaticky ho naformátuje. Na novém (prázdném) čipu se tím vytvoří funkční souborový systém a metoda begin poté vrátí hodnotu true.

Pojďme to vyzkoušet! Výsledek vidíme na obrázku č. 2 a to již je asi to, co bychom si přáli.

Uspěšná inicializace FS

Obrázek č. 2 – Úspěšná inicializace LittleFS při prvním spuštění.

Jak vidíme na obrázku č. 2, proces inicializace nyní proběhl v pořádku. FS je připraven a zároveň se vypisují údaje o vzniklém souborovém systému. Celková velikost je 1 441 792 bajtů a využito je již nyní 8192 bajtů.

Poznámka:
Hodnota 1 441 792 B = 352 bloků × 4096 B přesně odpovídá běžné LittleFS partition (~1.4 MB) používané v některých partition schématech Arduino core pro modul ESP32-WROOM-32. Zároveň vidíme, že i když souborový systém zatím neobsahuje žádné soubory, již pro své účely využívá 8192 bajtů (8192 B = 2 bloky × 4096 B). LittleFS na ESP32 funguje trochu jinak, než jsme možná zvyklí u klasického souborového systému FAT (souborový systém pro PC). Je navržen pro malé mikrokontroléry, a měl by mít určitou odolnost proti výpadku napájení, také pracuje s flash pamětí organizovanou do bloků. Proto i prázdný FS zabírá několik bloků, zde typicky:
Blok 1 – primární metadata
– Obsahuje superblock, informace o filesystemu, tabulku adresářů a souborů, aktuální stav bloků atd.
– V podstatě je to mapa FS a „pravidla hry“, jak zapisovat a číst data.
Blok 2 – záloha (redundance)
– LittleFS vždy udržuje kopii metadat, aby přežil náhlé vypnutí nebo reset během zápisu.
– Pokud by primární blok selhal nebo se poškodila data, FS může obnovit metadata ze záložního bloku.

Z předchozích řádků tedy plyne jasný praktický závěr: Na čistém ESP32 je bezpečnější použít LittleFS.begin(true). Díky parametru true se zaručí, že FS bude vytvořen a připraven k použití, i když je flash prázdná. A ještě je třeba dodat, že pokud FS již bude vytvořen a bude i obsahovat nějaké soubory, nic se formátovat nebude! Parametr true tedy neznamená bezpodmínečné formátování při každém novém spuštění.

Je pravda, že po prvním úspěšném spuštění už parametr true není nutný – FS je již vytvořen a LittleFS.begin() bez parametru bude fungovat, ale zde parametr true ponecháme pro jistotu.

Práce se soubory na LittleFS

Přestože asi čtenáři předešlého článku věnovanému souborovému systému SPIFFS budou následující řádky připadat dosti podobné, zkusíme si nyní ukázat, jak na LittleFS pracovat se soubory.

Zápis a čtení

Předešlý program rozšíříme o možnost uložení a načtení souboru. Abychom mohli opakovaně vypsat velikost zaplnění FS, což užijeme pro kontrolu obsazení jedním malým textovým souborem, vložíme si výpis obsazenosti do samostatné procedury nazvané printFSInfo().

void printFSInfo() {
    Serial.print("LittleFS celkem: ");
    Serial.print(LittleFS.totalBytes());
    Serial.print(" bytu, vyuzito: ");
    Serial.print(LittleFS.usedBytes());
    Serial.println(" bytu.");
}

Také jistě bude užitečná procedura, která nám vypíše obsah našeho „hardisku“. Tuto funkci nazveme listFS():

void listFS() {
    Serial.println("Obsah LittleFS:");

    File root = LittleFS.open("/");
    File file = root.openNextFile();

    while (file) {
        Serial.print(" ");
        Serial.print(file.name());
        Serial.print(" (");
        Serial.print(file.size());
        Serial.println(" B)");
        file = root.openNextFile();
    }
    Serial.println();
}

Na tuto funkci se podíváme podrobněji.

Pro načtení kořenového adresáře (složky) musíme dané místo otevřít. To uděláme tím, že pro toto místo vytvoříme objekt typu File, se kterým budeme nadále pracovat.

File root = LittleFS.open("/")

Metoda openNextFile() objektu root načte v daném umístění první soubor. Pokud se žádný soubor nenajde, je vrácena logická hodnota false, při úspěchu naopak true. Na to reaguje následující podmínka v cyklu, ve kterém jsou postupně načítány další soubory a v případě úspěchu vypisovány atributy objektu file – jméno (name()) a velikost (size()). Ale mohli bychom vypsat třeba i cestu souboru (path()), což je nejen název, ale i nadřazená adresářová struktura – zde zatím jen lomítko /.

while (file) {
    Serial.print(file.name());
    Serial.print(file.size());
    // Serial.print(file.path());

    file = root.openNextFile();
}

Ostatní procedury našeho programu budou následující:

  • Procedura saveFile() uloží jednoduchý textový soubor ahoj.txt, jehož obsah bude 'AHOJ'.
  • Procedura readFile() tento textový soubor ahoj.txt načte a obsah vypíše do okna seriového monitoru.

Princip obou těchto procedur bude asi při pohledu na jejich kód jasný. Nejdříve se ale zastavíme u příkazu otevření souboru (metoda open()). V obou případech je syntaxe podobná a v obou případech se vrací objekt typu File.

File f = LittleFS.open(path, mode);

kde prvním parametrem path je (absolutní) cesta k souboru, druhý (mode) je tzv. režim otevření.

pathcesta k souboru
Dokumentace uvádí, že LittleFS na ESP32 vyžaduje absolutní cestu souboru od rootu souborového systému. Nestačí tedy jen název souboru, ale musí být včetně lomítka na začátku, např. "/data.txt" nebo "/logs/log1.txt".
A důležité určitě je, že LittleFS rozlišuje velikost písmen, takže "/data.txt" a "/Data.txt" jsou zcela odlišné soubory!
moderežim otevření
Režim otevření určuje způsob, jak s daným souborem budeme pracovat – zda budeme číst, zapisovat se smazáním původního obsahu, přidávat do souboru za původní obsah apod.
Následující tabulka ukazuje přehled možných parametrů a jejich význam:
"r" Otevře soubor pro čtení.
"w" Otevře soubor pro zápis.
Pokud soubor neexistuje, vytvoří se.
Pokud soubor již existuje, smaže se jeho obsah.
"a" Otevře soubor pro přidávání na konec.
Pokud soubor neexistuje, vytvoří se.
Zápis probíhá vždy na konec souboru.
"r+" Otevře soubor pro čtení + zápis.
Soubor musí existovat.
Původní obsah se nesmaže.
"w+" Otevře soubor pro čtení + zápis.
Vytvoří soubor pokud neexistuje.
Vždy smaže obsah.
"a+" Otevře soubor pro čtení + zápis na konec.
Vytvoří soubor pokud neexistuje.
Čtení je možné odkudkoliv.
Zápis je možný vždy jen na konec.

Při otevření souboru je vždy třeba zkontrolovat, jestli se soubor otevřel:

File f = LittleFS.open("/data.txt", "r");
if (!f) {
    Serial.println("Nepodařilo se otevřít soubor");
}

Pro práci se souborem je možné použít několik základních metod – viz následující přehled těch základních:

read()
Přečte jeden byte souboru, tedy vrací hodnotu 0–255. Pokud není co číst, vrátí –1.
Příklad:
while (file.available()) {
    Serial.write(file.read());
}
readString()
Slouží k přečtení celého zbytku souboru jako textového řetězce (čte data od aktuální pozice v souboru).
readString() čeká na data maximálně 1000 ms (defaultně). Tento timeout lze změnit: file.setTimeout(200);
Příklad:
String text = file.readString();
Serial.println(text);
readStringUntil()
Slouží k přečtení části souboru dokud nenarazí na zadaný znak – např. konec řádky, středník apod.
Příklad:
while (file.available()) {   // čtení po řádkách
    String line = file.readStringUntil('\n');
    Serial.println(line);
}
readBytes()
Přečte více bajtů do bufferu. Přečte více bajtů najednou – ukládá je do bufferu. Vrací počet skutečně přečtených bajtů.
Příklad:
char buf[32];
file.readBytes(buf, sizeof(buf));
write()
Zapíše binární data. Zapisuje binární data, vrací počet zapsaných bajtů.
Příklad:
uint8_t data[4] = {'A','H','O','J'};   // Každý znak se automaticky převede na svůj ASCII kód.
file.write(data, 4);
print() / println()
Zapisuje textovou reprezentaci dat, umí: int, float, string, char. (println() navíc odřádkuje)
Příklad:
file.print(123);   // zapise 123
file.println("AHOJ");   // zapise AHOJ a odřádkuje
available()
Slouží pro zjištění, kolik bajtů je ještě možné přečíst ze souboru. (pro konec souboru (EOF) vrací 0, jinak číslo větší)
Příklad:
while (file.available()) {   // typické použití available()
Serial.write(file.read());
}
seek()
Nastaví pozici v souboru. Druhý parametr určuje, odkud se pozice počítá:
SeekSet – od začátku
SeekCur – od aktuální pozice
SeekEnd – od konce
Příklad:
file.seek(0, SeekSet);   // přejde na začátek souboru
position()
Vrátí aktuální pozici (aktuální offset v souboru)
Příklad:
Serial.println(file.position());
size()
Vrací velikost souboru v bajtech.
Příklad:
Serial.println(file.size());
close()
Zavře soubor, zapíše případné buffery do flash. Pokud soubor nezavřeme, může dojít ke ztrátě dat nebo poškození souboru při resetu.
close() je třeba používat i na konci čtení souboru!
Příklad:
while (file.available()) {
    Serial.write(file.read());
}
file.close();
Kód programu
#include <LittleFS.h>


// vypis statistik FS
void printFSInfo() {
   Serial.print("LittleFS celkem: ");
   Serial.print(LittleFS.totalBytes());
   Serial.print(" bytu, vyuzito: ");
   Serial.print(LittleFS.usedBytes());
   Serial.println(" bytu.");
}

// vypis obsahu FS
void listFS() {
   Serial.println("Obsah LittleFS:");

   File root = LittleFS.open("/");
   File file = root.openNextFile();

   while (file) {
      Serial.print("  ");
      Serial.print(file.name());
      Serial.print(" (");
      Serial.print(file.size());
      Serial.println(" B)");
      file = root.openNextFile();
   }
   Serial.println();
}

// ulozeni souboru
void saveFile() {
   Serial.println("Ukladam soubor /ahoj.txt");

   File f = LittleFS.open("/ahoj.txt", "w");
   if (!f) {
      Serial.println("Chyba pri otevreni souboru pro zapis");
      return;
   }

   f.print("AHOJ");
   f.close();

   Serial.println("Soubor ulozen");
}

// nacteni souboru
void readFile() {
   Serial.println("Nacitam soubor /ahoj.txt");

   File f = LittleFS.open("/ahoj.txt", "r");
   if (!f) {
      Serial.println("Soubor se nepodarilo otevrit");
      return;
   }

   String obsah = f.readString();
   Serial.print("Obsah souboru: ");
   Serial.println(obsah);

   f.close();
}

void setup() {
   Serial.begin(115200);

   // inicializace FS
   if (!LittleFS.begin(true)) {
      Serial.println("Chyba pri inicializaci LittleFS!");
      return;
   }

   Serial.println("LittleFS je pripraven!");
   printFSInfo();
   Serial.println();

   // vypis puvodniho obsahu
   listFS();

   // ulozeni souboru
   saveFile();

   // nacteni souboru
   readFile();

   // novy vypis obsahu
   listFS();

   // znovu statistika FS
   Serial.println("\nStatistika FS po ulozeni:");
   printFSInfo();
}

void loop() {
   // Zatím nic
}

Poznámka:
Nepřehlédněme, a už jsme to zmiňovali, že cesta souboru při zápisu a čtení musí obsahovat počáteční lomítko! V LittleFS cesta souboru musí být absolutní, tedy začínat /. LittleFS nezná pojem aktuálního pracovního adresáře!
Funkce jako open(), remove() nebo rename() vždy očekávají absolutní cestu.

Pojďme se podívat, jak program proběhl, jaký je jeho výstup (viz obr. 3) a asi si popíšeme i některé v něm použité příkazy.

zápis a čtení souboru

Obrázek č. 3 – Zápis a načtení souboru v souborovém systému LittleFS.

Na obrázku č. 3 vidíme postupný průběh programu. Nejdříve se inicializuje FS a poté se zobrazí velikost jeho obsazenosti. Následuje výpis souborů. Protože je při prvním (!) spuštění FS prázdný, nevypsalo se nic. Další je zápis souboru ahoj.txt a jeho načtení. Pokračujeme výpisem obsahu FS, na kterém vidíme, že nyní obsahuje soubor ahoj.txt, který má velikost 4 B. Na samotný závěr je opět vypsána obsazenost FS – za zmínku stojí velikost volného místa – je stejná, jako když tam žádný soubor nebyl!

Proč se číslo nezmění po vytvoření souboru ahoj.txt?

Odpověď spočívá v tom, že LittleFS neukládá data po jednotlivých bajtech, ale po blocích. Pokud má souborový systém ještě volný prostor v již alokovaném bloku, uloží se soubor tam a usedBytes() se nezmění. Jinými slovy: Soubor je malý a vejde se do volného místa v již alokovaném bloku. Malé soubory tedy prakticky nezvýší usedBytes(), pochopitelně dokud se nevyčerpá aktuálně alokovaný blok.

Jak ověřit že se FS opravdu mění?

Pojďme vytvořit větší soubor, například 10 kB. Do sekce setup před poslední výpis souborů v FS (listFS()) přidáme následující řádky:

File f = LittleFS.open("/test.txt", "w");
for(int i = 0; i < 10000; i++){
    f.print("A");
}
f.close();

Následující obrázek č. 4 znázorňuje výstup v seriovém monitoru po spuštění takto upraveného programu.

uložení většiho souboru

Obrázek č. 4 – Zápis většího souboru a následný výpis obsazenosti FS.

Jak je to nyní s obsazeností paměti? Přidání souboru test.txt (10 000 B) spotřebuje 3 bloky (10 000 B / 4096 B ≈ 2,44 → zaokrouhleno na 3 bloky). Celková obsazenost je tedy 5 bloků × 4096 B = 20 480 B (2 původní bloky + 3 nové bloky).

Poznámka:
Možná jste si při svých experimentech s LittleFS všimli, že již při prvním spuštění mohou být v modulu ESP32 nahrané soubory ahoj.txt a případně test.txt.
Důvodem je to, že ve skutečnosti Vaše „první“ spuštění není již první. K prvnímu spuštění (a tedy i k zápisu obou souborů) došlo hned po nahrání programu do modulu ESP32. Což se ale nedozvíte, protože Arduino IDE v tu chvíli zobrazuje okno výstupu, kde se vypisují informace o překladu a nahrání programu. Takže se v sériovém monitoru nic nezobrazí – není připojen k sériovému portu modulu ESP32.
Při následném Vašem stisknutí tlačítka RESET již běží program podruhé a to již jsou soubory v modulu ESP32 uloženy.

V další části našeho popisu práce se soubory na LittleFS si ukážeme, jak soubor přejmenovat a smazat.

Přejmenování a smazání

Využijeme toho, že nyní máme v modulu ESP32 soubor ahoj.txt, zkusíme jej nejdříve přejmenovat, pak definitivně smazat. Abychom se vyvarovali situaci s „nechtěným prvním“ spuštěním (viz červený rámeček výše), soubor ahoj.txt si v rámci programu na začátku vždy vytvoříme.

V programu použijeme metody:

rename()
Tato metoda má dva parametry – první je původní název (včetně cesty), druhý je nový název (opět včetně cesty) na který bude soubor přejmenován.
remove()
Parametr této metody udává cestu k souboru, který má být smazán

Obě metody vrací logickou hodnotu, která potvrzuje úspěšnost/neúspěšnost provedení.

Kód programu
#include <LittleFS.h>

// vypis obsahu FS
void listFS() {
   Serial.println("Obsah LittleFS:");
   File root = LittleFS.open("/");
   File file = root.openNextFile();
   while (file) {
      Serial.print("  ");
      Serial.print(file.name());
      Serial.print(" (");
      Serial.print(file.size());
      Serial.println(" B)");
      file = root.openNextFile();
   }
   Serial.println();
}

void setup() {
   Serial.begin(115200);

   // inicializace FS
   if (!LittleFS.begin(true)) {
      Serial.println("Chyba pri inicializaci LittleFS!");
      return;
   }
   Serial.println("LittleFS pripraven!");

   // vytvoreni souboru
   File f = LittleFS.open("/ahoj.txt", "w");
   if (f) {
      f.print("AHOJ");
      f.close();
      Serial.println("Soubor /soubor.txt ulozen");
   }

   listFS();

   // prejmenovani souboru
   if (LittleFS.rename("/ahoj.txt", "/novy_soubor.txt")) {
      Serial.println("Soubor prejmenovan na /novy_soubor.txt");
   } else {
      Serial.println("Chyba pri premenovani");
   }

   listFS();

   // smazani souboru
   if (LittleFS.remove("/novy_soubor.txt")) {
      Serial.println("Soubor /novy_soubor.txt smazan");
   } else {
      Serial.println("Chyba pri mazani");
   }

   listFS();
}

void loop() {
    // nic
}

Výstup programu vidíme na obrázku č. 5. Prvním krokem je vytvoření souboru ahoj.txt. Druhým krokem je přejmenování tohoto souboru na název novy_soubor.txt, který je ve třetím kroku následně odstraněn. O úspěšném smazání souboru nás utvrzuje výpis všech souborů v kořenovém adresáři. A jak na obrázku vidíme, souborový systém je prázdný a všechno je vymazáno.

přejenování a smazání souboru

Obrázek č. 5 – Zápis většího souboru a následný výpis obsazenosti FS.

Složky

LittleFS na ESP32 podporuje složky (adresáře), ale trochu jinak než klasické souborové systémy. Složky v LittleFS se chovají trochu jinak než u klasického souborového systému, který známe třeba z běžného počítače. Kupříkladu se nelze „přepínat“ do nějaké pracovní složky a v ní pak pracovat pomocí relativní cesty. Složky zde jsou reprezentovány předponou (absolutní) cesty /adresar/ v názvu souboru a vždy se pracuje s absolutní cestou.

Upozornění:
V některých tutoriálech se píše, že LittleFS nevyžaduje explicitní vytvoření složky, a že složka vzniká, jakmile se vytvoří soubor s danou předponou – např. vytvoření souboru /mp3/song.txt má automaticky vytvořit složku mp3.
Osobně s tímto moc nesouhlasíme!
Při našich zkouškách na našem modulu ESP32 bylo třeba jakoukoliv složku (např. mp3) nejdříve založit příkazem mkdir(), pak teprve do ní uložit soubor.
Je možné, že se jedná o nějakou starší informaci a v novější verzi LittleFS se už explicitní zakládání složek vyžaduje. Tohle opravdu nevíme.

Následující program má za úkol vytvořit složku mp3, do ní uložit soubor song.txt (tedy vytvořit /mp3/song.txt). Následně se pokusíme složku a soubor smazat. Program nám ukáže, že smazat složku lze jen, pokud je prázdná (tj. neobsahuje žádný soubor nebo podadresář). Pokud se pokusíme smazat složku mp3 obsahující soubor song.txt dojde k chybě. Následně tedy smažeme nejdříve soubor song.txt, pak prázdnou složku mp3. To již proběhne úspěšně.

Kód programu
#include <LittleFS.h>

// vypis obsahu FS
void listFS(const char *dirname="/") {
   Serial.printf("Vypis slozky: %s\r\n", dirname);
   File root = LittleFS.open(dirname);
   if (!root) {
      Serial.println("- slozku nelze otevrit"); return;
   }
   if (!root.isDirectory()) {
      Serial.println("- neni to slozka");
      return;
   }
   File file = root.openNextFile();
   while (file) {
      if (file.isDirectory()) {
         Serial.print("Slozka: ");
         Serial.println(file.name());
         listFS(file.path());
      } else {
         Serial.print(" Soubor: ");
         // Serial.print(file.name());
         Serial.print(file.path());
         Serial.print("\t(");
         Serial.print(file.size());
         Serial.println(" B)");
      }
      file.close();
      file = root.openNextFile();
   }
 }

void setup() {
   Serial.begin(115200);
   delay(1000);

   if (!LittleFS.begin(true)){
      Serial.println("Chyba pri inicializaci LittleFS!");
      return;
   }
   Serial.println("LittleFS pripraven!");

   if(LittleFS.mkdir("/mp3")) {
      Serial.println("Slozka /mp3 vytvorena");
   }
   // Vytvoření souboru ve složce
   File file = LittleFS.open("/mp3/song.txt", "w");
   if (file){
      file.print("AHOJ ve slozce!");
      file.close();
      Serial.println("Soubor /mp3/song.txt ulozen");
   } else {
      Serial.println("CHYBA: Nelze otevrit soubor song.txt!");
   }

   // výpis FS
   listFS();

   // pokus o smazání složky přímo – selže, protože obsahuje soubor
   if (LittleFS.remove("/mp3")) {
      Serial.println("Slozka smazana");
   } else {
      Serial.println("Slozku nelze smazat, neni prazdna");
   }

   // smazání souboru
   if (LittleFS.remove("/mp3/song.txt")) {
      Serial.println("Soubor /mp3/song.txt smazan");
   }

   // prubezny výpis FS
   listFS();

   // smazání složky (nyní prázdné)
   if (LittleFS.rmdir("/mp3")) {
      Serial.println("Slozka /mp3 smazana");
   } else {
      Serial.println("Slozku se nepodarilo smazat");
   }

   // konečný výpis FS
   listFS();
}

void loop() {
   // nic
}

Ještě než se podíváme, jak vypadá výstup programu, je třeba upozornit na zcela přepracovanou funkci listFS(), která se nyní „vnořuje“ do složek a vypisuje v nich obsažené soubory. Možná by se dalo očekávat, že stačí normálně vypsat všechny soubory v kořenovém adresáři a některé zkrátka budou mít název „delší“ o předponu složek, do kterých jsou vloženy. Tak to ale nefunguje. Soubor /mp3/song.txt existuje, ale nevypisuje při „plochém“ původním výpisu kořenové složky (rootu). Musíme použít rekurzivní procházení složek podle prefixu (předpony).

Při výpisu souborů uvnitř složky se musíme dotázat na soubory s danou předponou – tak trochu jako bychom se „přepnuli“ do složky. No…, když jsme říkali, že se nelze „přepínat“ do složek, tak to nyní trochu popíráme, že? Ono se nyní tak trochu budeme do složek „přepínat“. A to tak, že jakmile ve výpisu narazíme na složku, necháme vypsat její obsah pomocí té samé funkce listFS() – je s předponou názvu této složky:

File root = LittleFS.open(dirname);

Tím se vlastně „přepneme“ do dané složky, neboť se bude pracovat jen se soubory dané předpony (dané složky). Zní to zmateně? Pojďme se na funkci podívat podrobněji:

// vypis obsahu FS
void listFS(const char *dirname="/") {
    Serial.printf("Vypis slozky: %s\r\n", dirname);
    File root = LittleFS.open(dirname);
    if (!root) {
        Serial.println("- slozku nelze otevrit"); return;
    }
    if (!root.isDirectory()) {
        Serial.println("- neni to slozka");
        return;
    }
    File file = root.openNextFile();
    while (file) {
        if (file.isDirectory()) {
            Serial.print("Slozka: ");
            Serial.println(file.name());
            listFS(file.path());
        } else {
            Serial.print(" Soubor: ");
            // Serial.print(file.name());
            Serial.print(file.path());
            Serial.print("\t(");
            Serial.print(file.size());
            Serial.println(" B)");
        }
        file.close();
        file = root.openNextFile();
    }
}

Vstupní parametr je název složky – výchozí hodnota je /, tedy kořenový adresář. Příkazem File root = LittleFS.open(dirname); se zvolí vybírání všech souborů, které jsou v této složce (to je to naše „přepnutí“ do složky).

Následuje kontrola možnosti otevření zvolené složky, včetně toho, zda to vůbec složka je. To jsou běžné testy, aby byla procedura trochu robustní (tzv. idiotensicher 😉)

V následném cyklu jsou načítány položky obsažené ve zvolené složce. Pokud se narazí na složku, je opět otevřena funkcí listFS() – programátorská technika tzv. rekurze. Pokud daná položka není složka, jde o soubor a je pomocí funkce file.path() vypsána jeho cesta (tj. jméno včetně prefixu nadřazených složek). Pokud bychom chtěli jen čistý název, mohli bychom použít funkci file.name() (v programu je tato možnost zakomentována). Po průchodu všech položek dané složky se funkce ukončí (dochází k postupnému „vynořování“ rekurze ze systému složek).

Nyní se vrátíme k celému programu a jeho výstupu. Na obrázku č. 6 vidíme výstup v sériovém monitoru prostředí Arduino IDE.

práce se složkami

Obrázek č. 6 – Práce se složkami v LittleFS na modulu ESP32.

Na začátku dojde k inicializaci LittleFS a následuje vytvoření složky mp3 pomocí funkce mkdir("/mp3"). Následně je do vytvořené složky mp3 uložen soubor song.txt. Všimněme si, jak je soubor otevřen pomocí zadání celé (absolutní) cesty.

File file = LittleFS.open("/mp3/song.txt", "w");
if (file){
    file.print("AHOJ ve slozce!");
    file.close();
    Serial.println("Soubor /mp3/song.txt ulozen");
} else {
    Serial.println("CHYBA: Nelze otevrit soubor song.txt!");
}

Úspěšné provedení této části ilustruje blok 1 (na obrázku č. 6), který je zakončen výpisem uložených souborů (zde složka mp3 v rootu / a ve složce mp3 soubor song.txt o velikosti 15 bajtů).

Následuje blok 2, ve kterém se pokusíme smazat složku mp3:

if (LittleFS.remove("/mp3")) {
    Serial.println("Slozka smazana");
} else {
    Serial.println("Slozku nelze smazat, neni prazdna");
}

Je třeba si pamatovat, že LittleFS nepodporuje rekurzivní mazání složek. Takže pokud chceme smazat neprázdnou složku, musíme nejprve smazat soubory uvnitř složky. Výše uvedený pokus o smazání tedy selže (složka není prázdná – obsahuje soubor song.txt).

Takže se v programu musí přejít k smazání souboru song.txt:

if (LittleFS.remove("/mp3/song.txt")){
    Serial.println("Soubor /mp3/song.txt smazan");
}

Blok 2 končí výpisem obsahu LittleFS, na kterém vidíme, že je zde již jen složka mp3, která je prázdná.

Jakmile je složka mp3 prázdná, můžeme přejít k jejímu smazání (blok 3):

if (LittleFS.rmdir("/mp3")){
    Serial.println("Slozka /mp3 smazana");
} else {
    Serial.println("Slozku se nepodarilo smazat");
}

Opětovný výpis souborů funkcí listFS() nyní ukazuje, že došlo ke smazání i složky mp3.

💡 A máme zde test pro pozorné čtenáře! 😉

Zdalipak si někdo všiml, že jsme se v programu pokusili smazat složku mp3 dvěma rozdílnými způsoby?

  • V prvním případě šlo o metodu remove("/mp3").
  • V druhém případě jsme použili metodu rmdir("/mp3").

Nemůže případný (ne)úspěch při mazání složky mp3 souviset i s tímto?
Ne! V rámci dobrovolného domácího úkolu zkuste obě části prohodit – výsledek bude stejný.

Tak co tedy použít – remove() nebo rmdir()?

remove()
Používá se především na soubory. Pokud zadáme cestu k souboru, odstraní soubor. Pokud zadáme cestu k složce, tak složku smaže (pokud je složka úplně prázdná).
Shrnutí: remove() = smaže soubor nebo prázdnou složku.
rmdir()
Používá se speciálně na složky. Odstraní prázdnou složku.
Shrnutí: rmdir() = vyloženě pro mazání složek (ale musí být složka prázdná).

Technicky vzato remove() je univerzální, ale většina lidí používá rmdir() pro složky, protože dává jasnou sémantiku: „Mažu adresář, ne soubor.“

Kopírování/přesun souboru

Na samý konec ukázek práce se soubory v souborovém systému LittteFS jsme si nechali kopírování. Přiznám se, že bych u tak vyspělého souborového systému očekával, že zde kromě výše uvedených metod bude i metoda pro kopírování.

A hle… ona není! 😒

Ukážeme si tedy, jak takovou funkci vytvořit „svépomocí“.

Kopírování souboru

Začneme základním kódem:

File src = LittleFS.open("/mp3/song.txt", "r");
File dst = LittleFS.open("/song.txt", "w");
if (src && dst) {
    while(src.available()) {
        dst.write(src.read());
    }
    Serial.println("Soubor zkopirovan do /song.txt");
} else {
    Serial.println("CHYBA: Kopirovani souboru selhalo");
}
src.close();
dst.close();

Program otevře dva soubory – první (src) je zdrojový soubor otevřený pro čtení, druhý (dst) je cílový soubor otevřený pro zápis. Po kontrole, zda oba soubory byly otevřeny úspěšně, program čte obsah zdrojového souboru bajt po bajtu a zapisuje jej do cílového souboru. Na konci se oba soubory zavřou.

Nyní zkusíme výše uvedený kód trochu optimalizovat. Je jasné, že čtení a zápis bajt po bajtu není příliš efektivní a u větších souborů může výrazně zatížit mikrokontrolér. Ve výše uvedeném přehledu základních metod byla zmíněna i metoda readBytes(), která dokáže načítat více bajtů najednou do bufferu. Stejně tak metoda write() zvládne zapsat celý buffer najednou.

Následující kód obsahuje malou optimalizační vychytávku (doporučenou pro ESP32), která využívá rychlejší kopírování po blocích místo po jednotlivých bajtech:

File src = LittleFS.open("/mp3/song.txt", "r");
File dst = LittleFS.open("/song.txt", "w");
if (src && dst){
    uint8_t buffer[64];   // buffer po blocích
    while(src.available()){
        int len = src.readBytes((char*)buffer, sizeof(buffer));
        dst.write(buffer, len);
    }
    Serial.println("Soubor zkopirovan");
}
src.close();
dst.close();

Výše uvedené kódy jednorázově zkopírují soubor /mp3/song.txt do kořenového adresáře /song.txt. Pro obecnější použití je lepší vytvořit kopírovací funkci, do které se zadá zdrojový soubor a cesta k jeho budoucí kopii.

Následující kód ukazuje takovou funkci – nejde o samostatný spustitelný program, pouze o definici funkce:

Funkce copyFile():

bool copyFile(const char* srcPath, const char* dstPath) {
   const size_t bufferSize = 256;   // pevný buffer

   File src = LittleFS.open(srcPath, "r");
   if (!src) {
      Serial.printf("CHYBA: Nepodarilo se otevrit zdrojovy soubor %s\n", srcPath);
      return false;
   }

   File dst = LittleFS.open(dstPath, "w");
   if (!dst) {
      Serial.printf("CHYBA: Nepodarilo se otevrit cilovy soubor %s\n", dstPath);
      src.close();
      return false;
   }

   uint8_t buffer[bufferSize];
   while(src.available()) {
      int len = src.readBytes((char*)buffer, bufferSize);
      dst.write(buffer, len);
   }

   Serial.printf("Soubor %s zkopirovan do %s\n", srcPath, dstPath);

   src.close();
   dst.close();
   return true;
}

Použití této funkce v programu může vypadat například takto:

copyFile("/mp3/song.txt", "/song.txt");

Přesun souboru

Možná někoho nyní napadlo, že přesun souboru je jen pouhé doplnění naší kopírovací funkce o závěrečné smazání původního souboru. To by sice fungovalo, bylo by to ale neefektivní – a určitě to jde lépe!

Když si uvědomíme, že data souboru jsou uložena napevno ve flash paměti a že souborový systém vlastně zajišťuje jakousi „hru“ na soubory a složky, lze soubor přesunout, aniž bychom přesunuli jediný jeho bajt. Stačí totiž souborovému systému říci, že data v paměti nebudou přístupná na původní cestě, ale na cestě nové. Jinými slovy – stačí soubor přejmenovat! Přesněji řečeno, nezměníme jeho jméno, ale cestu, na které jej má souborový systém prezentovat.

Pojďme si to ukázat na konkrétním příkladu. Co udělá následující příkaz?

LittleFS.rename("/mp3/song.txt", "/song.txt");

Soubor song.txt, který byl na absolutní cestě /mp3/song.txt (čili ve složce mp3), se přejmenuje na /song.txt. To je stejný soubor, ale nyní v kořenovém adresáři. Takže soubor se – aniž by se pohnul jediný jeho bajt – přesunul ze složky mp3 do kořenové složky /.

Myslím, že jsme se práci se soubory v souborovém systému LittleFS věnovali už dost. Je skvělé, že nyní dokážeme soubory vytvářet, číst, mazat, kopírovat nebo přesouvat, ale určitě bychom je rádi do souborového systému nahráli i zvenčí – například soubory HTML nebo obrázky pro jednoduchý webový server.

Dále se tedy podíváme, jak do LittleFS nahrát soubory pomocí prostředí Arduino IDE.


Doplněk LittleFS Uploader

Doplněk LittleFS Uploader je nástroj pro Arduino IDE, který umožňuje snadno nahrávat soubory do souborového systému LittleFS na modulech ESP32. Díky němu můžeme do flash paměti mikrokontroléru přenést například HTML, CSS, JavaScript nebo obrázky pro webový server běžící na ESP32, aniž bychom museli soubory zapisovat přímo z programu. Doplněk zajišťuje rychlý a spolehlivý přenos dat, vytvoří image souborového systému LittleFS a nahraje jej do vyhrazené oblasti flash paměti, což výrazně zjednodušuje vývoj a testování projektů využívajících LittleFS.

Instalace LittleFS Uploader

Pro nahrávání souborů do ESP32 v prostředí Arduino IDE (verze 2) lze použít plugin LittleFS Uploader. Plugin je možné využít nejen s deskami ESP32, ale také s moduly ESP8266 nebo Raspberry Pi Pico.

Následující postup popisuje instalaci pluginu do prostředí Arduino IDE běžícího v operačním systému Microsoft Windows.

  1. Z repozitáře GitHub doplňku Arduino-LittleFS-Upload autora Earle F. Philhower III stáhneme aktuální verzi pluginu (soubor s příponou .vsix – viz obr. 7).
Stažení pluginu LittleFS Uploader

Obrázek č. 7 – Stažení aktuální verze pluginu LittleFS Uploader.

  1. V počítači přejdeme do složky:
    C:\Users\uživatelské_jméno\.arduinoIDE\, kde uživatelské_jméno je uživatelské jméno, kterým se přihlašujeme do Windows.
  2. Pokud se v tomto umístění ještě nenachází složka plugins, vytvoříme ji (viz obr. 8).
Vytvoření složky plugins pro LittleFS Uploader

Obrázek č. 8 – Vytvoření složky plugins pro LittleFS Uploader.

  1. Do složky plugins zkopírujeme stažený soubor s příponou .vsix. Pokud se ve složce již nachází starší verze pluginu LittleFS Uploader, je nutné ji odstranit – ve složce by měl být pouze jeden soubor tohoto pluginu (viz obr. 9).
Soubor pluginu ve složce plugins

Obrázek č. 9 – soubor pluginu LittleFS Uploader ve složce plugins.

  1. Restartujeme nebo otevřeme prostředí Arduino IDE (verze 2). Plugin by měl být úspěšně nainstalován.

Test úspěšné instalace LittleFS Uploader

Po spuštění prostředí Arduino IDE (verze 2) na první pohled nepoznáme, zda byl plugin LittleFS Uploader úspěšně nainstalován. Funkčnost pluginu proto musíme ověřit.

Po spuštění Arduino IDE současně stiskneme klávesy  Ctrl  +  Shift  +  P . Tím otevřeme okno příkazů (Command Palette).

Pomocí posouvání seznamu nebo vepsáním začátku hledaného výrazu do vyhledávacího pole vyhledáme položku:

Upload LittleFS to Pico/ESP8266/ESP32

Pokud se tato položka v seznamu zobrazí, je plugin správně nainstalován.

test instalace pluginu

Obrázek č. 10 – Test úspěšné instalace pluginu LittleFS Uploader.

Nahrání souborů do modulu ESP32 pomocí LittleFS Uploader

Chceme-li nahrát soubory do souborového systému LittleFS na modulu ESP32, postupujeme podle následujících kroků. Jako ukázku nahrajeme na modul textový soubor AHOJ.txt.

  1. Otevřeme prostředí Arduino IDE a vytvoříme nový projekt (prázdnou skicu).
  2. Skicu uložíme, aby se vytvořila pracovní složka projektu.
  3. Vzniklou složku projektu otevřeme pomocí nabídky: (viz obr. 11)
    ProjektZobrazit složku projektu.
Otevření složky projektu

Obrázek č. 11 – Otevření složky projektu.

  1. V pracovní složce projektu vytvoříme podsložku s názvem: data (viz obr. 12).
Poznámka:
Plugin očekává složku: data (malými písmeny). Velké písmeno Data většinou funguje ve Windows, ale na Linuxu nebo macOS by to nemuselo fungovat. Dokumentace Arduino zkrátka používá data, tak tedy data.
Otevření složky projektu

Obrázek č. 12 – Vytvoření složky data ve složce projektu

  1. Do složky data zkopírujeme soubor, který chceme nahrát do modulu ESP32, nebo jej zde vytvoříme. Pro demonstrační účely vytvoříme textový soubor AHOJ.txt (viz obr. 13).
vytvoření TXT souboru ve složce projektu

Obrázek č. 13 – vytvoření TXT souboru ve složce data složky projektu

  1. Obsah souboru AHOJ.txt vytvoříme například pomocí programu Notepad (Poznámkový blok) – viz obr. 14.
vytvoření obsahu TXT souboru ve složce projektu

Obrázek č. 14 – Vytvoření obsahu souboru AHOJ.txt pomocí Poznámkového bloku.

  1. Vrátíme se do prostředí Arduino IDE, kde vybereme správný typ připojeného modulu ESP32 a odpovídající COM port, ke kterému je modul připojen (viz obr. 15).
vyber-modulu

Obrázek č. 15 – Výběr modulu ESP32 a COM portu pro přenos dat do flash paměti.

  1. Stiskneme klávesy  Ctrl  +  Shift  +  P , čímž otevřeme okno příkazů. V seznamu vybereme příkaz:
    Upload LittleFS to Pico/ESP8266/ESP32 (viz obr. 16)
upload dat do ESP32

Obrázek č. 16 – Upload souborů ze složky data do modulu ESP32.

Důležité:
Při nahrávání souborů do souborového systému ESP32 musí být zavřené okno monitoru sériového portu (Serial Monitor). Pokud je otevřené, nahrávání souborů selže!
  1. Po spuštění příkazu vyčkáme několik sekund, než dojde k nahrání dat (souboru AHOJ.txt) do modulu ESP32. Po úspěšném dokončení operace se zobrazí zpráva: ⓘ LittleFS upload completed! Soubory byly úspěšně nahrány do souborového systému modulu ESP32. (viz obr. 17).
upload dat do ESP32 - dokončení

Obrázek č. 17 – Soubory byly úspěšně nahrány do souborového systému ESP32.

Ověření nahrání souborů do modulu ESP32

Nyní ověříme, zda bylo nahrání souborů úspěšné. Nahrajeme proto do modulu ESP32 jednoduchý program, který vypíše obsah souborového systému ve flash paměti. Můžeme upravit některý z programů uvedených na začátku článku – postačí výpis souborů bez rekurzivního procházení složek.

Následující program vypíše základní informace o souborovém systému LittleFS a seznam souborů, které obsahuje. Kód zkopírujeme do prostředí Arduino IDE, přeložíme a nahrajeme do modulu ESP32.

Vypsání souborů v LittleFS:
#include <LittleFS.h>

// vypis statistik FS
void printFSInfo() {
   Serial.print("LittleFS celkem: ");
   Serial.print(LittleFS.totalBytes());
   Serial.print(" bytu, vyuzito: ");
   Serial.print(LittleFS.usedBytes());
   Serial.println(" bytu.");
}

// vypis obsahu FS
void listFS() {
   Serial.println("Obsah LittleFS:");
   File root = LittleFS.open("/");
   File file = root.openNextFile();
   while (file) {
      Serial.print(" ");
      Serial.print(file.name());
      Serial.print(" (");
      Serial.print(file.size());
      Serial.println(" B)");
      file = root.openNextFile();
   }
   Serial.println();
}

void setup() {
   Serial.begin(115200);
   // inicializace FS
   if (!LittleFS.begin()) {
      Serial.println("Chyba pri inicializaci LittleFS!");
      return;
   }
   Serial.println("LittleFS je pripraven!");

   printFSInfo();
   Serial.println();

   // vypis obsahu
   listFS();
}
void loop() {
   // Zatím nic
}
Poznámka:
V kódu si všimněme, že inicializace LittleFS je volána jako LittleFS.begin(), tedy bez parametru true. Pokud jsme do souborového systému nahráli soubor pomocí doplňku LittleFS Uploader, lze předpokládat, že při spuštění již souborový systém existuje.

Program spustíme v modulu ESP32. V okně sériového monitoru prostředí Arduino IDE se zobrazí výpis obsahu souborového systému (viz obr. 18).

ovezeni uploadovanych dat na ESP32

Obrázek č. 18 – Výpis obsahu flash paměti ukazuje přítomnost souboru AHOJ.txt.

Pokud je soubor ve výpisu uveden (obr. č. 18), znamená to, že byl úspěšně nahrán do souborového systému doplňkem LittleFS Uploader.

Pokud složku data naplníme více soubory, všechny se při uploadu nahrají do modulu ESP32. Je však potřeba pamatovat na omezenou velikost datového úložiště ve flash paměti!

Upozornění:
Všimněme si, že nahrání programu nijak nepřepsalo soubory uložené ve flash paměti (například soubor AHOJ.txt) spravované souborovým systémem LittleFS. Platí to i naopak – aktualizace dat v této části paměti neovlivní uložený program.
To je velmi praktické například při změně konfiguračních souborů. Není nutné znovu překládat a nahrávat celý program, stačí aktualizovat pouze soubory v souborovém systému.

Závěr

V dnešním článku jsme si ukázali, jak lze na modulu ESP32 využít souborový systém LittleFS pro ukládání a správu dat ve flash paměti. Nejprve jsme si vysvětlili princip fungování tohoto souborového systému a jeho nastavení v prostředí Arduino IDE. Následně jsme si na jednoduchých příkladech vyzkoušeli základní operace se soubory – jejich vytvoření, zápis a čtení, přejmenování a smazání. Podívali jsme se také na práci se složkami a na možnosti kopírování nebo přesunu souborů.

V závěru jsme si představili doplněk LittleFS Uploader, pomocí kterého lze pohodlně nahrávat soubory z počítače přímo do souborového systému mikrokontroleru, a ukázali jsme si i způsob, jak ověřit, že byly soubory do zařízení úspěšně uloženy. Díky těmto postupům nyní můžeme ve svých projektech snadno využívat flash paměť ESP32 pro ukládání konfiguračních souborů, webových stránek nebo jiných dat.

Zbývá už jen jediné – vyzkoušet si práci se souborovým systémem LittleFS přímo v některém ze svých projektů na ESP32.

Pošli signál autorovi: