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:
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.
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.
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.
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 ...
Stefan Collings