Laufende Erkenntnisse bei ESP8266-Projekten.


Klasse EEPROMClass (EEPROM)

Das EEPROM wird beim ESP8266 in einem 4K großen kontinuierlichen Flash-Bereich emuliert. 4K (SPI_FLASH_SEC_SIZE (4096) ist in spi_flash.h) ist die Sektor-Größe des Flash.

Eine gute Anleitung zur Verwendung findet man bei kriwanek.de

Will man mehr machen, muss man verstehen, wie das System funktioniert. Zunächst ist das Ganze als Arduino-typische Klassenkonstruktion aufgebaut. Es gibt die Klasse EEPROMClass, die die Funktionalitäten bereit stellt und die vordefinierte Instanz EEPROM, über die diese Funktionalitäten abgerufen werden können.

void EEPROMClass::begin(size_t size) initialisiert das System. Es wird ein interner Puffer mit Namen _data in der angegeben Größe angelegt und der als EEPROM deklarierte Flash-Bereich in diesen Puffer eingelesen. Nachfolgende Lese oder Schreib-Operationen erfolgen ausschließlich aus bzw. in den Puffer. Erst bei Aufruf der Methode commit(), werden der interne Puffer zurück ins Flash geschrieben. end() schreibt die Daten ebenfalls zurück, gibt aber den zusätzlich den internen Puffer an die Speicherverwaltung zurück.

EEPROM

In der internen Variablen _dirty wird nachgehalten, ob der Pufferinhalt geändert wurde. Ein Zurückschreiben des Puffers bei commit() erfolgt nur, wenn _dirty gesetzt ist. Die Methode getDataPtr() liefert einen Zeiger auf den internen Puffer. Auch beim Aufruf dieser Methode wird _dirty gesetzt, weil der Pufferinhalt über diesen Zeiger abgeändert werden kann.

Der Konstruktor der Klasse EEPROMClass benötigt noch die Angabe der Speicheradresse (Sektornummer) in EEPROM.cpp wird die vordefinierte Instanz der Klasse EEPROM wir folgt angelegt:

EEEPROMClass EEPROM((((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE));

_SPIFFS_end ergibt sich aus der in der IDE festgelegten SPIFFS-Konfiguration.

Verwendung

Zur strukturierten Benutzung des EEPROM legt man am besten eine Struktur an, die die zu persistierenden Daten enthält, z.B.:

struct  {
  float Value1;
  int  Value2;
  char Value3[16];
  bool Value4;
} PersistenceStruct;

Das EEPROM initialisiert man nicht größer als notwendig, damit nicht unnötig RAM verschwendet wird. Die häufig empfohlene Initialisierung mit 4096 bewirkt, dass ein interner 4096 Byte großer Puffer angelegt wird. Aber auch beim ESP8266 ist das RAM endlich!

EEPROM.begin(sizeof(PersistenceStruct));

Der entsprechende EEPROM-Bereich ist nun in den internen Puffer kopiert. Mit

EEPROM.get(0,PersistenceStruct);

überträgt den internen Puffer in die Struktur-Variable. 0 ist die Startadresse im internen Puffer und kann bei diesem Beispiel auf 0 gelassen werden.

Die gespeicherten Daten stehen nun über die Struktur-Variable lesend und schreibend zur Verfügung, z.B.:

if (PersistenceStruct.Value4)     // lesen
  PersistenceStruct.Value1 = 1.0; // ändern

Wenn Daten geänderte Daten persistiert werden sollen, geschieht dies mit

EEPROM.put(0, PersistenceStruct); // Kopiert die Strukturvariable in den internen Puffer
EEPROM.commit();                  // Kopiert den internen Puffer in den EEPROM-Bereich