Forum: Mikrocontroller und Digitale Elektronik ATMEGA128 Watchdog Fehler finden?


von Patrick (Gast)


Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Patrick (Gast)


Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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...

: Bearbeitet durch User
von Patrick (Gast)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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.

von Ingo L. (corrtexx)


Lesenswert?

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:
1
if ( Flags.Gui ){
2
      Flags.Gui = OFF;
3
      Gui();
4
    }
5
    //////////////////////////////////////////////////////////////////////////
6
    if ( Flags.LCD_Update ){
7
      Flags.LCD_Update = OFF;
8
      Update_LCD();
9
    }
10
    //////////////////////////////////////////////////////////////////////////
11
    if ( Flags.Calc_Values ){
12
      static uint8_t TemperaturDelay = 0;
13
      Flags.Calc_Values = OFF;
14
      uint16_t Temp = 0;
15
           ...
16
    //////////////////////////////////////////////////////////////////////////
17
    if ( Flags.ReInit_LCD ){
18
      Flags.ReInit_LCD = OFF;
19
      Init_LCD();
20
       }
Mehr Überblick geht fast nicht. Ich bin absoluter Gegner von "ich 
schreib alles untereinander weg, passt schon..."

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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...

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Patrick (Gast)


Lesenswert?

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:

1
void SendFTmsg(int8_t *pMsg, unsigned long dwToWrite)

der Aufruf erfolgt dann so:
1
SendFTmsg(cTxBuf, 9);

von Peter D. (peda)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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...

von Einer K. (Gast)


Lesenswert?

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.

von Patrick (Gast)


Lesenswert?

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.

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

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

von Patrick (Gast)


Lesenswert?

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!

von Patrick (Gast)


Lesenswert?

Hallo, es war doch nicht die Spg.Versorgung. Der Fehler war das es einen 
Interrupt gab für den keine ISR vorhanden war.
1
ISR(BADISR_vect)
2
{
3
  
4
}

und alles war gut :-)

Gruss Patrick

von Peter D. (peda)


Lesenswert?

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.

von Sascha W. (sascha-w)


Lesenswert?

Patrick schrieb:
>
1
> ISR(BADISR_vect)
2
> {
3
> 
4
> }
5
>
das mag zwar eine Lösung sein, in erster Line solltest du aber den nicht 
benötigten Interrupt abschalten.

Sascha

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.