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"
1 | #include <avr/interrupt.h> |
2 | |
3 | ISR(BADISR_vect) |
4 | {
|
5 | // user code here
|
6 | }
|
ja mal von Dir ausschließen. Die avr-libc http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html ist 'ne feine Sache.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.