Forum: www.mikrocontroller.net WDT Beitrag im AVR-Tutorial gewünscht?


von Z8 (Gast)


Lesenswert?

ja oder nein?

von Skua (Gast)


Lesenswert?

Ja

von Karl H. (kbuchegg)


Lesenswert?

Jeder Beitrag im Tutorial ist erwünscht.
Nur denk bitte drann es handelt sich um ein Tutorial für Einsteiger. Das 
heißt, du must die Dinge so schreiben, wie du sie deiner kleinen 
12-jährigen Schwester erklären würdest. Grade soviele technische 
Details, dass man die Zusammenhänge gut sehen kann. Unwichtiges kann 
erst mal außen vor bleiben, sonst wird der Artikel überfrachtet.

Am besten sind immer möglichst vollständige Beispiele. Im 
Assembler-Tutorial ist alles auf einen Mega8 mit 4Mhz Taktfrequenz 
ausgelegt. Deine Testprogramme zu Hause unbedingt testen und danach das 
Timing auf 4Mhz umrechnen.

Schau dir auch auf anderen Tutorial-Seiten an, wie die neue Seite in die 
Kette der einzelnen Tutoriumsbeiträge eingefügt wird. Und auf das 
'Inhaltsverzeichnis' auf der ersten Seite nicht vergessen.

Im C-Tutorium das eigene Ego über Bord werfen und im Code-Stil bitte an 
den Rest des Tutoriums anpassen (Variablennamen, Einrückungen, 
Klammernsetzung, Leerzeichen, ...)

Zu guter letzt: vielen Dank, daß du bereit bist das Tutorium mit einem 
neuen Beitrag zu bereichern.

von Z8 (Gast)


Lesenswert?

würde jetzt mal als Präambel schreiben:

"
ACHTUNG!!!

Der WDT ist dafür bestimmt, unnormale Programmzustände zu
entdecken und zu beseitigen, dem µC also aus der Klemme zu
helfen.

NUR bei getesteten Software- und Hardwaredesigns
anwenden!

Der WDT ist kein Allheilmittel für Testfaule!
"

mfg Z8

Ist das OK so?

von Hannes Lux (Gast)


Lesenswert?

> Ist das OK so?

Ja, so ungefähr habe ich das schon öfters von PeDa gelesen. ;-)

...

von Klaus (Gast)


Lesenswert?

vorläufiger Eintwurf WDT:
----------------------------------------------------------------

ACHTUNG!!!

Der WDT ist dafür bestimmt, unnormale Programmzustände zu
entdecken und zu beseitigen, dem µC also aus der Klemme zu
helfen.

NUR bei getesteten Software- und Hardwaredesigns
anwenden!

Der WDT ist kein Allheilmittel für Testfaule!
----------------------------------------------------------------
Ein WDT ist ein Timer, der überwacht, wie lange eine Aktion maximal
dauern darf. Wird die Zeit überschritten, löst der WDT ein RESET aus.

Der WDT wird durch das Watchdog Timer Control Register – WDTCR
gesteuert.

BIT  7  6  5  4  3  2  1  0
  -   -  -  WDCE  WDE  WDP2  WDP1  WDP0

BIT 4 : Watchdog Change Enable
BIT 3 : Watchdog Enable

BIT   2  1  0  Time-out nach ms
----------------------------------------------------------------
  0  0  0  16,3
  0  0  1  32,5
  0  1  0  65
  0  1  1  130
  1  0  0  260
  1  0  1  520
  1  1  0  1100
  1  1  1  2100


Am Einfachsten läßt es sich durch ein kleines Programmbeispiel 
demonstrieren.

Ein ATmega 8 wird mit 1 MHZ des internen Taktgenerators mit einer
Startup-Zeit von 64 ms getaktet. Die WDTON-Fuse ist gesetzt (WDT 
aktiviert).
An Port B ist eine LED angschlossen (PIN egal).

<avrasm>
.include "m8def.inc"

; ATMaga8L mit internen 1 MHz getaktet + 64 ms Startuptime
; WDTON aktiviert!

.def Temp1 = R16
.def SubCount = R17


.org 0x0000
        rjmp    Reset               ; Reset Handler
.org OC1Aaddr
        rjmp    timer1_compare      ; Timer Compare Handler

Reset:
        ldi     Temp1, LOW(RAMEND)  ; Stackpointer initialisieren
        out     SPL, Temp1
        ldi     Temp1, HIGH(RAMEND)
        out     SPH, Temp1

  ldi     Temp1, 0xFF         ; Port B auf Ausgang
        out     DDRB, Temp1

        ldi     Temp1, high(10000 - 1)
        out     OCR1AH, temp1
        ldi     Temp1, low(10000 - 1)
        out     OCR1AL, temp1
                                    ; CTC Modus einschalten
                                    ; Vorteiler auf 1
        ldi     Temp1, ( 1 << WGM12 ) | ( 1 << CS10 )
        out     TCCR1B, temp1

        ldi     Temp1, 1 << OCIE1A  ; OCIE1A: Interrupt bei Timer 
Compare
        out     TIMSK, temp1

        ; kann auch weggelasen werden, da nach einem Reset das Register
        ; auf 0x00 steht, WDT Reset nach 16ms
        ldi Temp1, (0<<WDCE)|(0<<WDE)|(0<<WDP2)|(0<<WDP1)|(0<<WDP0)
        out WDTCR, Temp1

        sei

Mainloop:
        rjmp    Mainloop

timer1_compare:                     ; Timer 1 Output Compare Handler

        ;** findet 100 x pro  Sekunde statt (10 ms)
        wdr                         ; Watch-Dog-Reset

        inc     SubCount            ; Wenn dies nicht der 50. Interrupt
        cpi     SubCount, 50        ; ist, dann passiert gar nichts
        brne    exit_isr

        ;** findet 2 x pro  Sekunde statt (500ms)
        clr     SubCount

  ;** Port B umschalten
  in      Temp1, PinB
  com     Temp1
  out     PortB, Temp1

exit_isr:
        reti                        ; das wars. Interrupt ist fertig

</avrasm>


Der Timer 1 läuft im CTC - Modus mit einer Frequenz von 100 Hz (10 ms).
Durch den Soft-Subcounter wird die Frequenz auf 2 Hz geteilt und
jeweils nach 500 ms das Port B negiert. Da die LED in diesem Beispiel
nach 500 ms jeweils ein- und ausgeschalten wird, blinkt sie mit einer
Frequenz von 1 Hz. Der WDT wird nach jeweils 10 ms zurückgesetzt, so
dass er keinen RESET auslösen kann.

Wird jetzt der Befehl WDR auskommentiert, führt der WDT nach 16 ms
einen RESET aus. Die LED blinkt nun, bedingt durch die Startup-Zeit
von 64 ms und einem Time-out von 16ms mit rund 6 Hz.

1/(64ms + 16ms) ~ 12 Hz (halbe Periode)

Der WDT läßt sich auch softwaremäßig durch Setzen des WDE - Bits
im WDTCR Register aktivieren.

<avrasm>
WDT_on:

  in Temp1, WDTCR      ; Write logical one to WDCE and WDE
  ori Temp1, (1<<WDE)
  out WDTCR, Temp1
  ret
</avrasm>


Dieses hat den Vorteil, dass man ihn
auch softwaremäßig wieder deaktivieren kann.

Ein Deaktivieren des WDTs ist nicht möglich, wenn die WDTON - Fuse 
gesetzt ist!

Das softwaremäßige Deaktivieren verlangt allerdings eine besondere
Deaktivierungssequenz.

<avrasm>
WDT_off:

  WDR        ; reset WDT

  in Temp1, WDTCR      ; Write logical one to WDCE and WDE
  ori Temp1, (1<<WDCE)|(1<<WDE)
  out WDTCR, Temp1

  ldi Temp1, (0<<WDE)    ; Turn off WDT
  out WDTCR, Temp1
  ret
</avrasm>

wird nicht WDCE und WDE in einem Zug vor dem Deaktivieren
auf 1 gesetzt, hat das Rücksetzen des WDE-Bits keine Wirkung und
der WDT läuft munter weiter!

von Benedikt K. (benedikt)


Lesenswert?

Was mir jetzt spontan auffällt: Das WDR im Timerinterrupt (auch wenn 
dieser in diesem Beispiel nur als Timingquelle dient) ist eine schlechte 
Idee. Der Interrupt läuft meist nämlich noch, wenn der Rest schon lange 
hängt.
Sowas verleitet dazu, das WDR in einen Timer Interrupt zu packen.
Besser wäre vielleicht ein Beispiel von einer klassischen Mainloop in 
der mehrere Funktionen aufgerufen werden und am Ende der Schleife dann 
das WDR erfolgt. In dem Beispiel können die Funktionen ja aus einfachen 
Delay Schleifen als Ersatz für die Laufzeit irgendeines anderen Codes 
stehen.
Und eine von diesen Funktionen hat halt einen Bug so dass diese 
irgendwann mal hängen bleibt, oder zu lange benötigt, so dass der WDT 
zuschlägt.

Da die Timerinit in diesem Beispiel auch mehr Platz benötigen als die 
WDT Init, geht diese im Code irgendwie etwas unter. Ich würde daher 
garkeinen Timer verwenden.

Vielleicht sollte man auch noch erwähnen, dass der WDT nach einem Reset 
(also auch über das Flashen einer neuen Software hinweg!) aktiv bleibt, 
wenn er einmal an war, und danach mit der kürzesten Zeit weiterläuft. Da 
fallen immer wieder Leute drauf rein (ich auch), oder momentan hier:
Beitrag "Watchdog beendet Programm, aber startet nicht neu"
Das steht nämlich nicht explizit im Datenblatt, sondern man kann es nur 
anhand der Defaultwerte der Bits entnehmen, was viele übersehen.
Vor allem wenn man z.B. in C programmiert und die Makros des GCC dafür 
verwendet...

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Vorschlag oben umgesetzt: AVR-Tutorial: Watchdog

von Z8 (Gast)


Lesenswert?

Hi  Benedikt K.

>Was mir jetzt spontan auffällt: Das WDR im Timerinterrupt (auch wenn
>dieser in diesem Beispiel nur als Timingquelle dient) ist eine schlechte
>Idee. Der Interrupt läuft meist nämlich noch, wenn der Rest schon lange
>hängt.

Der µC kann sich aber auch in einer Timer ISR aufhängen!
So zB wenn er anstatt mit reti nur mit ret beendet wird
(keine erneute Int.- freigabe) oder sich innerhalb der ISR
eine Endlosschleife befindet. Eine WDT - RESET Simulation im Mainloop
ist schwierig, da der µC nach einem WDT - RESET auf jeden Fall
wieder im Mainloop landet.

oder sollte ich das so verstehen?:

WDT auf 1,1s initialiesieren

mainloop:
  rcall delay1000      ; 1000ms warten
  LED einschalten

  wdr

  rcall delay1000      ; 1000ms warten
  LED ausschalten

  rjmp    Mainloop


man würde, glaube ich, einen deutlichen Unterschied
der Zeiten (An/Aus) sehen, wenn man wdr auskommentiert.

Gruß Z8

von Z8 (Gast)


Lesenswert?

Hi  Stefan,

der Artikel war noch nicht soweit! :)

von Benedikt K. (benedikt)


Lesenswert?

Z8 wrote:
> Der µC kann sich aber auch in einer Timer ISR aufhängen!

Klar kann er, nur wird man das schnell merken. Der WDT wäre dann genau 
das was er nicht sein soll: Eine Lösung für einen schweren 
Softwarefehler.
Einen Stacküber/Unterlauf oder ähnliches fängt ein WDR im Timerinterrupt 
dagegen nicht ab, denn der Interrupt läuft mit einer eingestellten 
Frequenz weiter. Und sowas dürften, denke ich, genau die nur schwer zu 
erkennenden Probleme sein, bei denen ein Watchdog sinnvoll ist. Wobei 
ein Stacküberlauf natürlich auch meist ein Softwarefehler ist, den man 
schon bei der Programmierung hätte erkennen können (jetzt mal von 
rekursiven Funktionen und ähnlichem abgesehen).

> Eine WDT - RESET Simulation im Mainloop
> ist schwierig, da der µC nach einem WDT - RESET auf jeden Fall
> wieder im Mainloop landet.
>
> oder sollte ich das so verstehen?:

In etwa so wie du geschrieben hast, nur etwas allgemeiner:

WDT auf 1,1s initialiesieren

Mainloop:

  LED=1
  rcall function1
  rcall function2
  rcall function3
  LED=0

  rcall delay500      ; 500ms warten (um die LED sichtbar blinken zu 
lassen)

  wdr
  rjmp    Mainloop

function1:
; irgendeine Funktion
  rcall delay100      ; 100ms warten
ret

function2:
; irgendeine andere Funktion
  rcall delay100      ; 100ms warten
ret

function3:
; noch eine andere Funktion
  inc     SubCount            ; Wenn dies nicht der 10. Durchlauf
  cpi     SubCount, 50        ; ist, dann passiert gar nichts
  breq crash
ret

crash:
  rjmp crash

Alternativ kann man crash auch durch eine weitere Wartzeit ersetzen so 
dass die WD Zeit überschritten wird.
Das ganze ist natürlich nur ein Vorschlag, da dies die typische 
Anwendung des WDT etwas besser zeigt als in einem Timerinterrupt.

Die LED sollte etwa mit 1,4Hz blinken. Sobald der Fehler zuschlägt, 
bleibt die LED für etwa 1s an und dann beginnt das ganze von vorne.
Die LED symbolisiert dann quasi die Zeit in der der µC aktiv am Rechnen 
ist.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Z8 wrote:

> der Artikel war noch nicht soweit! :)

Deshalb steht im Artikel am Anfang, dass der Artikel im entstehen ist 
und die Diskussion hier geführt wird.

Die Diskussion ist IMHO etwas einfacher, wenn es bereits eine 
Zusammenfassung und eine Struktur gibt. Und das Schöne am Wiki ist ja, 
dass man den Artikel nach und nach ausbauen kann und immer einen 
kompletten Block hat. Bei der Diskussion in einem Thread kann sich 
einiges zerfretteln.

Bei den Beispielen oder der Einführung/Erläuterung wünsche ich mir 
"etwas praktisches", d.h. wo man den WDT sinnvoll anwendet. Das 
derzeitige Beispiel zeigt zwar schön wie der WDT arbeitet, aber ich 
vermisse den Praxisbezug. Besonders, wenn man die Anmerkung (kein Ersatz 
für Testfaule) berücksichtigt.

von Z8 (Gast)


Lesenswert?

Hi Stefan,

das ist ja fast schon high checking. :)

Herzlichen Dank!

Z8

von Z8 (Gast)


Lesenswert?

Danke Andreas! für das "t" :)

von ich der Gast (Gast)


Lesenswert?

Xcus wenn ich störe,
meine Auffassung ist jedoch dahingehend das ein Watchdog hauptsächlich 
zum abfangen unvorhersehbare EMV-Störungen dienen sollte. Er sollte also 
in solch einem Fall das System in einen sicheren Zustand bringen,
Fehlermeldung und Stop
oder
Fehlermeldung und Neustart

Also gehört er in den Mainloop

Sicherlich zu viel für ein Tutorial dieses komplett zu erörtern aber 
einmal kurz darauf ansprechen sollte man doch.
Ansonsten geht es hier eher darum die eigentliche Funktion nahezubringen 
da seid ihr schon gut dabei.
Weiter so

von Karl H. (kbuchegg)


Lesenswert?

Ich hätte das auch ohne Timer demonstriet
(Teil der Tutoriumshardwareausstattung sind ja auch Taster)

Ich hätte ein Progrmm gemacht, das beim Loslaufen mal ein paar Led wild 
blinken lässt. So als Zeichen: Jetzt gehts los!

Dann in der Mainloop einen Taster abfragen
Nicht gedrückt landet dann in einer Funktionalität in der der WDT 
ständig resettet wird und daher nichts passiert. (Was weiss ich 
regelmässiges Blinken mit x Hz)

Ist der Taster gedrückt gehts in eine andere Funktionalität, in der im 
Prinzip das gleiche gemacht wird, nur unterbleibt der WDT Reset.

Das kann man jetzt dem Leser als die fehlerhafte Funktion verkaufen und 
durch das Led Geflacker am Anfang kann er erkennen, dass der µC resettet 
wurde.

von Gast (Gast)


Lesenswert?

1. Hilfreich wäre meines Erachtens auch, wenn das Beispiel noch mit der 
Auswertung des WDT-Reset ergänzt würde, d.h. man erkennt, ob es sich um 
einen normalen Reset oder ein WDT-Reset handelt. Ich habe es wie folgt 
probiert, funktioniert aber nur nach der Initialisierung der Ports und 
des Stackpointers, habe keine Ahnung warum.

  in temp1,MCUCSR      ;MCU Control und Statusregister lesen
  sbrs temp1,WDRF      ;Prüfen ob Watchdog-Restart erfolgte
  rjmp reset           ;nein: Normalstart
  cbr temp1,1<<WDRF
  out MCUCSR, temp1    ;WDR-Flag zurücksetzen
  rjmp wdrReset        ;WDR-Start


2. Weiterhin könnte man zeigen, wie mit einer Variablen, die einen 
Fehlercode beinhaltet die Auswertung noch verfeinert werden kann. Man 
könnte dazu ein Beispiel generieren, bei dem innerhalb einer bestimmten 
zeit ein Hardwareereignis eintreten soll oder eine Taste gedrückt wird. 
Jedes Ereignis enthält einen Code und führt zu einem WDR-Reset, der wie 
oben ausgewertet wird und zusätzlich die Statusvariable auswertet. Würde 
so etwas funktioniern? D.h. bleibt der Inhalt der Statusvariable durch 
den WDR erhalten?

3. "WDT gezielt zum Reset verwenden" sollte für Anfänger direkt ein 
Beispiel enthalten. Ich würde es so machen:
  cli
  rjmp PC

4. Ist ldi Temp1, (0<<WDE) nicht das gleiche wie clr Temp1 ?

von Z8 (Gast)


Lesenswert?

Hi Gast,

keiner hindert Dich dieses "einzubauen"!
Punkt 1-3 finde ich sehr sinnvoll.

Punkt 4 lass weg. (der Übersicht halber). Z8

von Z8 (Gast)


Lesenswert?

Danke Gast (Gast),

Änderungen passen.

mfg Z8

von Fantastic F. (flood1k4)


Lesenswert?

hallo, hab bisschen was angepasst:

1. erster absatz:
war ein wenig komisch formuliert, es wird ja eigentlich nicht das 
programm resetet, sondern der µC

2. Steuerung:
übersichtlicher formatiert und bisschen was ergänzt
(z.B heißt das WDCE auch beim ATmega32 anders und die time-out zeit
hängt auch vom wdt-osc ab.)

hoffe es ist so oke, grüße!

von Michael H. (michael_h45)


Lesenswert?

Das wär mal was für die Änderungsbeschreibung gewesen ^^

von wolf (Gast)


Lesenswert?

ich weiss, der letzte Beitrag ist schon ein paar Jahre her, vielleicht 
zur Ergaenzung:
Bei neueren AVR (z.B. Atmega162) wurde die Vorgehensweise zur 
Einstellung des Vorteilers (Prescaler) geaendert:

in einem Befehl ist WDCE und WDE im Register WDTCR auf 1 zu setzen
innerhalb der naechsten 4 Prozessortakte muss in einem Befehl WDE auf 1 
und WDP2..0 auf den gewuenschten Vorteiler geschrieben werden, 
andernfalls laeuft der WD mit der kuerzesten Resetzeit.

Also: (Bsp. fuer 2sec WDR)

ldi temp, (1<<WDCE)|(1<<WDE)     ;alternativ: ldi temp, 0x18
out WDTCR, temp
ldi temp, (1<<WDE)|(1<<WDP2)|(1<<WDP1)|(1<<WDP0)
                                 ;alternativ: ldi temp, 0x0F
out     WDTCR, temp

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.