ja oder nein?
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.
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?
> Ist das OK so?
Ja, so ungefähr habe ich das schon öfters von PeDa gelesen. ;-)
...
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!
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...
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
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.
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.
Hi Stefan, das ist ja fast schon high checking. :) Herzlichen Dank! Z8
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
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.
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 ?
Hi Gast, keiner hindert Dich dieses "einzubauen"! Punkt 1-3 finde ich sehr sinnvoll. Punkt 4 lass weg. (der Übersicht halber). Z8
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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.