EEPROM-Lese-/Schreibfehler auf dsPIC

Ich verwende einen Microchip dsPIC30F6012a. Ich habe diesen Chip auf mehreren Leiterplatten, auf denen alle dieselbe Software ausführen, und beobachte auf allen dasselbe Problem. Dies impliziert ein systemisches Problem, kein einmaliges Produktionsproblem. Das Problem ist auch reproduzierbar, was bedeutet, dass ich in der Lage sein sollte, es zu töten, wenn ich weiß, wo ich suchen muss. Aber ich habe immer noch überraschende Schwierigkeiten beim Debuggen der Anwendung.

Die zu testende Platine akzeptiert 24 V, die durch einen V7805 auf 5 V herabgesetzt werden. Der Chip läuft auf seinem internen Oszillator mit einer 16x PLL, was eine Betriebsgeschwindigkeit von ~29,5 MIPS ergibt. Der relevante Code auf diesem Board ist im Wesentlichen sehr einfach: aufwachen, Daten aus dem EEPROM lesen, dann eine Endlosschleife eingeben. Unterbrechen Sie jede Millisekunde, beobachten Sie einige Umgebungsdaten und schreiben Sie einen aktualisierten Wert in das EEPROM. Es gibt noch andere Dinge, aber das Problem tritt auch dann auf, wenn der Code ohne Bezug auskommentiert ist, sodass ich ziemlich sicher sein kann, dass er für das vorliegende Problem nicht relevant ist.

Im Allgemeinen wacht das Board in 95 % der Fälle mit dem richtigen Wert im Speicher auf und fährt mit seiner Arbeit fort. Die anderen 5% der Zeit wacht es jedoch mit einem falschen Wert auf. Insbesondere wacht es mit einer bitumgedrehten Version der Daten auf, die es haben sollte. Es ist ein vorzeichenloses Vier-Byte-Long, das ich beobachte, und entweder das obere oder das untere Wort des Long kann umgedreht werden. Zum Beispiel wird 10 zu 2^16-10, was später zu 2^32-10 wird. Ich kann den Fehler reproduzieren, indem ich die Stromversorgung mehrere Dutzend Mal manuell aus- und wieder einschalte, aber das ist nicht sehr konsistent, und mein Schaltfinger wird abgenutzt.

Um das Problem kontrolliert zu reproduzieren, habe ich eine zweite Platine gebaut, die die 24V-Versorgung der zu testenden Platine ansteuert. (Ein weiterer dsPIC, der einen Darlington-Optokoppler ansteuert.) Die Testerplatine schaltet die 24 V für 1,5 Sekunden aus (lang genug, damit die 5-V-Schiene auf praktisch 0 abfällt und dort für eine Sekunde bleibt), und schaltet dann die 24 V für eine konfigurierbare Zeitdauer ein . Mit einer Einschaltzeit von ungefähr 520 ms kann ich diesen EEPROM-Fehler jedes Mal innerhalb von fünf Einschaltzyklen reproduzieren.

Die 5V-Schiene verhält sich vernünftig. Es pendelt sich innerhalb von 1 ms nach dem Einschalten bei 5 V ein, mit vielleicht 0,4 V Überschwingen, vorausgesetzt, ich kann meinem Oszilloskop vertrauen. Beim Ausschalten fällt es exponentiell auf 0 V ab und erreicht 1 V innerhalb von 50 ms. Ich habe keine Build-Warnungen, die relevant erscheinen, nur unbenutzte Variablen und fehlende Zeilenumbrüche am Ende von Dateien.

Ich habe mehrere Dinge ausprobiert:

  • Aktivieren/Deaktivieren des MCLR
  • Aktivieren/Deaktivieren des WDT
  • Codeschutz aktivieren/deaktivieren
  • Aktivieren/Deaktivieren/Ändern der Brownout-Erkennungsspannung
  • Aktivieren/Deaktivieren/Ändern des Einschalttimers
  • Unterschiedliche PLL-Einstellungen am internen Hauptoszillator
  • Anschließen/Trennen meines PICkit 3-Programmierers
  • Hinzufügen von 470 uF Kapazität zur 5-V-Schiene
  • Hinzufügen/Entfernen von 0,1 uF über den 4,7-k-Pullup auf meinem MCLR-Pin
  • Alle Interrupts im Code deaktivieren und nichts als EEPROM-Updates in der Hauptschleife belassen
  • Hinzufügen einer Verzögerung von 1,5 Sekunden zu meiner Startroutine, bevor ich mit dem Lesen des EEPROM beginne

Ich habe auch einen separaten Testcode geschrieben, der nichts anderes tut, als kontinuierlich Werte in das EEPROM zu schreiben und sie dann zurückzulesen, um sicherzustellen, dass sich der Wert nicht geändert hat. Zehntausende Iterationen ergaben keine Fehler. Alles, was ich daraus schließen kann, ist, dass beim Lesen oder Schreiben des EEPROM etwas schief geht, insbesondere beim Ein- und Ausschalten.

Ich verwende seit 2007 dieselben EEPROM-Bibliotheken. Ich habe gelegentlich Störungen gesehen, aber nichts Reproduzierbares. Den entsprechenden Code finden Sie hier:
http://srange.net/code/eeprom.c
http://srange.net/code/readEEByte.s
http://srange.net/code/eraseEEWord.s
http:/ /srange.net/code/writeEEWord.s

Ich habe EEPROM-Fehler schon früher in anderen Anwendungen gesehen, aber immer als einmalige Störungen, nichts so Reproduzierbares oder Konsistentes.

Hat jemand eine Ahnung, was los ist? Mir gehen die Dinge aus, die ich ausprobieren kann.

Hier finden Sie ein Update zur Lösung dieses Problems: electronic.stackexchange.com/questions/38083/…

Antworten (3)

Zwei Dinge fallen mir ein:

Erstens dauert ein Lösch-Schreib-Zyklus laut Datenblatt mindestens 0,8 ms und bis zu 2,6 ms. Sie sagen, dass Sie alle 1 ms einen Interrupt haben, der zu einem Schreibvorgang führen kann. Ich habe im Code gesehen, dass Sie Interrupts für Teile der Lösch- und für Teile der Schreibfunktion deaktivieren. Aber es kann immer noch zu lustigen Verschachtelungen der Funktionsaufrufe kommen. Vielleicht hilft es, wenn Sie Interrupts für die gesamte Sequenz von Löschen und Schreiben deaktivieren?

Zweitens - Sie möchten vielleicht schreiben, während der Strom ausfällt, und das EEPROM-Schreiben erfolgt genau in dem Moment, in dem die Versorgungsspannung unter die Betriebsspannung fällt. Sie können versuchen, die Versorgungsspannung zu überwachen und einen Schreibvorgang abzulehnen, wenn sie beispielsweise unter 4,5 V liegt. Dies setzt voraus, dass sie lange genug über 2,7 V als minimale Betriebsspannung bleibt, und die Brown-Out-Erkennung so eingestellt ist, dass sie nur unterhalb dieses Punktes auslöst.

Du bist in der Nähe! Der Zyklus ist Löschen->Schreiben. Wenn also zwischen Löschen und Schreiben ein Stromausfall auftritt, verlieren Sie Ihre Daten. Meine erste Lösung bestand darin, das EEPROM in mehrere redundante Kopien aufzuteilen, die automatisch auf Inkonsistenzen überprüft werden. Aber da das 3/4 meines EEPROMs verbraucht hat, ersetze ich das durch einen einfachen Schreibpuffer. Der Puffer ist ein spezieller EEPROM-Block, der die zu schreibenden Daten, die zu schreibende Adresse und ein Flag enthält, das anzeigt, dass das Schreiben noch nicht abgeschlossen ist. Dies sollte das Problem beheben und gleichzeitig viel weniger Platz beanspruchen.
Ich kann jetzt bestätigen, dass mein pufferbasierter Ansatz funktioniert und kein Datenverlust durch asynchrones Herunterfahren zwischen Löschen und Schreiben entsteht.

Sie haben sich viele mögliche Hardwareprobleme angesehen. Das ist in Ordnung, aber dies ist höchstwahrscheinlich ein Firmware-Fehler.

Leider ist Ihr Quellcode schlecht dokumentiert und so formatiert, dass er visuell schwer zu verfolgen ist. Ihre erste Datei enthält oben die Deklaration externer Routinen:

void readEEByte (unsigned int, unsigned int, void*);
void eraseEEWord (unsigned int, unsigned int);
void writeEEWord(unsigned int, unsigned int, void*);

Es ist nicht nur eine schlechte Idee, Deklarationen wie diese privat in Client-Modulen zu platzieren, es ist kein einziger Kommentar in Sicht! Wir können anhand ihres Namens nur erahnen, was Sie mit diesen Routinen beabsichtigen, und die Aufrufargumente sind vollständig undokumentiert. Weiter in dieser Datei haben Sie verschiedene Zeilen, die mit "//" beginnen, und eine ganze Zeile mit Gleichheitszeichen. Diese fügen visuelle Unordnung hinzu und machen es zu schwierig, dem Code zu folgen.

Sie können sagen, dass dies für die Funktionsweise des Codes nicht von Bedeutung ist. Schlechte Programmierpraktiken wie diese spielen jedoch eine große Rolle. Sie führen dazu, dass der Code schlecht geschrieben ist und es schwierig ist, Fehler oder sogar das, was der Code tun soll, zu erkennen. All dies führt dazu, dass schwer zu findende Probleme lauern, wie Sie feststellen. Sie haben sogar selbst gesagt, dass Sie seit 2007 gelegentlich Störungen in diesem Code gesehen haben. Das hätte ein starker Hinweis auf einen Fehler sein müssen, möglicherweise sogar auf ein schlechtes Gesamtdesign.

Beheben Sie das Durcheinander, dokumentieren Sie alle Schnittstellen ordnungsgemäß und fügen Sie allgemeine Deklarationen in Include-Dateien ein, die Sie einmal schreiben und dann bei Bedarf referenzieren. Auch Ihre Aussage , dass ich keine Build-Warnungen habe, die relevant erscheinen, ist eine riesige rote Fahne. Beheben Sie erneut das Durcheinander. Gehen Sie beim Debuggen immer zuerst auf die leicht reproduzierbaren und behebbaren Probleme ein. Manchmal sind diese tatsächlich die Ursache für die schwerwiegenden Probleme, oder manchmal entdecken Sie bei der Behebung die Ursache anderer Probleme. Der Compiler warnt Sie vor Schlamperei auf dem Silbertablett. Was willst du noch? Sie sollten keine ungenutzten Variablen haben, weil sie bei jedem, der versucht, Ihren Code zu verstehen, Verwirrung stiften, und es gibt überhaupt keine Entschuldigung dafür, neue Zeilen zu verpassen. Beheben Sie erneut das offensichtliche Durcheinander, insbesondere bevor Sie andere bitten, sich Ihren Code anzusehen.

Sauberkeit und Liebe zum Detail sind wichtig . Eine Menge.

 

Mit dem Code hast du recht. Nur damit es klar ist, ich habe vor fünf Jahren angefangen, diesen Code zu verwenden, aber jemand anderes hat ihn geschrieben. Ich schreibe keine Sachen, die so aussehen. Ich sollte es noch reparieren, und es ist nicht gut, dass ich es nicht getan habe. Nur damit ich nicht wie ein ZIEMLICH so großer Trottel aussehe. :-)
Der Zugriff auf das interne EEPROM ist einfach. Für solch einfache Dinge ist es einfacher, Ihren eigenen Code zu schreiben, als herauszufinden, wie die Bugware eines anderen funktioniert, und sie dann zu patchen, bis sie zu funktionieren scheint. Lesen Sie das Datenblatt und schreiben Sie den Code. Du wärst in einer Stunde fertig.
Ich stimme Olin hier darin zu, dass es höchstwahrscheinlich Firmware ist. Der Teil Errata erwähnt, dass nichts mit dem EEPROM faul ist.
@Madmad - Errata-Blätter sagen vielleicht nicht, dass etwas mit dem Teil faul ist, aber sie werden niemals sagen, dass nichts faul ist :-)
@Remiel: Der technische Support wollte wahrscheinlich nicht mehr durch unordentlichen, schlecht dokumentierten Code waten als ich. Wenn Sie eine schlampige Präsentation machen, dreht sich die Diskussion (falls es überhaupt eine gibt) um die Schlamperei und Ihr ursprünglicher Punkt wird entführt. Es ist schwierig, sich zu erholen, selbst wenn Sie es irgendwann reparieren, weil die Leute Sie bis dahin bereits ausgeblendet haben. Außerdem hilft Ihnen das Argumentieren, dass der Chip schuld ist, nicht, Ihren Fehler zu finden, noch tun Sie irgendetwas, um die Leute dazu zu bringen, Sie ernst zu nehmen.
@stevenvh Mein Umgang mit Microchip und ihren FAEs war überwiegend positiv. Die Errata für die Teile, die ich verwendet habe, waren korrekt, und sie sind eingesprungen, um uns bei Problemen zu helfen, und haben oft Problemumgehungen für uns gefunden.

Ich hatte ein identisches Verhalten mit 4 Stück dsPIC30F6014A (von etwa 10 Stück, die in den letzten Monaten verwendet wurden). Die einzige Möglichkeit, die sporadische Datenbeschädigung während des Ausschaltens zu vermeiden, besteht darin, das MCLR kurz vor dem Herunterfahren auf Null zu setzen.

Offensichtlich ist dies in der Praxis nicht machbar, daher habe ich mich für den Austausch des "schlechten" dsPIC entschieden, falls jemand stattdessen eine andere Lösung hat ...

Warum wäre das nicht machbar? Das Erkennen von Stromausfällen wird viel getan, selbst um Daten in den letzten ms im EEPROM zu speichern.