PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Watchdog Interrupt?



Dunuin
12.12.2010, 13:02
Moin,

Ich bastle gerade mit der Bascom-Demo an einem Projekt, wo ein ATtiny2313 vier LEDs per PWM dimmen soll. Das klappt auch soweit mit der PWM, aber leider sind jetzt dadurch Timer0 und Timer1 blockiert.
Ich muss jetzt noch irgendwie die Zeit messen, was ich über Timer2 mit einem Timeroverflow machen wollte, der der immer ein Flag auf 1 setzt und eine Variable hochzählt.
Mir ist leider jetzt erst aufgefallen, dass der Tiny ja gar keinen Timer2 besitzt.

Dann habe ich im Datenblatt nach einer Alternative gesucht und habe gelesen, dass der Watchdogtimer alternativ zum Reset auch einen Interrupt auslösen kann.

Über Bascom kann ich aber wohl nur den Watchdog starten, zurücksetzen und den Prescaler definieren. Eine Einstellung als Interrupt geht wohl nicht und ein Interruptvektor für den Overflow konnte ich auch nicht finden.

Ich glaube ich muss folgendes machen, um das Register des Watchdogs auf Interrupt umzustellen:


Wdtcsr = &B01010000

Wenn ich das richtig verstanden habe, dann sollte der WDTimer damit alle 16ms einen Interrupt auslösen und nicht resetten.

Aber wie mache ich das jetzt mit dem Interrupt?

Der Vektor dafür hat die Nummer 19, ist an Programmadresse "0x0012" und Source ist "WDT OVERFLOW", laut Datenblatt.

Normalerweise würde ich das ja mit...


Enable Interrupts
Enable Vektorname
On Vektorname Isr_wdovf
Isr_wdovf:
Incr Zeit1
Zeitflag = 1
Return

...machen, aber den Vektor kennt Bascom ja nicht.

Hat da schon wer Erfahrungen gemacht?
Kann mir da wer helfen?

MfG

Dunuin

for_ro
12.12.2010, 13:31
Hallo Dunuin,
ich hätte jetzt sowas gemacht:
On WDT Wdt_isr

Allerdings musst du bei Änderung des WDTCSR Registers bedenken, dass du das Change bit setzen musst und dann innerhalb von 4 Takten deine Änderungen, also unmittelbar danach:
WDTCSR.WDCE = 1
WDTCSR = &B01000000

TobiKa
12.12.2010, 13:37
Wieso nicht mit einem Timer 2 Dinge zählen?!

Besserwessi
12.12.2010, 13:51
Vermutlich ist es besser einen der PWM timer mit zu nutzen. Außer der vielleicht etwas hohen Frequenz spricht nichts dagegen auch bei Timer 1 noch den Overflow Interrupt zu nutzen.

Das ändern der Watchdog timer Einstellungen über die Register geht so direkt nicht von BASIC aus - das schaft der Compiler nicht in den geforderten 4 Zyklen. Da müsste man schon inline ASM bemühen.

for_ro
12.12.2010, 14:03
Das ändern der Watchdog timer Einstellungen über die Register geht so direkt nicht von BASIC aus - das schaft der Compiler nicht in den geforderten 4 Zyklen. Da müsste man schon inline ASM bemühen.
Der Compiler braucht das auch nicht zu schaffen, das kann der µC sehr gut selber. Register setzen dauert exakt 2 Takte, also wo ist das Problem. Und das ist nichts anderes, als inline ASM.

Dunuin
12.12.2010, 14:27
Aha, dann werde ich das mal mit dem Timer1-Overflow versuchen. Wusste nicht, dass das auch noch geht, wenn ich den als PWM nutze.

Der Timer1 ist ja ein 10-Bit Timer, den ich als 8-Bit PWM eingestellt habe, da die 256 Abstufungen eigentlich reichen und Timer0 ja auch nur als 8-Bit PWM funktioniert.
Sehe ich das richtig, dass der dann immer nach 255 Schritten überläuft? Also immer von 65280 bis 65535 hochzählt?

Besserwessi
12.12.2010, 14:43
Ich glaube eher der Timer wird von 0 bis 255 laufen, ist aber eigentlich auch ziehmlich egal.
Beim PWM Mode kann man noch zwischen fast PWM und Phasenrichtigem PWM Wählen. Beim Phasensirchtigen PWM läuft der Timer abwechselnd hoch und runter - der Überlauf kommt dann nur alle 512 Takte.


Beim zugriff auch die Regster des WDT gibt es schon eine Schwierigkeit mit der Zeit: es müssen innerhalb der 4 Zyken 2 mal Werte geschrieben werden. Das ist in ASM kein Problem, weil man da beide Werte aus 2 CPU Registern schreiben kann. Beim Compiler ist es da nicht sicher das da nicht noch etwas dazwischen kommt, und sei es nur den 2 ten Wert ins CPU Register zu laden.

Dunuin
25.03.2011, 12:18
Moin, ich mal wieder. :-)

Jetzt stehe ich bei einem neuen Projekt wieder vor dem gleichen Problem, dass ich nicht weiß, wie ich unter Bascom den Interrupt des WDT nutzen soll.
Diesmal komme ich aber nicht drum herum, da ich im Energiespar-Modus die Zeit mitzählen muss und das höchstens über Timer2 gehen würde, der den uC aber zu oft aufwecken würde, dass die Batterie zu schnell leer geht.

Bascom Version ist 2.0.4.0 und ich nutze einen Atmega48V.

Also die Idee war, dass ich den WDT im "Hybrid-Modus" nutze, dass der also alle 8 Sekunden den uC aus dem Powerdown-Modus aufweckt und in der Interruptroutine die Byte-Variable "Zeit" um 1 erhöht, aber trotzdem noch den uC resettet, wenn sich dieser aufhängt. Wird leider alles nicht direkt von Bascom unterstützt, aber das Datenblatt meint dazu:


Bit 6 - WDIE: Watchdog Interrupt Enable
When this bit is written to one and the I-bit in the Status Register is set, the Watchdog Interrupt is
enabled. If WDE is cleared in combination with this setting, the Watchdog Timer is in Interrupt
Mode, and the corresponding interrupt is executed if time-out in the Watchdog Timer occurs.

If WDE is set, the Watchdog Timer is in Interrupt and System Reset Mode. The first time-out in
the Watchdog Timer will set WDIF. Executing the corresponding interrupt vector will clear WDIE
and WDIF automatically by hardware (the Watchdog goes to System Reset Mode). This is useful
for keeping the Watchdog Timer security while using the interrupt. To stay in Interrupt and
System Reset Mode, WDIE must be set after each interrupt. This should however not be done
within the interrupt service routine itself, as this might compromise the safety-function of the
Watchdog System Reset mode. If the interrupt is not executed before the next time-out, a System
Reset will be applied.

Bit 4 - WDCE: Watchdog Change Enable
This bit is used in timed sequences for changing WDE and prescaler bits. To clear the WDE bit,
and/or change the prescaler bits, WDCE must be set.
Once written to one, hardware will clear WDCE after four clock cycles.Das WDCE bit, wo man 4 Takte schnell sein muss, scheint ja nur für die 4 Prescalerbits und WDE gebraucht zu werden, was den WDT in den Resetmodus setzt.
Das sollte dann ja nicht das Problem sein, wenn man mit "Config Watchdog = 8192" den WDT einstellt, da der dann ja den richtigen Prescaler hat und im Reset-Modus arbeitet.

Aber was muss ich jetzt genau in Bascom machen, damit der WDT auch parallel als Interrupt arbeitet?
Direkt nach dem "Config Watchdog" nur noch per "Wdtcsr.6 = 1" WDIE auf 1 setzen und auch immer, wenn der WDT-Interrupt ausgelöst wird?

Und dann weiß ich immer noch nicht, was ich in Bascom machen muss, damit der WDT eine Interruptroutine auslöst, die dann meine Zeit-Variable hochzählt eine Flag-Variable setzt, damit im Hauptprogramm dann wieder WDIE auf 1 gesetzt wird.

Kann mir da jemand helfen?

Edit:
Falls jemand an der Lösung interessiert ist, so ging es:


$regfile = "m48def.dat" 'ATmega48V-10AU TQFP
$crystal = 1000000 '1 MHZ

Dim Zeit As Byte 'Wird alle 8 Sekunden um 1 erhöht
Dim Wdtflag As Byte 'Wird alle 8 Sek auf 1 gesetzt, zum anzeigen, dass die Watchdogtimer-ISR ausgelöst wurde und das WDIE Bit im WDTCSR Register wieder auf 1 gesetzt werden muss

Enable Interrupts
Config Watchdog = 8192 'Watchdog auf Resetmodus mit 8sek Zeit einstellen
Wdtcsr.wdie = 1 'WDIE Bit auf 1 setzen, damit beim WDT-Timeout ein Interrupt ausgeführt wird und kein Reset
Start Watchdog
On Wdt Isr_wdt

Wdtflag = 0
Zeit = 0

Do
If Wdtflag = 1 Then
Reset Watchdog
Wdtcsr.wdie = 1
Wdtflag = 0
End If
Loop

'Diese Interruptroutine wird beim Timeout vom Watchdogtimer ausgelöst und dient
' der Zeitmessung und dem Resetten des WDTs
Isr_wdt:
Wdtflag = 1
Incr Zeit
Return

lendl
26.02.2021, 09:57
Das ist genau das, was ich gesucht habe!
Leider bekomme ich es nicht zum Laufen. Mit einem xmega128a1 bekomme ich beim kompillieren immer diese Fehler:



Config Watchdog = 8000 'Watchdog auf Resetmodus mit 8sek Zeit einstellen
Wdtcsr.wdie = 1 'WDIE Bit auf 1 setzen, damit beim WDT-Timeout ein Interrupt ausgeführt wird und kein Reset
Start Watchdog
'On Wdt Isr_wdt


Fehler:
Getclass error [0]
Variable not dimensioned [0 -> 0]
Invalid Date typ [[0011]0[WDIE]]
Variable not dimensioned [0 -> 0]
Invalid Date typ [[0011]0[WDTCSR]]

Was mache ich denn da falsch?
Danke!

oberallgeier
26.02.2021, 11:14
Sorry - verwechselt.

Searcher
26.02.2021, 11:56
Config Watchdog = 8000 'Watchdog auf Resetmodus mit 8sek Zeit einstellen
Wdtcsr.wdie = 1 'WDIE Bit auf 1 setzen, damit beim WDT-Timeout ein Interrupt ausgeführt

Fehler: ...
Was mache ich denn da falsch?

Der Watchdog im XMEGA wird anders als im ATmega48 konfiguriert. Ein Watchdog-Interrupt kann dort nicht aktiviert werden.

Deine Compiler Fehler kommen daher, daß die entsprechenden Register und Bitnamen im XMEGA nicht existieren.

Auf der Microchip Seite gibt es die Application Note AN2654 zum XMEGA Watchdog.

https://www.microchip.com//wwwAppNotes/AppNotes.aspx?appnote=en591662

Gruß
Searcher

wkrug
27.02.2021, 10:06
Ich würde eine Zeitmessung eigentlich immer über einen Timer(Interrupt) machen.
Der Watchdog wäre für mich immer nur eine Notbremse, falls sich das Prog irgendwo aufhängt ( Stack Overflow, Warten auf ein Ereignis ).

Die Timer der AVR sind äusserst flexibel.
Wenn der Prescaler für die Anwendung passt kann so ein Timer auch durchaus bis zu 3 Aufgaben auf einmal bewältigen ( Zeit messen ( Input Capture ), PWM generieren, Timer Interrupts generieren ).

Zudem kann man einen Timer mit relativ hoher Taktfrequenz laufen lassen und im Overflow Interrupt Variablen runterzählen lassen ( frisst zwar viel Rechenzeit geht aber ).
Somit sind dann auch Messungen für unterschiedliche Zeitintervalle möglich.

stemmy
20.02.2022, 14:27
Als sehr einfach zu realisierende "Pi-mal-Daumen"-Zeitbasis, an die keine hohe Präzisionsforderung gestellt wird,
ist der WD-Timer sehr gut geeignet. Die anderen Timer bleiben dann anderweitig nutzbar.

Für die Attinys u.A. geht das auch ganz simpel:

Config watchdog = 8000 'nach meiner Erfahrung läuft der wd-Timer damit schon los, auch ohne "start"-Befehl
Set Wdtcr.wdie 'wd in Interrupt-Modus versetzen, statt reset-Modus


If Wdtcr.wdif = 1 Then 'zeitintervall abgelaufen
set Wdtcr.wdif ' das wdif-flag sofort wieder löschen, indem man es setzt
Incr wd_tick
end if


Damit wird die Zählvariable "wd_tick" jedesmal wenn das wdif-flag gesetzt wird incrementiert,
und das wdif_flag bis nach Ablauf des nächsten Zeit-Intervalls zurückgesetzt,
ohne dass man eine WD-Interruptroutine aufrufen bzw. ausführen muss. (= Polling)

Zu beachten ist, dass das vom Timer gesetzte wdif-flag dadurch gelöscht wird, dass man es setzt(!),
also mit einer 1 beschreibt, obwohl es schon gesetzt ist.

Man braucht hierbei auch keine 4-Takte-Sequenz einhalten, wie oft irrtümlich geschrieben wird.

Dieses einfache Polling des Interrupt-Flags geht auch bei anderen Timern oder anderen Interruptquellen, wenn man die zeitraubenden Pushs und Pops der Interruptroutinen vermeiden will.