C EEPROM Werte auf feste Speicheradressen setzen

schnutzibaer

Neues Mitglied
26. Mai 2014
4
0
0
Sprachen
Adding/changing EEPROM definitions on ATMEL MEGA 8 Bit

Möglich ist, dass die geschilderte Lösung bereits von anderen beschrieben wurde, ich konnte trotz intensiver Suche im Web aber nichts Vergleichbares finden.

Ein oft gefragtes Problem in verschiedenen Foren ist die korrekte und dauerhafte Platzierung von Programm-Variablen im EEPROM. Wichtige Gründe dafür sind:
Zugriff mehrerer Prozessoren auf denselben EEPROM.

Änderungen oder Zusätze zur bestehenden EEPROM Struktur, wo sich inzwischen die Initialwerte geändert haben und die Änderungen nicht überprogrammiert werden dürfen.
Andere Gründe überlasse ich der Phantasie der User.

Ich habe nun folgende Lösung gefunden, die mir gegenüber den im Web beschriebenen praktikabler erscheint, aber dennoch ein exaktes und gründliches Arbeiten erfordert.

Ich bin noch nicht am Ende meiner Untersuchungen, möchte hier trotzdem den Stand der Dinge niederschreiben (ich sitze gerade im Ausland im Hotel, da hab ich Zeit).

Die Lösung ist unter folgenden Randbedingungen entstanden:

AVR Studio 6.2 Standard-Installation
Alle compiler-options standard. The only one I changed is Optimization from O1 to Os.
Ich weiß inzwischen, dass die Compiler-Options eine Rolle spielen, ob das Beschriebene funktioniert oder nicht. Ich will das in den nächsten Wochen noch gründlicher untersuchen.
Falls an dem Thema weiterhin Interesse besteht, teile ich meine Erkenntnisse gerne mit und bitte um Rückfragen.

Zur Überprüfung der Ergebnisse habe ich das Freeware-Tool “Hexplorer” verwendet. Damit ist es möglich, die vom Compiler erzeugte *.eep Datei (INTEL-HEX Format) zu importieren und sich das Ergebnis, das in den EEPROM gelangt, als reine Binärdarstellung anzuschauen.


Schritt 1:
Definieren einer, aber auch nur einer Struktur, die alle EEPROM Variablen enthält:

typedef struct
{
//Dummy for Byte 0
uint8_t EE_DUMMY; // don't use it

//a byte
uint8_t EE_HW_ADDR;
:
:
// a word
uint16_t EE_Def_Buz_Freq;
:
:
//an array
uint8_t EE_BLM[48];
} EE_data_t;




Zweiter Schritt:
Erzeugen Sie eine Instanz dieser Typdefinition. Hier ist es möglich, die Variablen mit Initialwerten zu belegen. Belegen Sie alle Werte, auch NULL-Werte !!
S
chicken Sie die Instanz in den EEPROM Bereich durch Verwendung der EEMEM Klausel.

EE_data_t EEMEM EE_Data =
{
//** uint8_t EE_DUMMY
0x00, //don't use it

//Hardware address (DIP switch configuration)
//** uint8_t EE_HW_ADDR
0x55, // a funny address as joker


//**uint8_t EE_BLM[48]
{
254, LED_MSK_RED_VAL, 40,
250, LED_MSK_YEL_VAL, 45,
255, LED_MSK_GRN1_VAL, 35,
254, LED_MSK_GRN2_VAL, 30,
254, LED_MSK_RED_VAL, 44
}

Stellen Sie unbedingt sicher, dass die Instanz mitsamt den Initialwerten absolut identisch ist mit der zuvor getätigten Struktur-Definiton !
Das ist der kritischste Punkt an dem Verfahren.

Dritter Schritt:
Testen:
Verwenden Sie zuerst eine „Minidefiniton“ mit einigen wenigen Variablen. Mischen Sie dabei unterschiedliche Datentypen.
Projekt compilieren. Dann benutzen Sie das o.g. Tool “Hexplorer” oder was auch immer Sie haben, und importieren Sie das *.eep File, das beim ATMEL Studio standardmäßig im Projektordner, Unterordner „debug“ zu finden ist. („Datei >> Importieren >> INTEL Hex Format“, die Fehlermeldung mit der fehlenden Startadresse ignorieren, das macht das Programmiermodul später alleine).
Drucken Sie es aus, schreiben Sie es ab oder machen Sie ein Screenshot.
Dann fügen Sie an das Ende der Strukturdefinition eine weitere Variable an und belegen Sie diese auch in der Instanz mit einem (beliebigen) Wert.
Projekt neu compilieren. EEP File neu importieren. Vergleichen Sie Byte für Byte das alte und das neue EEP-File. Der zusätzliche Variablenwert muß am Ende des Hexdumps stehen. Der Rest muss genauso aussehen wie vorher. Dann ist alles richtig.

Vierter Schritt:
Jetzt ist es soweit, dass Sie trotz aller Umsicht und Vorausschau eine Änderung an Ihrer EEPROM Struktur vornehmen müssen. Und alles soll am alten Platz bleiben.

Fall 1: Es kommt was Neues hinzu.
Platzieren Sie zusätzliche Variablen immer am Ende der Struktur-Definition! Vergessen Sie nicht, bei der Instanz-Erzeugung passende Initialwerte einzutragen !
Fertig. Alle alten Werte bleiben auf derselben absoluten Adresse.





Fall 2: Eine bestehende Definition muss geändert werden.
Sie müssen aus einem Byte ein Word machen. Oder zu einer Array-Definition sind zusätzliche Spalten oder Zeilen erforderlich.
Lassen Sie die „alte“ Definition da, wo sie ist, und geben Sie ihr nur einen anderen Namen. Das ist jetzt verlorener Platz. Hängen Sie die geänderte Definition hinten dran mit dem bisher benutzten Namen ! Vergessen Sie nicht, auch hier der angehängten Strukturdefinition passende Initialwerte zu vergeben.

Eine andere Lösung:
Szenario ist folgendes: Sie haben ihr Device während der Produktion programmiert, incl. EEPROM-Werten. Während des allgemeinen Betriebs haben sich einige Werte im EEPROM geändert. Sie sind sich nicht sicher, dass z.B. ein Service-Mann mit einem Handheld-Programmer die EEPROM-Werte überschreibt, weil die EESAVE-Fuse zwar gesetzt ist, aber manche Handhelds die Fuse kurzerhand rücksetzen vor der Programmierung.
Dann hilft folgendes:
Voraussetzung ist, dass im Flash noch genügend Platz für den EEPROM Inhalt ist.
Dann platzieren Sie die Instanz Ihrer predefined Values im Flash, indem Sie die EEMEM Klausel weglassen:

alt: EE_data_t EEMEM EE_Data = ….

neu: EE_data_t EE_Data =

Nun müssen Sie dafür sorgen, dass diese Werte in das EEPROM gelangen, aber nur, wenn noch nichts drinsteht:
Lesen Sie aus dem EEPROM einen unveränderlichen signifikanten Wert aus und vergleichen Sie ihn mit der Predefinition im Flash. Ist dieser Wert noch nicht im EEPROM, schreibe ich die Default-Werte rein. Ich benutze hier z.B. eine (unveränderliche) Variable „Application ID“:

void Check_EEPROM_Defaults(void)
{
uint8_t Appl_ID[8];

eeprom_read_block( Appl_ID , &EE_Data.EE_APPL_ID , sizeof(EE_Data.EE_APPL_ID ));

if(memcmp((void*)&Appl_ID[0] , &EE_Data.EE_APPL_ID[0], 8) != 0)
{ //no Application ID wrote earlier, write default values to EEPROM !
eeprom_write_block( (void*)&EE_Data,&EE_Data_Top,sizeof(EE_Data) );
}

}

Die Zieladresse für eeprom_write_block definiere ich einfacherweise mit:

uint8_t EEMEM EE_Data_Top;

Das darf dann aber die einzige “EEMEM” Definition im ganzen Projekt sein !!

Benötigen Sie für nachträgliche Eintragungen vordefinierte Werte im EEPROM, müssen diese "manuell" durch die Software erzeugt werden.
 
Noch Fehler im Beitrag

Es sind noch Fehler im o.g. Beitrag, was den letzten Teil betrifft (Ablage der Defaultwerte im Flash mit anschließender Kopie ins EEPROM). :(
Werde die Korrektur Anfang nächste Woche nachreichen.

Entschuldigung. Schnutzibaer.
 
angekündigte Korrektur

Hallo,

hier die versprochene Korrektur:

Es betrifft den Abschnitt:

Eine andere Lösung:
Szenario ist folgendes: Sie haben ihr Device während der Produktion programmiert, incl. EEPROM-Werten. Während des allgemeinen Betriebs haben sich einige Werte im EEPROM geändert. Sie sind sich nicht sicher, dass z.B. ein Service-Mann mit einem Handheld-Programmer die EEPROM-Werte überschreibt, weil die EESAVE-Fuse zwar gesetzt ist, aber manche Handhelds die Fuse kurzerhand rücksetzen vor der Programmierung.
Dann hilft folgendes:
Voraussetzung ist, dass im Flash noch genügend Platz für den EEPROM Inhalt ist.
Dann platzieren Sie die Instanz Ihrer predefined Values im Flash, indem Sie die EEMEM Klausel weglassen:


Benutzen Sie die Struktur-Definiton zweimal:

im Flash mit predefined values:

EE_data_t EE_Data_templ =
{
//** uint8_t EE_DUMMY
0x00, //don't use it

//Hardware address (DIP switch configuration)
//** uint8_t EE_HW_ADDR
0x55, // a funny address as joker


//**uint8_t EE_BLM[48]
{
254, LED_MSK_RED_VAL, 40,
250, LED_MSK_YEL_VAL, 45,
255, LED_MSK_GRN1_VAL, 35,
254, LED_MSK_GRN2_VAL, 30,
254, LED_MSK_RED_VAL, 44
}
}


und dann noch einmal im EEPROM ohne jeden Wert:

EE_data_t EEMEM EE_Data;


Dass diese Werte in das EEPROM gelangen, aber nur, wenn noch nichts drinsteht:

Lesen Sie aus dem EEPROM einen unveränderlichen signifikanten Wert aus und vergleichen Sie ihn mit der Predefinition im Flash. Ist dieser Wert noch nicht im EEPROM, schreibe ich die Default-Werte rein. Ich benutze hier z.B. eine (unveränderliche) Variable „Application ID“:
Gegenüber der alten Version benutze ich hier nicht die eeprom_write_block() Funktion, sondern eeprom_write_byte(), weil die Block Funktion für meinen Watchdog einfach zu lange gedauert hat.

void Check_EEPROM_Defaults(void)
{
uint8_t Appl_ID[8];
uint8_t Databyte;
uint8_t *pa;
uint8_t *pb;
uint16_t StrucLen;
uint16_t x;

eeprom_read_block( Appl_ID , &EE_Data.EE_APPL_ID , sizeof(EE_Data.EE_APPL_ID ));

if(memcmp((void*)&Appl_ID[0] , &EE_Data_templ.EE_APPL_ID[0], 8) != 0)
{ //no Application ID wrote earlier, write default values to EEPROM !
StrucLen = sizeof(EE_Data_templ);
pa = &EE_Data_templ.EE_DUMMY;
pb = &EE_Data.EE_DUMMY;

for ( x = 1 ; x <= StrucLen ; x++ )
{
wdt_reset();
Databyte = *pa;
eeprom_update_byte( pb , Databyte) ;
pa++;
pb++;
}
}
}

Benötigen Sie für nachträgliche Eintragungen vordefinierte Werte im EEPROM, müssen diese "manuell" durch die Software erzeugt werden.
 
Warum mir diese Versionen nicht gefallen

hm... also es gibt im Netz schon Beispiele......

Ich persönlich verwende diese Methode: (erstes Beispiel)
http://www.edaboard.com/entry862.html

oder
http://blog.cc-robotics.de/2009/03/20/einstellungen-im-eeprom-eines-avr-speichern/

Hallo, avr_newbie,

zunächst Danke für Deine Tipps!

Ich denke, die beiden Links habe ich bei meiner Recherche auch gesehen.

Link 1 gefällt mir persönlich nicht, weil ich hier wirklich auf FIXE Adressen angewiesen bin. Hab ich mich da verzählt bei den Definitionen, überlappen sich die Variablen sehr schnell. Da ist meine Methode doch nicht ganz so riskant.
Und bei Link 2 musst Du zugeben, dass die nicht sehr elegant ist.
Es geht bei mir teilweise um mehr als 200 Byte strukturierte Information, die ich im EEPROM ablegen muss, und die sich während des allgemeinen Betriebs ständig ändert.

Ende des Monats ist mein neuestes Projekt fertig. Du mußt Dir vorstellen, dass ich beim Kunden immer vier Ebenen zu versorgen habe: ein Zentral-PC, ein bis acht Etagenmodule, die steuern jeweils 10 bis 60 Zimmermodule, und die sind für je 5..10 Zimmermodule zuständig. Das Ganze läßt sich von ganz oben mit Firmware-Updates versorgen (per Bootloader), und wehe, es wird dann noch ein EEPROM überschrieben oder die Speicheradressen ändern sich. Hab ich dann bis Jahresende 20 oder 30 dieser Projekte realisiert, kommt mich jede Fehler teuer zu stehen.

Schöne Pfingsten

Schnutzibaer
 
Geschmackssache... wie gesagt, mir persönlich gefällt die 1. Variante und verwende diese auch , die fixe Adressen kann man umgehen, in dem man sich noch ne schöne Funktion dazu bastelt:D

Link zwei verwende ich auch nicht , wollte ich nur erwähnen....

Hallo, avr_newbie,

zunächst Danke für Deine Tipps!

Ich denke, die beiden Links habe ich bei meiner Recherche auch gesehen.

Link 1 gefällt mir persönlich nicht, weil ich hier wirklich auf FIXE Adressen angewiesen bin. Hab ich mich da verzählt bei den Definitionen, überlappen sich die Variablen sehr schnell. Da ist meine Methode doch nicht ganz so riskant.
Und bei Link 2 musst Du zugeben, dass die nicht sehr elegant ist.
Es geht bei mir teilweise um mehr als 200 Byte strukturierte Information, die ich im EEPROM ablegen muss, und die sich während des allgemeinen Betriebs ständig ändert.

Ende des Monats ist mein neuestes Projekt fertig. Du mußt Dir vorstellen, dass ich beim Kunden immer vier Ebenen zu versorgen habe: ein Zentral-PC, ein bis acht Etagenmodule, die steuern jeweils 10 bis 60 Zimmermodule, und die sind für je 5..10 Zimmermodule zuständig. Das Ganze läßt sich von ganz oben mit Firmware-Updates versorgen (per Bootloader), und wehe, es wird dann noch ein EEPROM überschrieben oder die Speicheradressen ändern sich. Hab ich dann bis Jahresende 20 oder 30 dieser Projekte realisiert, kommt mich jede Fehler teuer zu stehen.

Schöne Pfingsten

Schnutzibaer
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)