Wie wird eigentlich der Watchdog beim ATMEGA32 in C verwendet?
Ich habe mal ein wenig im Tutorial herumgeschaut, aber dort wurde mir
die Funktionsweise noch nicht ganz klar. Aus den Informationen habe ich
geschlossen, dass man am Anfang einmal wdt_enable(WDTO_2S); schreiben
muss, um den Watchdog einzuschalten. Muss man das vor dem Befehl sei();
machen oder danach (ich benutze noch timer-interrupts)? Dann dachte ich
mir, dass ich den Watchdog in jedem Timerzyklus zurücksetze mit
wdt_reset();. Aber irgendwie klappt das nicht.
Habe nämlich das Problem, dass mein Mikrocontroller aus für mich
unerklärlichen Gründen nach unregelmäßiger Laufzeit abstützt. Wenn ich
sei(); aus meinem Programm herauskommentiere und nur in der
Hauptschleife eine LED toggle, gehts.
Im Programm ist sonst nur noch der 16-bit Timer verwendet und die
serielle Schnittstelle ohne Empfangsinterrupt. Kann mir jemand
weiterhelfen, also zunächst mit dem Watchdog und ggf. noch mit dem
Abstürzproblem?
"Absturzprobleme" nur bei sei() enabled lassen üblicherweise 2 Ursachen
vermuten:
1.) Der Watchdog macht das, was er soll: Er schlägt zu, wenn er nicht
rechtzeitig wieder resetted wurde. Absichtlich wohl eher selten, ist
eher das Ergebnis einer deutlich längeren Laufzeit in Unterprogrammen,
Interrupthandlern etc.. Wenn das wie bei Dir in unregelmäßigen Abständen
passiert, hört sich das Plausibel an. Irgendwo wird mal etwas länger als
sonst gebraucht und schwups ...
2.) Es wird irgendwo ein anderer Interrupt aktiviert und bei sei() ohne
zugehörigem aktivierten ISR-Handler gibt es einen reset. Auch das kann
bei unregelmäßigen Resets die Ursache sein; irgendwann kommt mal ein
Interrupt, den Du nicht geplant hast. Das läßt sich durch leere
Interrupthandler oder einen "Allescatcher"
Dank Lutz für die Tipps - werde ich morgen mal testen. Aber dazu habe
ich doch noch ein paar Fragen: Unter Absturz verstehe ich ein
stehenbleiben, d.h. in meinem Toggle-LED-Programm bleibt die Led an.
Passiert so etwas bei einem Reset? Dachte eigentlich immer, dass bei
einem Reset der µC neugestartet wird, also das Programm von vorne
beginnt.
Fängt der "Allescatcher" alle Interrupts ab, d.h. auch die, die ich
definiert habe, oder nur die übrigen?
Was genau meinst du mit "deutlich längerer Laufzeit in Unterprogrammen"?
>Unter Absturz verstehe ich ein stehenbleiben, d.h. in meinem>Toggle-LED-Programm bleibt die Led an.
gut zu wissen
>Passiert so etwas bei einem Reset? Dachte eigentlich immer, dass>bei einem Reset der µC neugestartet wird, also das Programm von>vorne beginnt.
Nein. Wie Du schon schriebst, bei einem Reset fängt das Programm von
vorne an. Zuerst wird natürlich der µC in seinen Resetzustand (Register
haben dann die "initial values") versetzt, und der steht im Datenblatt
(jedenfalls kein normaler Port steht auf 1). Jetzt hängt es natürlich
von Deinem Programm und dem Verlauf ab, ob es von außen überhaupt zu
unterscheiden ist ob der µC wirklich "stehen bleibt" (das würde auf eine
versehentliche Endlosschleife schließen lassen) oder nach dem reset
anscheinend sofort wieder den gleichen Fehler macht und an gleicher
Stelle resettet (was dann, je nach Frequenz/Dauer eines Resetzyklus,
auch wie Dauerleuchten einer LED aussehen kann).
>Fängt der "Allescatcher" alle Interrupts ab, d.h. auch die,>die ich definiert habe, oder nur die übrigen?
Er fängt nur die von Dir nicht definierten Interrupts ab. Es gibt auch
noch empty interrupt-Handler
EMPTY_INTERRUPT(ADC_vect);
die mußt Du aber für jeden einzelnen Interrupt definieren (hier z.B.
ADC), die machen gar nix an Funktion. Aber les Dir das mal in Ruhe in
dem Link durch; da kommst Du eh nicht drum rum.
>Was genau meinst du mit "deutlich längerer Laufzeit in Unterprogrammen"?
Unterprogramme ist natürlich syntaktisch verkehrt, ich meine Funktionen.
Du kannst ja z.B. auf irgendwas in den Funktionen reagieren, z.B. bei
Timerinterrupt lese Port_sowieso ein. Wenn der Wert x ist, mache das,
wenn y, jenes etc. Und da kann theoretisch ja mal was kommen, was länger
dauert als Du dachtest. Nicht unbedingt in einer Abfrage, aber
irgendeine wilde Kombination. Und ein Takt zu spät reicht dem watchdog
...
>Und ein Takt zu spät reicht dem watchdog
Ach so, mit Watchdog meintest du das. Habe ich denn den Watchdog richtig
verwendet, bzw. ist mein Verständnis davon aus meinem ersten Posting
richtig?
>das würde auf eine versehentliche Endlosschleife schließen lassen
Das dachte ich auch, weshalb ich in alle while-Schleifen einen
Abbruch-Zähler eingebaut habe, der eine zusätzliche Bedingung darstellt.
Nachdem das aber nicht ging, habe ich mal alle Schleifen auskommentiert
und das Programm sehr stark reduziert, was leider nicht zum Erfolg
führte.
>Habe ich denn den Watchdog richtig verwendet, bzw. ist mein>Verständnis davon aus meinem ersten Posting richtig?
Grundsätzlich ja. Der Watchdog sollte (wie so ziemlich jede
"Peripherie", hier aber nicht zwingend) vor dem aktivieren konfiguriert
sein; in diesem Fall also wdt_enable(Zeit) und dann erst sei(). sei()
darf aber auch nicht zu spät nach dem Aktivieren kommen, denn die Zeit
des watchdog beginnt natürlich mit wdt_enable() zu Laufen! Wenn Du z.B.
mit wdt_enable(WDTO_2S) 2 Sekunden einstellst, dann alles mögliche
machst und der wdt_reset() zu spät kommt, hast Du nach sei() natürlich
gleich schon Feierabend. Die Zeit kannst allerdings nur Du bestimmen, da
nur Du Dein Programm kennst und wie lange es auch im worst case braucht
(die schon beschriebenen Funktionen, die mal längern dauern könnten und
mal nicht), bis der nächste wdt_reset() aufgerufen wird.
Es gibt laut Datenblatt ja mehrere Werte (steht aber auch in de Doku der
avr-libc wie im Link), die man einstellen kann, bis der watchdog
zuschnappt.
Vielleicht solltest Du Dein Programm mal im Debugger bzw. Simulator
(z.B. AVR-Studio, sofern Du Windowsbelastet bist) durchgehen und mal
verfolgen, was dort so passiert.
Viel Erfolg und schönes Wochenende.