Hello Matthias, > IIRC only the "disable watchdog" sequence is timing critical (the > 4 cpu cycles you mention). All other tasks can be performed at > lower speed, so a forth implementation should be fine.
My atmega328p seems to require any change to WDTCSR to be completed within 4 cycles (I have tried), so I do not think a pure forth solution (excluding using assembler.frt) is possible. > It would be a great contribution for the cookbook. Esp if it works with > Forth code. This made me think that writing 4 or 5 assembler words was not the best way. Instead, have one assembler word wd! to perform the timed write to WDTCSR and then have forth words for -wdt +wdt -wdi +wdi wd.delay! I think this was the approach (one assembler word) used in 2013 with assembler.frt so had I read it better I might have got there more quickly. https://sourceforge.net/p/amforth/mailman/message/31512894/ Included below are three files wdwrite.asm, wd.forth and wd-example.forth. Regarding wdwrite.asm, it is the first time I have used assembler since 1985. wd.forth has more comments than code and wd-example.forth may not be up to cookbook standards, though it has a number of examples. Many of these examples intentionally result in the avr microprocessor being reset on the watchdog timeout... ; wdwrite.asm ; ; VE_WDWRITE: .dw $ff03 .db "wd!" .dw VE_HEAD .set VE_HEAD = VE_WDWRITE XT_WDWRITE: .dw PFA_WDWRITE PFA_WDWRITE: in temp1,SREG push temp1 mov temp0, tosl cli ; Reset Watchdog Timer wdr ; Clear WDRF in MCUSR in temp1, MCUSR andi temp1, (0xff & (0<<WDRF)) out MCUSR, temp1 in_ temp1, WDTCSR ori temp1, (1<<WDCE) | (1<<WDE) out_ WDTCSR, temp1 out_ WDTCSR, temp0 loadtos pop temp1 out SREG,temp1 jmp_ DO_NEXT \ wd.forth --------------------------------------------------- \ Watchdog timer words \ based on mailing list contributions from Oct 2013 \ https://sourceforge.net/p/amforth/mailman/message/31512894/ \ ------------------------------------------------------------ \ DOCS \ build AmForth with \ wdr.asm - provides wdr ( -- ) resets watchdog (wdr) \ wdwrite.asm - provides wd! ( n -- ) changes WDTCSR & clears WDRF \ also make sense to build with sleep.asm \ WORDS provided by wd.forth \ +wdt ( -- ) \ turn on System Reset Mode \ -wdt ( -- ) \ turn off System Reset Mode \ +wdi ( -- ) \ turn on Interrupt Mode \ -wdi ( -- ) \ turn off Interrupt Mode \ wd.delay! ( n -- ) \ write prescaler AND -wdi -wdt \ ------------------------------------------------------------ \ include the correct constants for device \ below are for atmega328p &12 constant WDTAddr \ Watchdog Time-out Interrupt &96 constant WDTCSR \ Watchdog control register \ 7 6 5 4 3 2 1 0 \ WDTCSR = WDIF WDIE WDP3 WDCE WDE WDP2 WDP1 WDP0 : +wdt ( -- ) WDTCSR c@ %00001000 or wd! ; : +wdi ( -- ) WDTCSR c@ %01000000 or wd! ; : -wdt ( -- ) WDTCSR c@ %00001000 invert and wd! ; : -wdi ( -- ) WDTCSR c@ %01000000 invert and wd! ; : wd.delay! ( n -- ) \ wd! is given 00?00??? to write to WDTCSR \ set prescaler and unset WDIE and unset WDE dup $7 and swap $8 and 2 lshift or wd! ; \ From page 55 of atmega328 datasheet \ WDP3 WDP2 WDP1 WDP0 %0000 constant wd.16ms %0001 constant wd.32ms %0010 constant wd.64ms %0011 constant wd.125ms %0100 constant wd.250ms %0101 constant wd.500ms %0110 constant wd.1s %0111 constant wd.2s %1000 constant wd.4s %1001 constant wd.8s \ wd-example.forth \ \ WARNING \ \ Many of these example intentionally result in \ your AVR8 microprocessor being reset. #include ms.frt #include ./wd.forth : ex.1 ( -- ) \ reset in 8 seconds wd.8s wd.delay! +wdt 8 0 ?do 1000 ms i 1+ . cr loop ; : ex.2 ( -- ) \ use wdr to defer reset but eventually fail wd.4s wd.delay! +wdt 6 0 ?do wdr 1000 i * dup ms . cr loop ; \ constants for atmega328p and UNO for PIN 13 LED $24 constant DDRB $25 constant PORTB : hb.isr ( -- ) \ toggle PIN 13 on UNO #32 PORTB c@ xor PORTB c! ; : ex.3 ( -- ) \ interrupt only no reset and toggle an led #32 DDRB c@ or DDRB c! \ set PIN13 on UNO for output ['] hb.isr WDTAddr int! \ load xt of word to be run on wd timeout wd.500ms wd.delay! +wdi \ ; : ex.4 ( -- ) \ run after ex.3 \ turn off watchdog interrupt and then turn on again -wdi 4 0 ?do 1000 ms i loop +wdi cr ; \ use watchdog interrupt to wake from sleep \ this needs an AmForth built with sleep.asm variable snooze : ex.5 ( -- ) \ use watchdog interrupt to wake from deep sleep 0 snooze ! ['] noop WDTAddr int! \ interrupt routine does nothing wd.4s wd.delay! +wdi \ except wake the MCU up. begin 3 sleep \ sleep snooze dup @ 1+ dup . cr swap ! \ inc print store 50 ms \ small delay to allow print to finish snooze @ 5 > until \ exit after 6 sleeps ; \ use watchdog interrupt and reset #include is.frt #include values.frt #include avr-values.frt #include defers.frt variable app-reg \ my "application" status register 0 Evalue app-reg-save \ persistant EEPROM store for above \ to survive a reset : panic.isr ( -- ) \ wdr wasn't called in time \ ... app-reg @ to app-reg-save \ store "application" status register #32 PORTB c@ xor PORTB c! \ turn on PIN 13 LED \ will reset on next \ watchdog time out ; : ex.6 ( -- ) \ use watchdog interrupt and reset #32 DDRB c@ or DDRB c! \ set PIN13 on UNO for output #32 invert PORTB c@ and PORTB c! \ set PIN13 on low ['] panic.isr WDTAddr int! \ load xt of word to be run on wd timeout 0 to app-reg-save \ zero eeprom store of "register" wd.125ms wd.delay! +wdt +wdi s" Will reset in a short while. Look at app-reg-save after" itype cr 250 1 ?do i ms wdr app-reg dup @ \ some "made up" app-reg value i + swap ! loop \ after the reset/power cycle look at Evalue app-reg-save ; : ex.7 ( -- ) \ (roughly) what frequency is my 128 kHz ? #32 DDRB c@ or DDRB c! \ set PIN13 on UNO for output ['] hb.isr WDTAddr int! \ load xt of word to be run on wd timeout \ frequency f on PIN 13 \ 1 period is 2 timeouts \ each timeout is 2000 ticks \ so 2*f*2000 is roughly \ the frequency of my UNO's \ 128 kHz oscillator. wd.16ms wd.delay! +wdi \ I measure f to be 28.56Hz \ so watchdog ~114.2kHz \ compare datasheet page 606 \ for VCC=5V T=25DegC \ from chart ~114.2kHz ; ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Amforth-devel mailing list for http://amforth.sf.net/ Amforth-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/amforth-devel