Repository navigation
eeprom.pl
EEPROM przechowuje w pamięci flash mikrokontrolera ustawienia pod 32-bitowymi kluczami, na przykład wartość zadaną, kalibrację albo licznik. Mikrokontroler nie ma własnej pamięci EEPROM, dlatego biblioteka emuluje ją w pamięci flash. Podobnie jak PDB, niczego nie zmienia w zapisanych danych: nowa wartość trafia do nowej komórki, a odczyt bierze najnowszą.
- Magazyn zajmuje parzystą liczbę stron pamięci flash i dzieli je na dwie połowy, A i B. Do jednej trafiają zapisy, druga pozostaje skasowana.
- Każdy zapis dodaje jedną 8-bajtową komórkę: klucz i wartość, po 4 bajty. Ponowny zapis klucza zajmuje nową komórkę, a obowiązuje najnowsza.
- Przepisana połowa zaczyna się znacznikiem BEGIN, a kończy znacznikiem generacji, czyli licznika rosnącego przy każdym przepisaniu.
- Cztery najwyższe klucze, od
0xFFFFFFFCw górę, należą do samego EEPROM, a zapis z którymś z nich jest odrzucany.
Gdy aktywna połowa się zapełni, EEPROM przepisuje ją do drugiej w tej kolejności:
- Znacznik BEGIN.
- Najnowsza wartość każdego klucza, po jednej komórce.
- Znacznik z kolejnym numerem generacji.
- Dopiero wtedy pełna połowa jest kasowana.
Historia klucza skraca się do jednej komórki, a zapis trwa dalej w nowej połowie. Klucz, który nie mieści się w połowie, przepada przy przepisaniu, dlatego zbiór kluczy musi być znacznie mniejszy niż połowa.
Zasilanie może zaniknąć w dowolnej chwili. Przy następnym starcie EEPROM_Init odczytuje obie połowy i rozpoznaje, co było w toku:
- Przy zapisie wartości: komórka nie jest dokończona, więc się nie liczy, a jej klucz zachowuje starą wartość.
- Przy przepisaniu, przed znacznikiem generacji: nowa połowa ma znacznik BEGIN, ale nie ma znacznika generacji, więc jest kasowana, a przepisanie rusza od nowa.
- Po znaczniku generacji, przed skasowaniem pełnej połowy: obie połowy są kompletne, obowiązuje wyższa generacja, a druga połowa jest kasowana.
- Pod koniec kasowania: strona może odczytywać się jako skasowana, choć nie została skasowana do końca, więc EEPROM kasuje połowę w całości przed zapisem do niej, także taką, która odczytuje się jako skasowana.
Zanik zasilania w trakcie tego odtwarzania jest obsługiwany tak samo przy kolejnym starcie. Po zaniku zasilania w dowolnej chwili każdy klucz ma ostatnią zapisaną wartość, a klucz zapisywany w tej chwili starą albo nową. Testy na komputerze przerywają zasilanie w każdym cyklu pamięci flash długiej serii zapisów i przepisań, a także w trakcie samego odtwarzania.
Poza tą gwarancją pozostają trzy przypadki:
- Wartość zapisana pod dwoma kluczami, na przykład 64-bitowa, to dwa zapisy, więc zanik zasilania między nimi zostawia jej części z dwóch różnych zapisów.
- Przerwane
EEPROM_Clearmoże zostawić stare wartości do odczytu. - Najnowsza komórka liczy się tylko wtedy, gdy odczytuje się bez błędu, więc klucz zapisany raz traci wartość, jeśli w tej komórce z wiekiem przestawi się bit.
Własny magazyn: dwie strony i klucz dla każdego ustawienia, takie same w każdej wersji firmware.
enum { KEY_Setpoint = 1, KEY_Hysteresis = 2 };
// Two pages outside the program and the board stores
static EEPROM_t settings = { .page_start = 50, .page_count = 2 };Po każdym starcie najpierw EEPROM_Init, a każdy odczyt podaje wartość domyślną dla klucza, którego jeszcze nie zapisano.
static uint32_t setpoint, hysteresis;
void settings_init(void)
{
EEPROM_Init(&settings); // recovers whatever a power cut left
// A key not written yet reads as its default
setpoint = EEPROM_Read(&settings, KEY_Setpoint, 1500);
hysteresis = EEPROM_Read(&settings, KEY_Hysteresis, 50);
}
void setpoint_set(uint32_t value)
{
if(EEPROM_Write(&settings, KEY_Setpoint, value) == OK) setpoint = value;
}