Forum: Mikrocontroller und Digitale Elektronik ATMEGA16 - Probleme mit int. EEPROM


von Peter S. (petersp)


Lesenswert?

Hallo allemiteinander,

ein ATMEGA16 nutzt zum Ablegen eines Parameters das interne EEPROM. Das 
funktioniert auch soweit, d.h., der Parameter wird, falls er sich beim 
normalen Betrieb verändert, ins EEPROM geschrieben. Ich habe immer 
wieder den EEPROM-Inhalt ausgelesen und das überprüft.

Wenn man den Prozessor per Reset neu startet, wird der zuletzt 
gespeicherte Wert aus dem EEPROM geholt - passt also auch. Wenn ich 
jetzt die Versorgungsspannung aus- und wieder einschalte, funktioniert 
das Procedere nicht mehr. Den abgespeicherten Wert gibt es nicht mehr.

Ich benutze die Fuse EESAVE, um den EEPROM-Inhalt beim Neubeschreiben 
des Flash zu behalten. Dann habe ich rein zum Testen mal eine 
Zeitschleife in die main-function gebaut, bevor der EEPROM-Inhalt nach 
einem Neustart gelesen wird. Das hat aber auch nichts geholfen. Für 
meine EEPROM-Geschichte benutze ich die im AVR-GCC-Tutorial 
vorgestellten Routinen.

Was habe ich übersehen, weil sich der ATMEGA16 bei mir so verhält? Ich 
habe jetzt nicht den gesamten Programmcode gepostet, sondern nur die 
Teile, die für die EEPROM-Sachen zuständig sind. Vielleich mache ich ja 
einen grundsätzlichen Fehler:

1
#include <avr/eeprom.h>
2
int8_t value = 0;
3
uint8_t eeGluehByte EEMEM = 1;
4
5
// init nach einschalten oder reset:
6
7
value = eeprom_read_byte (&eeGluehByte); //gespeicherten Wert aus EEPROM lesen
8
9
// bei neuem ATMEGA sind die EEPROM-Zellen 0xFF
10
// falls der gelesene Wert ueber 0x46 liegt, wird in die EEPROM-Zelle 0x14 geschrieben
11
// value hat dann den (dezimalen) Wert 20
12
  
13
  if (value > 70)
14
  {
15
    value = 20;
16
    eeprom_write_byte(&eeGluehByte,value);
17
  }
18
19
// später dann in der function main():
20
21
      Status.Data_changed = 1;
22
      eeprom_write_byte(&eeGluehByte,value); // neuen Wert in EEPROM speichern
23
      Status.Data_changed = 0;

Kann mir jemand einen Tipp geben, was ich falsch mache?

Servus
Peter

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Peter Spiess schrieb:
> uint8_t eeGluehByte EEMEM = 1;

Das sieht nicht so richtig nach einer EEPROM Deklaration aus. Probier 
mal
1
uint8_t eeGluehByte  __attribute__((section(".eeprom")))
und überlasse das Festlegen der eigentlichen Adresse im EEPROM dem 
Kompiler.
Nimm hier mal das Leerzeichen raus:
1
eeprom_read_byte (&eeGluehByte);
Schreib übrigens nicht zu oft ins EEPROM. Es ist 'nur' für ca. 100000 
Schreibzyklen pro Zelle spezifiziert, so das du sparsam mit 
Schreibzyklen umgehen solltest.

: Bearbeitet durch User
von Peter S. (petersp)


Angehängte Dateien:

Lesenswert?

Hallo Matthias,

danke für Deine Antwort.

Matthias Sch. schrieb:
> Peter Spiess schrieb:
>> uint8_t eeGluehByte EEMEM = 1;
>
> Das sieht nicht so richtig nach einer EEPROM Deklaration aus. Probier
> mal
>
1
> uint8_t eeGluehByte  __attribute__((section(".eeprom")))
2
>
> und überlasse das Festlegen der eigentlichen Adresse im EEPROM dem
> Kompiler.

Ok, habe ich so ausprobiert. Das funktioniert ohne Probleme, allerdings 
mit gleichem Ergebnis. Bei einem Reset, ohne dem Controller die 
Stromversorgung zu nehmen, wird der gespeicherte Wert wieder geladen. 
Wenn ich den Strom aus- und wieder einschalte, ist der Wert weg.

Elektrisch ist der ATMEGA16 wie im Bild angeschlossen. Die Kondensatoren 
C6 - C8 sind direkt bei den uP-Pins 5, 17 und 38 platziert. Das sollte 
doch so in Ordnung sein.

> Nimm hier mal das Leerzeichen raus:
>
1
> eeprom_read_byte (&eeGluehByte);
2
>

Habe ich gemacht.

> Schreib übrigens nicht zu oft ins EEPROM. Es ist 'nur' für ca. 100000
> Schreibzyklen pro Zelle spezifiziert, so das du sparsam mit
> Schreibzyklen umgehen solltest.

Ja, das ist klar. Es wird nur bei einer Änderung des Wertes ins EEPROM 
geschrieben.

Servus
Peter

von m.n. (Gast)


Lesenswert?

Du mußt den Brown Out Detector verwenden, damit ein sauberer Reset bei 
fehlerhafter Eingangsspannung ausgelöst wird.
Die älteren ATmega hatten immer wieder Probleme mit dem EEPROM; ein 
neuer Typ dürfte besser funktionieren.

von Thomas E. (thomase)


Lesenswert?

Peter Spiess schrieb:
> Kann mir jemand einen Tipp geben, was ich falsch mache?
Gar nichts. Das funktioniert auf einem Attiny25 einwandfrei, was du da 
gemacht hast.

War da nicht irgendwas mit EEPROM-Adresse 0 bei den alten Gurken? Ich 
meine natürlich bei den beliebten Klassikern. Aber da soll Atmel 
irgendwas mit Adresse 0 vergurkt haben. Da gibt es, glaube ich, auch 
eine Empfehlung, Adresse 0 nicht zu benutzen.

Probier das mal "händisch" auf einer anderen Adresse:
1
if(eeprom_read_byte((unsigned char*)67) == 255)
2
{
3
  eeprom_write_byte((unsigned char*)67, 20);
4
  //Setze irgendeinen Port
5
}
6
else
7
{
8
  if(eeprom_read_byte((unsigned char*)67) == 20)
9
  {
10
    //Setze einen anderen Port
11
  }
12
}

mfg.

von c-hater (Gast)


Lesenswert?

Peter Spiess schrieb:

> Ok, habe ich so ausprobiert. Das funktioniert ohne Probleme, allerdings
> mit gleichem Ergebnis. Bei einem Reset, ohne dem Controller die
> Stromversorgung zu nehmen, wird der gespeicherte Wert wieder geladen.
> Wenn ich den Strom aus- und wieder einschalte, ist der Wert weg.

Typischer Brown-Out-Effekt. Deine Versorgungsspannung fällt zu langsam.

Das gibt dem µC ein Zeitfenster, in dem er noch irgendwas macht weil die 
Spannung dafür noch hoch genug ist, dies aber nicht mehr richtig macht, 
weil die Spannung für eine korrekte Arbeit bereits zu gering ist.

Sprich: er stürzt undefiniert ab und dabei wird in deinem Fall mehr oder 
weniger zufällig der EEPROM-Inhalt in Mitleidenschaft gezogen. Es können 
dabei auch völlig andere Sachen passieren, bis hin zur teilweisen oder 
gar vollständigen Löschung des Programms im Flash.

Dagegen helfen Softwareänderungen höchstens zufällig. Nur zwei Maßnahmen 
lösen das Problem wirklich:

1) (Bezogen auf den Zweck) sinnvolles Design der Versorgung.
2) µC bei ungenügender Spannung in den Reset-Zustand zwingen durch:
2.a) Internen Brownout-Detektor
2.b) Externen Reset-IC

Es spricht übrigens auch absolut nix dagegen, 1) und 2) in Kombination 
anzuwenden...

von Peter S. (petersp)


Lesenswert?

Hallo m.n. und c-hater,

Ihr habt Recht, mit aktivierten Brown Out Detektor funktioniert es 
einwandfrei!

Versorgt habe ich die Schaltung über einen 7805 mit entsprechenden Elkos 
am Ein- und Ausgang. Wenn ich die Versorgung wegnehme, gehen die 
geregelten 5V nicht aprupt, sondern relativ langsam in die Knie. Ist ja 
nachvollziehbar, dass der uP unkontrolliert abstürzt.

Daran hatte ich nicht gedacht, vielen Dank für Eure Hinweise und Hilfe.

Servus
Peter

von Peter S. (petersp)


Lesenswert?

Hallo Thomas,

Thomas Eckmann schrieb:
> War da nicht irgendwas mit EEPROM-Adresse 0 bei den alten Gurken? Ich
> meine natürlich bei den beliebten Klassikern.

:-)
Das mit dem Problem bei Adresse 0 habe ich auch schon gehört. Was 
würdest Du mir als modernen Nachfolgetyp für die alten ATMEGAs 
empfehlen?

Servus
Peter

von Thomas E. (thomase)


Lesenswert?

Peter Spiess schrieb:
> Hallo Thomas,
>
> Thomas Eckmann schrieb:
>> War da nicht irgendwas mit EEPROM-Adresse 0 bei den alten Gurken? Ich
>> meine natürlich bei den beliebten Klassikern.
>
> :-)
> Das mit dem Problem bei Adresse 0 habe ich auch schon gehört. Was
> würdest Du mir als modernen Nachfolgetyp für die alten ATMEGAs
> empfehlen?
>
> Servus
> Peter

Pinkompatibel zum 16er sind die 164, 324, 644 in der letzten Version 
jeweils als A oder PA und der 1284 und 1284P.

mfg.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Spiess schrieb:
> int8_t value = 0;
>   if (value > 70)

Falls die gelesene Zelle nicht initialisiert ist und 0xff enthält, wird 
valie zu -1 und damit der Vergleich nicht erfüllt.

von Peter S. (petersp)


Lesenswert?

Hallo Johann,

Johann L. schrieb:
> Peter Spiess schrieb:
>> int8_t value = 0;
>>   if (value > 70)
>
> Falls die gelesene Zelle nicht initialisiert ist und 0xff enthält, wird
> value zu -1 und damit der Vergleich nicht erfüllt.

ok, hast Du Recht. Wäre dann ein
1
uint8_t value = 0;

besser?

Servus
Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kommt ganz darauf an, was der Test value > 70 soll und wie value im 
weiteren Verlauf des Programms verwendet wird.

von Peter S. (petersp)


Lesenswert?

Johann L. schrieb:
> Kommt ganz darauf an, was der Test value > 70 soll und wie value im
> weiteren Verlauf des Programms verwendet wird.

Es geht um eine Glühkerzenregelung für Modellmotore. value wird mit 
einem Drehencoder eingestellt und kann Werte zwischen 20 ... 70 haben. 
Das wiederum bestimmt, wie hell die Glühkerze leuchtet.

Ursprünglich hatte ich vor (und möchte das auch noch verwirklichen), 
dass nach jedem Schreiben in eine EEPROM-Zelle die nächste Zelle 
genommen wird. Somit "verbrauche" ich nicht eine einzelne Zelle, sondern 
verteile die Schreibzyklen auf das gesamte EEPROM. Jede neu zu 
verwendende Zelle enthält 0xFF.

Wenn jetzt der Wert 0xFF gelesen wird, bekommt die Glühkerze zuviel 
Strom und brennt durch. Deshalb wollte ich sicherstellen, dass eine 
nicht initialisierte Zelle einen definierten Wert bekommt.

Servus
Peter

von Thomas E. (thomase)


Lesenswert?

Peter Spiess schrieb:
 > Ursprünglich hatte ich vor (und möchte das auch noch verwirklichen),
> dass nach jedem Schreiben in eine EEPROM-Zelle die nächste Zelle
> genommen wird. Somit "verbrauche" ich nicht eine einzelne Zelle, sondern
> verteile die Schreibzyklen auf das gesamte EEPROM. Jede neu zu
> verwendende Zelle enthält 0xFF.

Rein akademisch kann man das natürlich machen. Aber mehr als eine kleine 
Programmierübung ist das nicht.

Wenn sich der Wert durch Drehen am Encoder ändert, wird er 
abgespeichert.
Das muß aber nicht sofort passieren. Ich verbinde das mit einem Timer 
und prüfe 1s nachdem sich am Encoder nichts mehr getan hat, ob der Wert 
sich gegenüber dem EEPROM-Inhalt geändert hat. Klar, wenn in der 
Zwischenzeit der Akku schlapp macht(bla)...
Nur dann wird dieser auch abgespeichert. Die 100.000 Zyklen des EEPROMS 
beziehen sich auf das Löschen und sind in diesem Fall mehr als du jemals 
brauchen wirst. Wenn der täglich, auch Weihnachten, Silvester und Omas 
Geburtstag, 10 Mal geändert wird, sind das knapp 30 Jahre.

mfg.

von Peter S. (petersp)


Lesenswert?

Hallo Thomas,

Deine Berechnung ist ok :-) Ich sehe es als kleine Programmierübung, da 
ich noch nicht so fit in C bin.

Von den von Dir genannten Alternativcontrollern lasse ich mir bei meiner 
nächsten Bestellung einen zum Ausprobieren mitschicken.

Servus
Peter

von magic smoke (Gast)


Lesenswert?

Das Ding hat doch einen internen Brown-Out-Detektor. Schon mal 
ausprobiert? Stichwort BOD-Fuses.

von Peter S. (petersp)


Lesenswert?

Ja freilich, habe ich hier 
[[Beitrag "Re: ATMEGA16 - Probleme mit int. EEPROM"]] dann so gemacht. 
Seitdem funktioniert das Programm.

Servus
Peter

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.