Das EEPROM ist einer von drei Speichertypen, die der im Arduino Duemilanove verbaute Atmel ATmega328 mitbringt, in diesem Chip sind 1.024 Bytes davon verbaut.
Anders als das "normale" RAM verliert es seinen Inhalt nicht, wenn am Chip keine Spannung anliegt, es kann aber im Gegensatz zum Flash-Speicher auch vom Chip selbst beschrieben und geändert werden, das macht es zu einem für Konfigurations- und Kalibirierungsdaten äußerst geeigneten Speicher.
Für reines Daten-Logging ist es allerdings eher schlecht geeignet, Grund hierfür ist, dass dieser spezielle Speichertyp pro Speicherzelle nur eine bestimmte Anzahl Schreibvorgänge klaglos hin nimmt, für unsere Chips sind das 100.000. Ist diese Zahl erreicht, wird vom Hersteller nicht mehr gewährleistet, dass die Zelle nach einem Schreibvorgang auch den Wert enthält, den sie enthalten sollte.
Wenn ich also ein einzelnes Datenbyte habe, das ich gerne im EEPROM sicher ablegen will, dann könnte ich dieses Byte 100.000 mal ändern, und wäre immernoch auf der sicheren Seite, aber ab dann würde es unsicher werden...
Alternativ könnte ich das Byte natürlich jedes Mal an eine andere Stelle im Speicher schreiben, dann hätte ich plötzlich 1.024 mal 100.000 Möglichkeiten, den Wert zu ändern, und wäre noch auf der sicheren Seite, also über eine Milliarde.
Klingt gut, funktioniert aber so nicht, da man ja auch irgendwo speichern muss, WO genau im EEPROM das besagte Byte liegt.
Es kann sich glücklich schätzen, wer anderen nichtflüchtigen Speicher in seiner Schaltung hat, z.B. eine auf einem DS1307 basierende Echtzeituhr verwendet, denn die hat 56 Byte zur freien Verfügung, in denen man unter Anderem diese Startadresse hinterlegen könnte.
Alternativ zum EEPROM gibt es noch so genannte NVRAMs in separaten ICs. Es handelt sich dabei um einen Speicher, der die Vorteile der drei vorhandenen Speichertypen in sich vereinigt: Nichtverlust der Daten beim Spannungswegfall, Beschreibbarkeit vom Microprozessor aus und unbegrenzte Schreibzyklen.
Hätte ich diese zusätzlichen Möglichkeiten nicht, dann würde ich versuchen, ohne eine statische Stelle den Speicher abzuwechseln. Klingt im ersten Moment unmöglich, ist es aber nicht, da wir ja sowohl den komplette Überblick über das gesamte EEPROM wie auch alleinige und vollkommene Rechte darauf haben, und Lesevorgänge sind ja nicht begrenzt.
Man könnte z.B. als ersten Vorgang das gesamte EEPROM mit einem bestimmten Wert beschreiben (z.B. 0x00), wenn man dann einen Wert abgelegt hat, müsste man es nur durchsuchen, und würde das besagte Byte ohne Probleme finden können, da nur es sich vom Rest unterscheidet.
Würde sich der Wert ändern, dann würde ich das ursprüngliche Byte mit 0x00 überschreiben, und den neuen Wert eine Speicherstelle weiter ablegen. Käme man am Ende des Speichers an, würde man einfach am Anfang wieder beginnen, das ergäbe eine gleichmäßige Abnutzung aller Speicherstellen.
Nachteil dieser Methode wäre, dass man für ein Nutzbyte zwei Bytes beschreiben müsste (nämlich das alte Byte überschreiben und den neuen Wert ablegen), was die effektive maximal mögliche Lebensdauer des gesamten Speichers für die genutzte Datenmenge effektiv halbieren würde, man wäre aber auf jeden Fall 512 mal langlebiger als bei der das-Byte-immer-an-die-gleiche-Stelle-Methode.
Will man mehr als ein Byte speichern, so müsste man bei dieser Methode aber auf jeden Fall ein spezielles Markierungsbyte mit ablegen, denn bei einem einzigen Byte weiss man ja trotzdem, wie sein genauer Wert ist, selbst wenn im ganzen EEPROM nur 0x00 liegen, aber bei mehreren Bytes ist unklar, ob das "fehlende" Byte am Anfang oder am Ende der Struktur liegt.
Sollten die abzuspeichernden Werte es erlauben, ein Markierungsbyte definieren zu können, dessen Wert tatsächlich einzigartig ist (z.B. wenn man sicher nur Daten mit Werten zwischen 0x00 und maximal 0xFE abspeichern wird, dann könnte ein einzigartiges Markierungsbyte vom Wert 0xFF dargestellt werden), dann kann man tatsächlich auf die Löschung alter Daten verzichten, indem man beim nächsten Schreibvorgang einfach leicht überlappend speichert und das alte Markierungsbyte überschreibt, die restlichen Daten aber einfach liegen lässt.
Da man den Start (oder programmatisch besser das Ende) des Nutzdatenblocks anhand des Markierungsbytes bestimmen kann und die genaue Länge des Blocks kennt (da man ihn ja selbst geschrieben hat), ist es dann trotzdem kein Problem, die tatsächlichen Nutzdaten zu extrahieren.
Soweit zu meinen Ideen, kennt jemand eine noch effektivere Methode?