ESP32 (22) – SPIFFS

by luca
11 comments

In alcuni tutorial precedenti vi ho mostrato come includere elementi “esterni” al programma (immagini, certificati…) grazie alla funzionalità embedding binary data del framework. Oggi vi mostrerò invece come poter utilizzare una porzione della memoria flash per memorizzare dati, in maniera simile ad un disco fisso o una memory card.

Partizioni e file system

Avete già imparato dal mio quarto tutorial sul chip esp32 che la memoria flash collegata al chip viene suddivisa in partizioni, per poter ospitare diversi elementi e che è possibile – tramite menuconfig – configurare le diverse partizioni utilizzando dei template standard (es. “single factory app, no OTA”) o in maniera completamente custom.

L’elenco delle partizioni, la loro posizione all’interno della memoria flash e la loro dimensione sono definiti nella partition table, anch’essa memorizzata nella flash all’indirizzo 0x8000.

Possiamo definire un layout personalizzato della memoria flash creando un file csv con questo formato:

spiffs-001

Ogni riga corrisponde ad una partizione; per ogni partizione va indicato il tipo, il sottotipo, l’offset (ovvero l’indirizzo di partenza della partizione) e la dimensione. Il file csv sopra mostrato corrisponde a questo layout:

spiffs-002

Per verificare che le partizioni siano contigue, è sufficiente sommare all’offset la dimensione della partizione per trovare l’offset della successiva… ad esempio 0x9000 + 0x6000 = 0xf000.

Una partizione è semplicemente un’area di memoria: per poter memorizzarvi dei dati è necessario “organizzarli”; ad esempio abbiamo già visto l’utilizzo del componente NVS che si occupa di gestire dati nella forma “chiave-valore” nella partizione ad esso dedicato. I diversi supporti di memorizzazione (chiavette USB, dischi fissi…) organizzano i dati grazie ad un filesystem. Negli anni sono stati sviluppati moltissimi filesystem in base alle tipologie di supporti e ad esigenze specifiche… se avete un PC Windows quasi sicuramente il vostro disco fisso utilizzerà il filesystem NTFS, mentre le memory card normalmente utilizzano il filesystem FAT. Viste le caratteristiche peculiari delle memorie flash, Peter Andersson ha sviluppato un filesystem ottimizzato per tali supporti di memorizzazione, SPIFFS.

Componente

Per poter utilizzare il filesystem SPIFFS in un nostro programma, è necessario aggiungere alla cartella del progetto il componente sviluppato da Boris Lovosevic (loboris) che fa da wrapper tra la libreria SPIFFS di Peter Andersson (pellepl) e il Virtual File System (VFS) del framework esp-idf.

Scarichiamo quindi lo zip contenente il repository Github di loboris:

spiffs-01

Copiamo la cartella spiffs dallo zip all’interno della cartella components del nostro progetto:

spiffs-02

All’interno dello zip è anche presente lo strumento (mkspiffs) per poter “trasformare” una cartella del proprio PC in un file che rappresenta una partizione SPIFFS, pronto per essere caricato nella flash. Possiamo copiare la cartella mkspiffs ad esempio nella nostra home:

spiffs-04

Il componente spiffs richiede alcune variabili di configurazioni, che definiscono la geometria della partizione, ovvero come è “costruita”.

I parametri vanno aggiunti al file Kconfig.projbuild del progetto (qui vi ho spiegato la struttura di tale file) e sono i seguenti:

[checklist]

  • SPIFFS_BASE_ADDR, indirizzo della memoria flash dal quale inizia la partizione SPIFFS
  • SPIFFS_SIZE, dimensione in bytes della partizione
  • SPIFFS_LOG_BLOCK_SIZE, dimensione in bytes di ogni blocco di memoria
  • SPIFFS_LOG_PAGE_SIZE, dimensione in bytes di ogni pagina di memoria

[/checklist]

Se volete approfondire la struttura interna in blocchi e pagine della partizione SPIFFS, potete leggere questo documento.

Indirizzo base e dimensioni devono essere quelle che avete configurato nel file csv che definisce il layout della memoria flash, mentre valori “buoni” per dimensione blocco e pagina sono 8192 e 256.

Nel creare il file csv, abbiamo visto che è possibile specificare la dimensione indicando ad esempio 1M per 1MB (1 Mega Bytes). Tale dimensione equivale a 1.048.576 bytes (1024 * 1024 bytes) e non come si potrebbe pensare a 1.000.000 bytes.

Prepariamo e carichiamo l’immagine

Se è necessario caricare nella partizione SPIFFS del contenuto prima che venga eseguito il programma (ad esempio immagini, files audio… che saranno poi utilizzati dal programma durante la sua esecuzione) è possibile utilizzare il tool mkspiffs per preparare un file immagine con il contenuto di una cartella del proprio computer.

Per prima cosa dobbiamo compilare mkspiffs:

cd mkspiffs/src
make

spiffs-05

Creiamo ora sul nostro PC una nuova cartella e inseriamo i files che dovranno essere memorizzati nella partizione SPIFFS. Possiamo anche creare sottocartelle… ad esempio ho creato la cartella spiffs_image nella mia home con questo contenuto:

spiffs-06

Lanciamo il seguente comando per creare il file .img che rappresenta una partizione SPIFFS con il contenuto della cartella sopra:

./mkspiffs.exe -c /home/luca/spiffs_image/ -b 8192 -p 256 
 -s 1048576 /home/luca/spiffs_image.img

Il parametro -b rappresenta il valore di LOG_BLOCK_SIZE, -p il valore di LOG_PAGE_SIZE e -s la dimensione della partizione. Il comando mkspiffs visualizza il contenuto dell’immagine creata:

spiffs-07

Ora possiamo utilizzare esptool per memorizzare il contenuto del file creato all’interno della flash:

python $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 
--port COM15 --baud 115200 write_flash --flash_size detect 0x180000 /home/luca/spiffs_image.img

Sostituite la porta COM con quella a cui è collegata la vostra scheda di sviluppo. Fate particolare attenzione all’indirizzo (sopra 0x180000) da cui esptool inizia a scrivere i dati: deve corrispondere a quello specificato nel file csv che definisce il layout delle diverse partizioni.

Utilizziamo spiffs in un programma

Per prima cosa includiamo nel nostro programma gli headers del wrapper SPIFFS e del componente VFS:

// VFS and SPIFFS includes
#include "esp_vfs.h"
#include "spiffs_vfs.h"

All’inizio del programma, dobbiamo registrare il filesystem SPIFFS:

vfs_spiffs_register();

Questo metodo indica al componente VFS le caratteristiche proprie della partizione SPIFFS e quali funzioni chiamare per le diverse operazioni sul filesystem. Il metodo esegue anche il mount della partizione (formattandola se necessario) in modo che sia visibile a partire dal percorso /spiffs.

Possiamo verificare che la partizione sia stata montata con:

if(spiffs_is_mounted) {...}

A questo punto, grazie al componente VFS, è possibile operare sui files e cartelle contenute nella partizione usando le funzioni standard C. Ad esempio possiamo aprire in lettura il file “readme.txt” presente nella root della partizione con:

FILE *file;
file = fopen("/spiffs/readme.txt", "r");

e leggerne il contenuto con:

int filechar;
while((filechar = fgetc(file)) != EOF)
[...]

Nel mio repository Github trovate un programma che consente di navigare all’interno di una partizione SPIFFS con comandi unix-like (cd, ls) e di visualizzare il contenuto di files (cat):

[youtube id=”hGkbNuskVLw” width=”600″ height=”350″]

Conclusioni

La possibilità di utilizzare parte della memoria flash per memorizzare files ci consente di realizzare progetti che richiedano elementi esterni (pagine html, immagini, suoni…) senza bisogno di supporti di memorizzazione esterni al chip esp32.

Related Posts

11 comments

loris 1 novembre 2017 - 10:27

Ciao Luca.

Se provi a compilare l’esempio di blocca.
Deve esser cambiata la definizione in “esp_vfs.h”

Per risolvere il problema va commentato il campo:

esp_vfs_t vfs = {
// .fd_offset = 0,

Ciao Loris

Reply
luca 2 novembre 2017 - 08:36

grazie Loris, in effetti ora il framework ha incluso un driver SPIFFS “ufficiale”, sto rivedendo quindi l’articolo…

Reply
Maurizio 10 novembre 2017 - 08:59

Ciao Luca,
è possibile creare con SPIFFS un file locale che contenga un immagine recuperata da una IP cam ?
Un comando del tipo:
> SPIFFS.open(pippo, “w+”);
> File pippo = “http://address_ip:port/snapshot.cgi?user=xxx&pwd=xxx”;
Scusa se ho scritto qualche castroneria, ho questo oggetto da una settimana e sto imparando.
Grazie
Maurizio

Reply
luca 10 novembre 2017 - 11:48

Ciao, si non vedo problemi a fare quello che dici… solo va capito nella risposta della IP Cam da che punto “inizia” il bytestream che rappresenta l’immagine.

Reply
lucadentella.it – ESP32lights 15 gennaio 2018 - 08:23

[…] html, fogli di stile css…) sono memorizzati all’interno di una partizione SPIFFS. In un precedente tutorial vi ho mostrato come preparare l’immagine ed accedere al suo […]

Reply
Diego 16 gennaio 2018 - 12:47

Ciao Luca, complimenti per i tuoi tuttorial. Veramente ottimi!

Ora che il componente spiffs fa parte dell esp-idf framework, sto provando a caricare una immagine della partizione spiffs creata con il tool mkspffs. Riesco tranquillamente creare l’immagine e caricarla sul’esp con esptool. Tuttavia quando lancio il firmware dell’esp e provo a leggere i file di testo che ho precaricato ( sono dei file on.html e off.html ripresi dal tuo tutoria su ESP32 WEB server), ottengo solo caratteri strani come: ��@ ecc… Ciò non avvinee se il file lo creo direttamente dal firmware lo leggo poi lo leggo e lo ristampo. Sai quale potrebbe essere la causa del problema? Magari qualche problema di compatibilità tra mkspiffs e il componente spiffs del framework? l’ utimo commit del tool mkspiffs risale a 7 mesi fa

Grazie

Diego

Reply
luca 16 gennaio 2018 - 15:36

ciao Diego! E’ proprio così, anch’io avevo iniziato a fare delle prove ma pare che vi sia un disallineamento tra l’implementazione di SPIFFS del framework e quella del tool… per questo per ora continuo ad utilizzare (vedi il progetto ESP32lights) ancora il componente di loboris che funziona benissimo.

Reply
Diego 17 gennaio 2018 - 12:04

Grazie per la risposta!
Tuttavia volevo condividere con te la soluzione a questo problema. Ho approfondito un po’ la questione e alla fine sono riusito ad utilizzare il componente ufficiale spiffs con il tool mkspiffs di loboris. In 2 parole:
una volta tirato giù il pacchetto del toole mkspiffs, prima di compilarlo va sostituito il file mkspiffs/include/sdkconfig.h con quello del tuo progetto, il quale contiene i corretti parametri ralativi alla partizione spiffs: SPIFFS_BASE_ADDR, SPIFFS_SIZE, SPIFFS_LOG_BLOCK_SIZE e SPIFFS_LOG_PAGE_SIZE.
Poi si può compilare ed utilizzare il tool per creare l’immagine da caricare poi con esptool.py.
N.B. Nel caso vengano cambiati i parametri si deve ricompilare il tool mkspiffs.

Questo è il link al thread dove ho trovato la soluzione https://esp32.com/viewtopic.php?f=2&t=3955&p=18002&hilit=mkspiffs#p18002

Credo che lo stesso valga per le varie verisoni di mkspiffs ( ovvero sia quella di loboris che di igrr).
Io ho tuttavia provato soltato con il pacchetto che è possibile scaricare dal commento del thread (Tue Dec 19, 2017 9:47 am) fornito da loboris.

Ora riesco a leggere correttamente il contenuto dei file caricati usando il componente spiffs del esp-idf framework.

Spero di essereti stato utile,

Diego

Reply
luca 18 gennaio 2018 - 08:24

ottimo grazie!

Reply
Itamar Cohen 2 agosto 2018 - 13:16

Hi Luca
In your flash map / partition the factory 1M section starts at 0x10000 and should be ended at 0x110000
However the spiffs section starts at 0x180000
shouldn’t it starts at 0x110000 ?

Reply
luca 4 agosto 2018 - 13:21

Hi… well partitions don’t need to be contiguous but you’re right, in this case I’m wasting some space…

Reply

Leave a Comment