Hallo,
ich hab ein Problem mit dem Watchdog des ATMega128. Das Problem ist das
der WD tlw. nach Tagen erst zuschlägt. Hab das MCUCSR ausgewertet und
festgestellt das es tatsächlich ein WD Reset war. Die Frage ist nur wie
finde ich am besten das Problem im Programm?? Hat jemand eine Idee wie
ich vorgehen könnte?
Der WD ist auf 2sec eingestellt und wird immer am Ende einer While
Schleife gelöscht.
Gruss Patrick
Patrick schrieb:> Der WD ist auf 2sec eingestellt und wird immer am Ende einer While> Schleife gelöscht.
LOL.
Anscheinend nicht.
Man darf WD auch ruhig jede ms rücksetzen, muss nicht bis zum
letzten Moment warten.
genau das ist die Frage .. wo ist der letzte Moment, ich hab den WD
Reset auch schon im Programm verstreut, an Stellen an denen ich dachte
es wäre vorteilhaft.. leider hatte das keine Verbesserung gebracht. Die
Verlängerung auf 2sec hatte auch nix gebracht, an irgendeiner Stelle
hängt sich das Programm auf und die würde ich gerne finden. Ich hab nur
noch keine Idee wie
Patrick schrieb:> Verlängerung auf 2sec hatte auch nix gebracht, an irgendeiner Stelle> hängt sich das Programm auf und die würde ich gerne finden. Ich hab nur> noch keine Idee wie
Eine volatile bei jedem WDR hochzählen und (mit ZeilenNr.) ausgeben
oder ins Eeprom schreiben.
n ist OK, zwischen n und n+1 ist der Übeltäter.
P.S.
Volatile dient dazu zu sehen wie lange das Ganze gedauert hat...
Marc V. schrieb:> Patrick schrieb:>> Verlängerung auf 2sec hatte auch nix gebracht, an irgendeiner Stelle>> hängt sich das Programm auf und die würde ich gerne finden. Ich hab nur>> noch keine Idee wie>> Eine volatile bei jedem WDR hochzählen und (mit ZeilenNr.) ausgeben> oder ins Eeprom schreiben.>> n ist OK, zwischen n und n+1 ist der Übeltäter.>> P.S.> Volatile dient dazu zu sehen wie lange das Ganze gedauert hat...
Ok eine Idee, hast du ein Bsp. wie ich das mache?
Du kannst statt des Watchdogreset den Watchdoginterrupt nehmen und dort
z.B. über die UART den SP und einen RAM-Dump ausgeben oder in einem
EEPROM speichern.
Aller Code darin muß inline sein, d.h. darf keine Funktionen aufrufen
und keine Stackvariablen anlegen, weil ja der Stack in den Wald zeigen
könnte.
Am besten schreibt man das in Assembler.
Solche Fehler, die nur selten auftreten, deuten darauf hin, daß
irgendein Pointer Dir den Stack zerschießt, weil außerhalb des
Datenformats geschrieben wird.
Statt auf den Fehler zu warten, kann es daher sinnvoller sein, den Code
auf solche Stellen abzuklopfen.
Es ist auch sinnvoll sein Programm in Zeitschlitze zu packen, Stichwort
Echtzeit. Dann hast du den absoluten Überblick wann was in deinem
Programm abgearbeitet wird, Hier mal ein Auszug:
Ingo L. schrieb:> Programm abgearbeitet wird, Hier mal ein Auszug:
1
if(Flags.LCD_Update){
2
Flags.LCD_Update=OFF;// <-----------
3
Update_LCD();
4
}
Das macht man normalerweise in umgekehrter Reihenfolge:
1
if(Flags.LCD_Update){
2
Update_LCD();
3
Flags.LCD_Update=OFF;// <-----------
4
}
Hat aber mit seinem konkretem Problem nichts zu tun, nur mit der
Art, wie Programme überhaupt geschrieben werden sollen - und da
gebe ich dir und peda Recht - besser vorher nachdenken als nachher
Haare raufen...
Peter D. schrieb:> z.B. über die UART den SP und einen RAM-Dump ausgeben oder in einem> EEPROM speichern.
Kann helfen, muss aber nicht...
Wenn ein Array deklariert wird und ein Pointer auf dieses Array
gleich hinterher, dann packt es der Compiler auch so ins RAM.
Werden Arraygrenzen verletzt, wird auch sofort der Arraypointer
ins Nirwana gelenkt und der Zirkus geht los.
Falls in einem loop reingeschrieben wird, kann es sein, dass der
Arraypointer genau auf loopcounter zeigt und dann wird es echt
lustig - der ganze RAM kann mit Fantasiewerten überschrieben werden.
Was ich sagen will, ist folgendes:
Ein Dump muss nicht unbedingt etwas sinnvolles zeigen, kommt darauf
an, welcher Mist vorher gebaut wurde.
Eine variable und ZeilenNr. im Eeprom oder über UART rausgegeben,
hilft da aber schon weiter, auch wenn ich so etwas nicht gerade
debuggen nenne...
> Statt auf den Fehler zu warten, kann es daher sinnvoller sein, den Code> auf solche Stellen abzuklopfen.
Dem kann ich nur zustimmen.
Das das Problem mit einem Pointer zusammenhängt habe ich auch schon in
Erwägung gezogen, es gibt in dem Programm aber nur einen einzigen
Pointer der dazu verwendet wird einen Frame über den UART versenden:
Ein RAM-Dump zeigt auch nur, wo der Fehler zuschlägt. Das ist aber fast
nie die Funktion, die den Fehler verursacht.
Ich fülle auch gerne den Stack beim Init mit 0x77. Dann kann man im
RAM-Dump sehen, wieviel Stack noch Reserve war.
Patrick schrieb:> Das das Problem mit einem Pointer zusammenhängt habe ich auch schon in> Erwägung gezogen, es gibt in dem Programm aber nur einen einzigen> Pointer der dazu verwendet wird einen Frame über den UART versenden:
Das Problem kann mit vielem zusammenhängen, nicht nur mit Pointer.
Es können blockierende Routinen, Deadlocks u.ä. sein, z.B.
Ohne Code kann dir das aber niemand genau sagen und da es sich um
eine M128 handelt, würde ich dir empfehlen, sich keine Mühe zu
machen, deinen Programm mit 123KB Code überhaupt hier hochzuladen...
Patrick schrieb:> es gibt in dem Programm aber nur einen einzigen> Pointer
Kann ich mir kaum vorstellen.
Es werden in Verbindung mit Cstrings und Arrays auch implizit Pointer
genutzt.
Es muss also nicht offensichtlich sein.
Ich hab mir das angeschaut den WD statt MCU Reset als Interrupt zu
verwenden, wäre nicht schlecht aber leider kann das mein ATMega128
nicht, es gibt keine Möglichkeit mit dem WDTCR Register auf Interrupt
umzuschalten.
Hi
Dann sollte es aber möglich sein, beim RESET (Int-Vector 0) das WDF
(WatchDog-Flag) auszulesen.
Wenn Dieses gesetzt ist, hat der WatchDog den Reset ausgelöst.
'Riecht' nach Stacküberlauf, denke mir aber, daß nicht (nur) in
Assembler geschrieben wurde, die benutzte Sprache wurde aber noch nicht
genannt oder wurde von mir übersehen.
Selber, Assembler, simuliere ich die Einzelfunktionen und schaue, ob der
StackPointer wieder zur Start-Position zurück findet (also PUSHs und
POPs gleich oft vorhanden sind ... teilweise lasse ich mir auch
Return-Werte auf dem Stack zurück, aber eine andere Geschichte).
Zum Eingrenzen des Fehler:
Erstelle Dir einen Ring-Puffer (10 Byte im RAM oder Programmspeicher
sollten reichen).
Vor jeder aufzurufenden Funktion schreibst Du in diesen Ringspeicher
eine Zahl (die Nummer der Funktion).
Wenn der WatchDog zugeschlagen hat, gibst Du diese 10 'Zahlen' immer
wieder per UART o.Ä. aus - so hast Du eine Chance, die Reihenfolge der
letzten 10 Funktionen zu sehen und kannst Diese 'von Hand'
durch-simulieren.
Die Funktionen, Die Dir den Ringspeicher vollschreiben (und den
entsprechenden Pointer versetzen), brauchen sich selber nicht in den
Ringspeicher eintragen ;)
MfG
Hallo,
ich glaube den Fehler gefunden zu haben. Vorweg es scheint kein Problem
mit der Software zu sein auch wenn der WD ausgelöst wird. Es war die
Spg. Versorgung des uC, trotz BrownOut Überwachung wird zuvor der WD
ausgelöst. Warum das passiert und nicht der BrownOut zuschlägt hab ich
nicht herausgefunden, aber nach dem ändern der Versorgung ist das
Problem nicht wieder aufgetreten.
Danke mal für die Tipps!
Patrick schrieb:> ISR(BADISR_vect)> {>> }>> und alles war gut :-)
Oh Gott, wirf Hirn.
Das ist ungefähr so, als wenn es durchs Dach regnet und Du keinen
Dachdecker rufst, sondern Dich mit dem Regenschirm ins Zimmer setzt.
Ein Fehler, den man ignoriert, fällt einem immer wieder auf die Nase.