ESP8266 FLASH (/EEPROM)

esp_dev_kitEs geht weiter mit dem ESP8266. Die Grunddinge (softAP, station etc.) sitzen, wir kommen an den Punkt an welchem wir Daten speichern müssen. Daten können Zugangsdaten, Passwörter, Einstellungen, Stellungen etc. sein. Normalerweise nutzt man auf einer MCU dazu das altbekannte EEPROM. Dabei handelt es sich um einen persistenten Speicher, welcher seinen Inhalt im stromlosen Zustand behält. Auf dem ESP8266 haben wir jedoch kein solches EEPROM. Dafür haben wir einen schön grosssen FLASH Speicher. Unter anderem ist darauf Speicher für genau solche „User parameter“ reserviert. In diesem Artikel möchte ich einige Kernpunkte/Stolpersteine zur Verwendung davon nennen.

Hauptsächlich werden folgende 3 Funktionen genutzt. Diese sind im Espressif SDK vorhanden und in der API guide von Espressif beschrieben:

spi_flash_erase_sector (uint16 sec)
spi_flash_write (uint32 des_addr, uint32 *src_addr, uint32 size)
spi_flash_read(uint32 src_addr, uint32 * des_addr, uint32 size)

Der Nutzen der Befehle sollte im grossen und ganzen bereits durch dessen Namen klar sein.

Es wird von Sektoren und Adressen gesprochen. Woher weiss man nun wo man Daten schreiben kann/darf? Ganz einfach, es ist alles schön im Dokument „OTA Upgrade“ von Espressif beschrieben:512kb_esp8266
Anhand dieser Map können wir nun die Adressen/Sektoren berechnen. Interessant für uns ist der Block „User param“. Dieser umfasst 16KB, das heisst 4 Sektoren. Ein Sektor ist immer 4KB gross. Die erste Adresse berechnen wir nun wie folgt:

(64 + 176)  * 1024 = 0x3C000

Sektor ist demnach 0x3C (Adresse / 4096)

Am besten rechnet man sowas im Windows Taschenrechner, die Rechnung an sich ist Dezimal, danach um das Resultat in Hex zu haben auf Hexidezimal wechseln:

calc_0x3c

Ich arbeite im weiteren Verlauf jedoch mit dem zweiten User param Sektor. Dieser hat die Adresse 0x3D000 bzw. Sektor 0x3D. Berechnen kann man diesen indem man die Adresse für 4KB später berechnet.

Nun haben wir alle Infos um mit dem „arbeiten“ zu beginnen. Am besten fängt man mit einem simplen Programm wie folgt an:

unsigned char meinsatz[1024] = "Ich nutze ab jetzt den Flash Speicher für meine Daten!\n";
unsigned char meinflash[1024];

spi_flash_erase_sector(0x3D);
spi_flash_write(0x3D000, (uint32 *) meinsatz, sizeof(meinsatz));
spi_flash_read(0x3D000, (uint32 *) meinflash, sizeof(meinflash));
os_printf("%s", meinflash);

Das Programm löscht den Sektor (4KB) zuerst (zwingend!), danach wird der Speicher mit dem meinsatz beschrieben, dabei wird automatisch mit dem sizeof die Grösse ermittelt. Danach wird genau der Satz wieder geladen und mit printf ausgegeben.

So haben wir nun schon mal was. Schön ist das ganze jedoch natürlich noch nicht. Normalerweise hat man mehrere Parameter, z.B. einen Parameter für eine RGB Lampe Rot, Grün, Blau. Diese könnte man nur mit einem zusätzlichen (selbstgestrickten) handler trennen und organisieren. Das ganze lässt sich jedoch bereits ziemlich einfach und gut mit C Bordmitteln lösen. Dabei bauen wir uns sozusagen einen eigenen Datentyp. Diesen können wir mit bekannten Datentypen spicken (int, char, bool etc.).

struct parameter {
 char red, green, blue;
};

Diesen können wir nun wie folgt, ähnlich wie Variablen, nutzen.

struct parameter myparameter

myparameter.red = 120;
myparameter.green = 135;
myparameter.blue = 145;

Nun wird man sich fragen warum das für die Geschichte mit dem Flash gut sein soll. Ganz einfach: Wir können das ganze Struct in den Flash speichern und auch wieder holen 🙂

struct parameter myparameter
struct parameter myparameterfromflash
myparameter.red = 120;
myparameter.green = 135;
myparameter.blue = 145;

spi_flash_erase_sector(0x3D);
spi_flash_write(0x3D000, (uint32 *) &myparameter, sizeof(myparameter));
spi_flash_read(0x3D000, (uint32 *) myparameterfromflash, sizeof(myparameterfromflash));
os_printf("%s", myparameterfromflash.red);
os_printf("%s", myparameterfromflash.green);
os_printf("%s", myparameterfromflash.blue);

So können wir nun ganz Bequem und aufgeräumt Parameter zwischenspeichern, nutzen und vorallem auch persistens in den Flash speichern.

Ich habe dabei mit der NONOS SDK Version 1.5.2 gearbeitet. Konfiguiert wurde der Compiler auf den 512k Mode 0 ohne Boot.