Ich habe in einer Anlage einen Mikrocontroller ATMEGA32A mit externem Quarz am laufen.
Für diverse Kalibrier-Aufgaben speichere ich dort per einmaligem Befehl insgesamt 4 Werte ins EEprom. Diese Werte werden dann bei jedem Programmstart (also nach Einschalten der Anlage) einmalig aus dem EEprom ausgelesen und zur Weiterberechnung im MC verwendet (Ablage im RAM).
Nun kommt es alle paar Monate einmal vor, dass nach dem Einschalten der Anlage plötzlich völlig falsche, korrupte Daten in den vier Variablen-Addressen im EEprom stehen.
Brown-Out-Detection ist aktiv und auf 4,0V eingestellt.
Ich konnte den Fehler bisher nicht gezielt reproduzieren (z.B durch mehrfaches Ein- und Ausschalten der Versorgungsspannung)
Hat jmd. eine Idee woran dieses sporadische Verhalten liegen könnte?
Ein EEProm Schreibbefehl wird wie gesagt nur einmalig auf Anweisung ausgeführt, und der Fehler trat immer nach Einschalten der Anlage auf.
Ich suche nach einer Möglichkeit den Fehler zu verstehen, um ihn dann mit entsprechenden Maßnahmen zu beheben.
Ich würde mich sehr über ein paar Ratschläge freuen. :)
Bei älteren AVRs war ein Problem, dass bei schlechter Spannungsversorgung der Controller nicht mehr richtig funktionierte und irgendwelche Befehlssequenzen ausführte, zum Beispiel auch solche, die den EEPROM schreiben.
Betroffen war vor allem Adresse 0, weil das der Reset-Wert für die EEPROM Adresses ist. Lösung war, die EEPROM-Daten an anderer Adresse anfangen zu lassen als an Adresse 0, etwa per -Wl,--section-start,.eeprom=0x810001 bei Verwendung von avr-gcc, so dass die EEPROM-Daten an Adresse 1 beginnen.
Eigentlich sollten diese Probleme mit einer funktionierenden BrownOut Erkennung / Behandlung nicht mehr auftreten; einen wirklichen Ratschlag hab ich daher nicht. Ausser eben nochmals die Fuses zu checken, evtl. auch "Slow Rising Power" zu verwenden. BODLEVEL=0 (4V, programmed), BODEN=0 (BOD enabled).
Interessant wäre auch zu wissen, ob nur Adresse 0 betroffen ist oder auch andere Adressen. Vielleicht bringt auch die Reset-Ursache Hinweise, die man möglichst früh aus MCUCSR ausliest (und danach MCUCSR auf 0 setzt für den nächsten Reset).
BOD schlägt nur zu, wenn VCC ne gewisse Zeit lang under BOD-Level ist, BrownOut hilft also nicht gegen Transienten auf der Spannungsversorgung wenn ich es richtig verstehe.
BrownOutDetection erzeugt - wie ich aus dem Datenblatt entnommen habe - einen Reset. Wenn also mehrere Zellen beschrieben werden, bricht der Vorgang eventuell in der Mitte des Vorgangs ab. Dann passen die Daten nicht mehr zueinander. Ein ähnliches Problem habe ich vor vielen Jahren so gelöst, dass die VCC-Spannung (oder - noch besser - die Spannung aus der VCC gewonnen wird) überwacht wird. Vor jedem Schreibvorgang wird geprüft, ob die Spannung über dem Grenzwert liegt und nur dann wird der Schreibvorgang begonnen. Ein großer Elko stellte sicher, dass die Spannung am Ende des Schreibvorganges noch hoch genug war, den Prozessor am Laufen zu halten. (Natürlich darf der Schreibvorgang nicht durch andere Aktivitäten wie Interrupts o.ä. verlängert werden.)
Sind die Fusebits auf Full-Swing und maximale Resetzeit gesetzt?
Schaltest Du Netzspannung oder hohe Ströme (Motoren) in der Nähe des MCs?
Warum nimmst Du nicht den moderneren ATmega324P?
Wenn das EEPROM genutzt wird,
sind ein paar Vorsichtsmaßnahmen
zu beachten.
In stark gefilterten
Spannungsversorgungen neigt UCC
dazu, sehr langsam zu steigen
bzw. zu fallen,
wenn die Spannungsversorgung ein-
bzw. ausgeschaltet wird. Das
heißt, dass der
Baustein für eine gewisse
(verhaeltnismäßig lange) Zeit in
einem Spannungsbereich arbeitet,
der kleiner als das spezifizierte
Minimum ist, in der der Takt
arbeitet. Wie in solchen
Fällen ein Fehlverhalteverhindert
werden kann, ist unter
Schutzmaßnahmen beschrieben.
8.4.2 Verfälschten EEPROM vermeiden
In Zuständen,
in denen UCC zu niedrig ist,
um die CPU und das EEPROM
richtig arbeiten zu lassen,
können die EEPROM-Daten
verfälscht werden. Dies
gilt auch für externe EEPROMs.
Daher sind in beiden Fällen die
gleichen schaltungstechnischen
Lösungen erforderlich.
Ein Verfälschen der EEPROM-Daten
kann durch zwei Situationen ausgelöst werden,
in denen UCC zu niedrig ist. Erstens benötigt ein regulärer Schreibvorgang eine Mindestspannung, um einen korrekten Schreibvorgang durchzuführen. Zweitens kann es dazu kommen, dass die CPU selbst in der Ausführung der Befehle unsauber arbeitet, wenn die Versorgungsspannung zu gering ist.
Das Verfälschen der EEPROM-Daten kann auf einfache Weise verhindert werden, wenn folgende Design-Empfehlungen angewendet werden.
Den RESET-Eingang auf Low halten, solange die Spannungsversorgung unzureichend ist. Dies kann durch einen externen Resetbaustein erfolgen oder durch die
interne Unterspannungsüberwachung. Wenn der Level der internen
Unterspannungsdetektors nicht ausreicht, kann auch eine externe Resetschaltung verwendet werden, die einen Spannungsabfall erkennt. Wenn ein Reset während eines laufenden Schreibvorganges
auftritt, so wird dieser noch zu Ende geführt, vorausgesetzt die
Versorgungsspannung ist noch
ausreichend.
Erstes Wort (Adresse) und viertes Wort werden als "Dummy" im EEProm verwendet,
Wort 2 und 3 sind die "wichtigen" Werte.
Die Werte sind Kalibrierwerte, die zur Berechnung einer Kraft notwendig sind.
Der Atmega32A sitzt auf einer Platine, die per CAN-Bus an eine übergeordnete Steuerung angebunden ist.
Auf der Platine sitzt außerdem Messelektronik für eine Wägezelle und ein Motortreiber für einen Schrittmotor mit Getriebe.
Die Werte werden anfangs mit sinnvollen Standardwerten im EEprom vorbelegt (nach Aufspielen des Programms)
Wenn von der übergeordneten Steuerung ein Kalibrier-Befehl via CAN-Bus kommt, dann werden die neu ermittelten Werte des Atmega32A ins EEprom geschrieben (Alte Werte werden überschrieben)
Der Schreibbefehl in EEProm wird also nur sehr selten ausgeführt, das Einlesen der Werte aus dem EEprom jedoch bei jedem Hochlaufen.
Du könntest mal überlegen, ob Du statt des alten Mega32A einen neueren Mega 324P(A) oder 644P(A) einsetzen kannst. Der ist pinkompatibel, kann mehr und sollte weniger Bugs haben.
Es kann also, rein theoretisch, sein, dass das gar nichts mit dem Aus/Ein-Schalten zu tun hat, sondern dass irgendwann im laufenden Betrieb fälschlicherweise die EEPROM-Schreibroutine mit unsinnigen Daten ausgeführt wird.
einen Wechsel des Controllers habe ich zwar schon überlegt, allerdings möchte ich erst einmal das Problem verstehen und der Tausch soll erst der letzte Lösungsschritt sein.
Im laufenden Betrieb ist alles bestens, würde hier ein Fehler passieren, dann würde die Messung der Wägezellen ausfallen und automatisch der Fehler auffallen.
Die verstellten Werte sind bisher immer nach Einschalten der Anlage aufgefallen, da die Messwerte völlig unsinnig waren und die Anlage nicht gestartet ist.
Programmablauf ist wie folgt:
In der Main initialisiere ich einmalig die Werte aus dem EEProm:
//Werte aus EEPROM auslesen
Wert_0 = eeprom_read_word(&Wert_0_eeprom);
Wert_x = eeprom_read_word(&Wert_x_eeprom);
im Hauptprogramm wird quasi mit jedem Durchlauf die Kalibrierfunktion aufgerufen, innerhalb dieser Funktion wird der Befehl zum Kalibrieren und weitere Bedingungen abgefragt. Wenn alle Bedingungen erfüllt sind, wird der aktuelle Wert ins EEProm geschrieben.
Der Werte-Bereich für den Eintrag ist außerdem mit Ober-und Untergrenze versehen, so dass sich der zu schreibende Wert immer innerhalb einer Vorgabe befindet. -> Die falschen Werte im EEprom liegen weit außerhalb dieser Wertebereiche.
zB.: Untergrenze für Wort 2 ist 45, Obergrenze ist 2200. Wert im EEprom ist aber 65535.
Wenn von der übergeordneten Steuerung ein Kalibrier-Befehl via CAN-Bus
kommt, dann werden die neu ermittelten Werte des Atmega32A ins EEprom
geschrieben (Alte Werte werden überschrieben)
Der Schreibbefehl in EEProm wird also nur sehr selten ausgeführt, das
Einlesen der Werte aus dem EEprom jedoch bei jedem Hochlaufen.
Kannst du das wirklich so genau sagen, dass nur selten geschrieben wird?
Was wäre wenn die übergeordnete Steueruung meint, öfter kalibrieren zu wollen?
Ich hatte auch schon mal ähnliche Probleme mit dem internen EEPROM an einem Mega32.
Meine Lösung war nach vielen erfolglosen Versuchen:
3 weitere Kopien der Daten ablegen und beim Einlesen zu prüfen, ob alle konsistent sind. Falls nicht, wird der am häufigsten vorkommende Wert genommen und die kaputten Kopien damit überschrieben.
Mit externen EEPROMS war das nie ein Problem.
Externer Spannungsmonitor a la MCP130T hat auch zur Verbesserung beigetragen.
Ich hatte auch schon mal ähnliche Probleme mit dem internen EEPROM an
einem Mega32.
Meine Lösung war nach vielen erfolglosen Versuchen:
3 weitere Kopien der Daten ablegen und beim Einlesen zu prüfen, ob alle
konsistent sind. Falls nicht, wird der am häufigsten vorkommende Wert
genommen und die kaputten Kopien damit überschrieben.
Bei mir war es ein ..128 und ich hatte die Werte insgesamt dreimal auf verschiedenen Seiten auf 0xnXX im EEPROM abgelegt und mit einer Prüfsumme versehen. Das Problem war damit abgehakt.
Ich habe auch immer mindestens eine Kopie im Eeprom.
Und jede Kopie wird einzeln noch mit einem CRC-16 gesichert. Damit kann man leicht prüfen, ob der Datensatz noch stimmt.
Bei einer anderen Anwendung kommt noch ein Zeitstempel dazu. Wenn beim Schreiben etwas schief geht, dann kann die ältere Kopie verwendet werden.
Im laufenden Betrieb ist alles bestens, würde hier ein Fehler passieren,
dann würde die Messung der Wägezellen ausfallen und automatisch der
Fehler auffallen.
Diese Schlussfolgerung stimmt so nicht. Du arbeitest ja im Betrieb nur mit den Daten aus dem RAM. Wenn sich da im EEPROM etwas ändert, merkst du das erst beim nächsten Hochfahren.
Eine Frage dazu noch. Die Kal-Daten werden laut deiner Aussage ja selten geschrieben und nur einmal am Anfang gelesen, aber gibt es darüberhinaus weitere Daten im EEPROM auf die im laufenden Betrieb öfter zugegriffen wird? EEPROM lesen/schreiben?.
Ich hatte auch schon mal ähnliche Probleme mit dem internen EEPROM an
einem Mega32.
Meine Lösung war nach vielen erfolglosen Versuchen:
3 weitere Kopien der Daten ablegen und beim Einlesen zu prüfen, ob alle
konsistent sind. Falls nicht, wird der am häufigsten vorkommende Wert
genommen und die kaputten Kopien damit überschrieben.
Bei mir war es ein ..128 und ich hatte die Werte insgesamt dreimal auf
verschiedenen Seiten auf 0xnXX im EEPROM abgelegt und mit einer
Prüfsumme versehen. Das Problem war damit abgehakt.
Genau das wollte ich auch gerade vorschlagen, eine Prüfsumme für den Datenblock, diesen mehrfach ablegen und beim Einlesen eine Mehrheitsentscheidung. Ich würde noch etwas weitergehen, und nach aussen signalisieren wenn die Blöcke unterschiedlich waren, bzw. die unterschiedlichen Blöcke irgendwo abspeichern und auslesbar machen. Vielleicht kann man dann anhand dieser Daten noch etwas Fehleranalyse betreiben.
Wenn ein Problem aufgrund von einer geringen Auftretenswahrscheinlichkeit (alle paar Monate) oder unklarer Randbedingungen (wie fährt die Spannung hoch, gibt es Spikes ...) nicht zu finden ist, hilft nur noch Mitigation.
Alternative Lösung: Program Flash!
Wenn die Kalibrierwerte eh nur einmal geschrieben werden und dann fest sind, dann könntest Du sie ja nicht ins EEPROM schreiben, sondern in die letzte Page des Program Flash (oder die letzte Page vor dem Bootloader-Bereich, wenn Du einen Bootloader hast). Die Schreib/Löschzylen von Flash sind zwar begrenzt, aber für Deine spezielle Anwendung spielt das ja keine Rolle.
Damit wären aber die Adressen 0 und 1 gleichzeitig betroffen und
gelöscht...
Wert im EEprom ist aber 65535.
Ist das im Fehlerfall immer der Fall?
Ben B. schrieb:
4 Werte ins EEprom.
4 Stück 16-Bit Werte?
dass nach dem Einschalten der Anlage plötzlich völlig falsche, korrupte
Daten in den vier Variablen-Addressen im EEprom stehen.
In allen 8 Bytes gleichzeitig?
Oder ist auch mal nur 1 einzelnes Byte der 8 betroffen?
Ich schreibe quasi immer Worte (je 2Bytes) ins EEprom.
Wort 1 = Dummy Variable
Wort 2 = Variable für Wert 0
Wort 3 = Variable für Wert X
Wort 4 = Dummy Variable
Ich habe nicht jeden Fehlerfall so genau untersucht, da ich zunächst von einem fehlerhaften Kalibrierbefehl ausging.
Allerdings waren beim letzten mal Dummy 1 und 4, sowie Wort 3 völlig falsch. Wort 2 könnte richtig sein, er lag zumindest innerhalb der Grenzwerte.
Kannst du das wirklich so genau sagen, dass nur selten geschrieben wird?
Was wäre wenn die übergeordnete Steueruung meint, öfter kalibrieren zu
wollen?
In diesem Fall würde ich den Wert der Wägezelle auslesen und als Kalibrierwert ins EEprom speichern. Die Routine prüft aber auf Ober- und Untergrenze, der Wert im EEprom lag deutlich außerhalb der Grenzen.
Ich könnte aber mal die Gesamtanzahl der Kalibrierbefehle über eine gewisse Zeit tracken.
Diese Schlussfolgerung stimmt so nicht. Du arbeitest ja im Betrieb nur
mit den Daten aus dem RAM. Wenn sich da im EEPROM etwas ändert, merkst
du das erst beim nächsten Hochfahren.
Eine Frage dazu noch. Die Kal-Daten werden laut deiner Aussage ja selten
geschrieben und nur einmal am Anfang gelesen, aber gibt es darüberhinaus
weitere Daten im EEPROM auf die im laufenden Betrieb öfter zugegriffen
wird? EEPROM lesen/schreiben?.
Das ist ein guter und berechtigter Einwand. Es könnte dann durchaus auch sein, dass das EEprom schon während des Betriebs korrupte Daten ablegt, aber der RAM noch richtige Wert hat.
Die 4 oben genannten Worte sind die einzigen Variablen, die ins EEprom gespeichert werden.
Ich hatte auch schon mal ähnliche Probleme mit dem internen EEPROM an
einem Mega32.
Meine Lösung war nach vielen erfolglosen Versuchen:
3 weitere Kopien der Daten ablegen und beim Einlesen zu prüfen, ob alle
konsistent sind. Falls nicht, wird der am häufigsten vorkommende Wert
genommen und die kaputten Kopien damit überschrieben.
Diesen Vorschlag haben wir intern auch diskutiert. Nur da ich nicht weis, was im EEprom passiert, habe ich etwas Bedenken, dass dann alle drei Kopien falsch sein könnten. Welchen Wert nimmt man dann? Eine Re-Kalibration würde in diesem Fall auch wieder notwendig werden.
Das könnte tatsächlich eine Alternative sein. Da die Schreibbefehle wirklich sehr selten sind (würde sagen in der Lebenszeit des Bauteils maximal 100 Schreibbefehle - wenn überhaupt), könnte ich diesen Weg beschreiten. Gibts bei dieser Lösung irgendwelche nennenswerten Nachteile?
Ich danke euch schon einmal hiermit für die super Hilfestellungen und Anregungen. Ihr seid Spitze! :)
Das könnte tatsächlich eine Alternative sein. Da die Schreibbefehle
wirklich sehr selten sind (würde sagen in der Lebenszeit des Bauteils
maximal 100 Schreibbefehle - wenn überhaupt), könnte ich diesen Weg
beschreiten. Gibts bei dieser Lösung irgendwelche nennenswerten
Nachteile?
Die kleinste Einheit, die Du löschen, oder schreiben kannst, ist eine Page (64 Worte zu je 16 Bit).
Du musst die zu beschreibende Page zuerst löschen, bevor du sie schreiben kannst.
Wenn der eigentlich Befehl zum Kopieren der Page aus dem internen Buffer ins Flash oder der Befehl zum Löschen einer Page gegeben wird, steht der Prozessor für die Dauer dieses Vorgangs.
Das sind die Nachteile. Da Du eh eine ganze Page schreiben musst, kannst Du ruhig noch eine CRC oder so dazupacken.
Defaultmäßig sind die Flashzellen auf 0xffff, also alle Bits gesetzt.
Da ich eher einen Programmfehler vermute, klingt diese Alternative für mich nach "den Teufel mit Beelzebub austreiben".
"CRC" - zeigt erstmal auch nur einen Fehlerfall auf, aber das ist dann ja bereits bekannt.
"CRC" - zeigt erstmal auch nur einen Fehlerfall auf
Was heißt bei Dir denn "auch nur"?
Daß man besser mehrere Datensätze abspeichert, hast Du gelesen?
Die älteren AVRs brauchten nicht immer einen blöden Programmierer, um Daten im EEPROM zu zerschießen.
Natürlich ist es viel besser, die Hardware komplett umzustricken, wenn einfache Lösungen zu schwer zu verstehen sind.
Wenn ich bei meinem PC "auch nur" einmal Error 404 lese, kaufe ich mir immer einen neuen Rechner.
Du könntest mal überlegen, ob Du statt des alten Mega32A
einen neueren Mega 324P(A) oder 644P(A) einsetzen kannst.
Der ist pinkompatibel, kann mehr und sollte weniger Bugs haben.
Da sind wir einer Meinung, ich fand den Vorschlag auch nicht gut; zumal in den Errata des ATmega32A nichts Einschlägiges zu finden ist.
(Das "Reading EEPROM by using ST or STS to set EERE bit triggers unexpected interrupt request" wird's ja wohl kaum sein)
Probiere mal vor die 100nF Kerkos bei VCC und AVCC... noch kleinen Elko 10uF aus.
Außerdem könntest du vor dem Schreiben die Interrupts ausschalten nicht das dir vielleicht ein Register in einer Interruptroutine verdreht wird weil du nicht gepushed und gepoped hast.
Ob es ein SW-Fehler ist, kannst Du ganz leicht heraufinden. Entferne den Schreibcode aus dem Programm und belege den EEPROM mittels EEP-Datei beim Programmieren. Bleibt er dann erhalten, mußt Du in der SW den Fehler suchen.
Für zusätzlichen Sicherheit kann man noch das Adreßregister nach jedem EEPROM lesen/schreiben und nach Reset auf eine unbenutzte Adresse setzen.
Und wie gesagt, die CKOPT-Fuse wirkt Wunder. Sie macht den Quarz deutlich stabiler, wenn es nicht auf das letzte µA ankommt.
... Adreßregister nach jedem EEPROM lesen/schreiben
und nach Reset auf eine unbenutzte Adresse setzen.
So habe ich es auch immer gehalten (& BOD) und nie EEPROM-Probleme gehabt bei den kleinen Brüdern ATmega16 und ATmega16A; zumindest wurden mir keine gemeldet, und rund tausend Anwendungen sind immerhin draußen.
Und wie gesagt, die CKOPT-Fuse wirkt Wunder. Sie macht den Quarz
deutlich stabiler, wenn es nicht auf das letzte µA ankommt.
Bei 4 MHz eigentlich noch nicht, ist aber einen Versuch wert.
Bei >= 16 MHz und nicht gesetzter CKOPT gibt es jedoch die merkwürdigsten Fehler.
Vielleicht auch noch die Amplituden an XTAL1 und XTAL2 kontrollieren, daß sie nicht allzu klein sind.