PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Der Mysteriöse Watchdog



Icon2k
26.12.2010, 14:57
Hallo,
bin beim stöbern durch das ATmega32 Datenblatt zufällig auf den "Watchdog" gestoßen, aber mir verschliesst sich irgenwie der Sinn. Auch eine kurze Internetrecherche hat mir nicht weitergeholfen.
Habe ich das Richtig verstanden:
Der Watchdog wird ausgelößt sobald der uC nichts tut, zählt dann mit seinem eigenen 1MHz Takt eine vorbestimmte Zeit runter und resettet den uC, falls er sich immer noch nicht regt? Also ist der Watchdog eine externe Schaltung, die den uC, wenn er abstürzt einfach neu startet.

Richard
26.12.2010, 15:37
Man kann sich da ein retriggerbares Monoflop vorstellen, solange das Programm ordentlich läuft wird das Monoflopp immer regelmäßig getriggert.
Hängt das Programm fällt das Monoflop in seinen Standart (Ruhe) Zustand und löst dabei einen Reset aus.

Gruß Richard

TobiKa
26.12.2010, 15:40
Der Watchdog merkt nicht selbst ob der der µC sich aufgehängt hat.
Der Watchdog wartet eine bestimmte Zeit und resetet den Controller, wenn er bis der Zähler des Watchdogs nicht zurückgesetzt wurde.
Die meisten AVRs (die ich kenne) haben einen internen Watchdog.

Che Guevara
26.12.2010, 15:50
Hallo,

naja nicht ganz... Den Watchdog kann/muss man auf eine bestimme Zeit einstellen. Wenn er vor Ablauf dieser Zeit nicht wieder resetet wurde, dann resettet er den ganzen µC. Also wenn dein Programm in einer Schleife festhängt, dann wird der ganze µC resettet!

Gruß
Chris

Icon2k
26.12.2010, 16:12
Ahh ok, eigentlich ja recht sinvoll

021aet04
26.12.2010, 17:22
Rech sinvoll. habe ich schon eingesetzt (als Sicherheit). Teilweise haben Maschinen (mit SPS bzw PC-Steuerung) einen Watchdog. Falls die SPS den Watchdog nicht zurücksetzt wird die Maschine abgestellt (z.B. Notaus) und es kommt eine Alarmmeldung.

Bei den AVRs (zumindest beim Attiny44) kann man mit dem Watchdog in eine Interruptschleife springen. Es wird nicht unbedingt der µC resettet.

MfG Hannes

radbruch
26.12.2010, 17:58
Hallo


...kann man mit dem Watchdog in eine Interruptschleife springen.Das können wohl nur die kleinen Tinies, der 13er kann das auch. Bei dessen Watchdog lauert aber eine ganz versteckte Gefahr:


Note: If the Watchdog is accidentally enabled, for example by a runaway pointer or
brown-out condition, the device will be reset and the Watchdog Timer will stay enabled.
If the code is not set up to handle the Watchdog, this might lead to an eternal loop of
time-out resets. To avoid this situation, the application software should always clear the
Watchdog System Reset Flag (WDRF) and the WDE control bit in the initialisation routine,
even if the Watchdog is not in use.(Aus: https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=336549#336549)

Den entsprechenden Hinweis habe ich im Mega32-Datenblatt noch nicht entdeckt. Vermutlich habe ich mir aber vor ein paar Tagen durch einen verirrten Zeiger möglicherweise deshalb einen Mega8 abgeschossen. Die von Atmel für den Tiny13 gemachte Empfehlung habe ich bei den Megas natürlich nicht eingebaut. (btw. wüßte ich auch gar nicht, wie man das Setzen der WD-Bits soweit vorne ins Programm bekommt, dass es ausgeführt wird, bevor der WD bellt)

Gruß

mic

uwegw
27.12.2010, 00:24
(btw. wüßte ich auch gar nicht, wie man das Setzen der WD-Bits soweit vorne ins Programm bekommt, dass es ausgeführt wird, bevor der WD bellt)

Dafür gibt es die .init...-sections. Dort liegen der Startup-Code, den der gcc erzeugt. Einige davon sind standardmäßig leer und können für eigene Zwecke genutzt werden. Ein Beispiel für den Watchdog findet man hier ganz oben:
http://www.nongnu.org/avr-libc/user-manual/group__avr__watchdog.html

radbruch
27.12.2010, 17:07
Hallo

Danke für die Info. Würde das dann ausreichen um einen fälschlich aktivierten WD einzuschläfern?


void kill_WD(void) __attribute__((naked)) __attribute__((section(".init3")));
void kill_WD(void) { wdt_disable(); }

int main(void)
{
kill_WD();


Denn das wäre ja kein allzugroßer Aufwand :) Allerdings kommt mir das etwas seltsam vor.

Den Inhalt von MCUSR brauche ich ja nicht zu sichern, wenn mich der Grund für den letzten Reset nicht interessiert.

Gruß

mic

uwegw
27.12.2010, 18:12
Sollte so stimmen. Allerdings müsstest du kill_WD() in main() nicht nochmal aufrufen.

EDIT: nein, da fehlt noch was: das Watchdog-Reset-Flag im MCUSR muss auf Null gesetzt werden!

radbruch
27.12.2010, 18:40
Hallo

Nochmals danke. Der Aufruf in main() war auch das, was mir seltsam vorkam, weil hier die Initialisierung ja schon gelaufen ist. Mit dem Löschen des MCUSR-Registers sieht's dann so aus:


// WatchDog beim Initialisieren ausschalten
// https://www.roboternetz.de/phpBB2/viewtopic.php?p=531597#531597
void kill_WD(void) __attribute__((naked)) __attribute__((section(".init3")));
void kill_WD(void) { MCUSR = 0; wdt_disable(); }


Ich werde die zwei Zeilen mal einbauen und hoffe, dass ich nun keine Kontroller mehr töte.

Gruß

mic

[Edit]

cam.elf: file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
0: 12 c0 rjmp .+36 ; 0x26 <__ctors_end>
2: 28 c0 rjmp .+80 ; 0x54 <__bad_interrupt>
4: 27 c0 rjmp .+78 ; 0x54 <__bad_interrupt>
6: db c1 rjmp .+950 ; 0x3be <__vector_3>
8: fd c1 rjmp .+1018 ; 0x404 <__vector_4>
a: 24 c0 rjmp .+72 ; 0x54 <__bad_interrupt>
c: 23 c0 rjmp .+70 ; 0x54 <__bad_interrupt>
e: 22 c0 rjmp .+68 ; 0x54 <__bad_interrupt>
10: 21 c0 rjmp .+66 ; 0x54 <__bad_interrupt>
12: 20 c0 rjmp .+64 ; 0x54 <__bad_interrupt>
14: 1f c0 rjmp .+62 ; 0x54 <__bad_interrupt>
16: 1e c0 rjmp .+60 ; 0x54 <__bad_interrupt>
18: 1d c0 rjmp .+58 ; 0x54 <__bad_interrupt>
1a: 1c c0 rjmp .+56 ; 0x54 <__bad_interrupt>
1c: 1b c0 rjmp .+54 ; 0x54 <__bad_interrupt>
1e: 1a c0 rjmp .+52 ; 0x54 <__bad_interrupt>
20: 19 c0 rjmp .+50 ; 0x54 <__bad_interrupt>
22: 18 c0 rjmp .+48 ; 0x54 <__bad_interrupt>
24: 17 c0 rjmp .+46 ; 0x54 <__bad_interrupt>

00000026 <__ctors_end>:
26: 11 24 eor r1, r1
28: 1f be out 0x3f, r1 ; 63
2a: cf e5 ldi r28, 0x5F ; 95
2c: d4 e0 ldi r29, 0x04 ; 4
2e: de bf out 0x3e, r29 ; 62
30: cd bf out 0x3d, r28 ; 61

00000032 <kill_WD>:
}

// WatchDog beim Initialisieren ausschalten
// https://www.roboternetz.de/phpBB2/viewtopic.php?p=531597#531597
void kill_WD(void) __attribute__((naked)) __attribute__((section(".init3")));
void kill_WD(void) { MCUSR = 0; wdt_disable(); }
32: 14 be out 0x34, r1 ; 52


r1 hat nach eor r1, r1 null als Inhalt und wird an 0x34 ausgegeben. Das ist allerdings (beim Mega8) die Adresse des MCUCSR-Register. Aber ich nehme mal an, das ist richtig so ;)

Auf jeden Fall steht es recht weit vorne im Programm. Nach dem Initialisieren des SREG (0x3F) und dem Stackpointer (0x3E/3D) wird das MCUCSR gelöscht. Echt spitze :)