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:
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:
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:
Copiamo la cartella spiffs dallo zip all’interno della cartella components del nostro progetto:
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:
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.
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
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:
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:
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):
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.
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
grazie Loris, in effetti ora il framework ha incluso un driver SPIFFS “ufficiale”, sto rivedendo quindi l’articolo…
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
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.
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
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.
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
ottimo grazie!
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 ?
Hi… well partitions don’t need to be contiguous but you’re right, in this case I’m wasting some space…