ATtiny85 Watchdog-reboot Together With SLEEP And/or ISR
by Rob__S in Circuits > Arduino
6713 Views, 2 Favorites, 0 Comments
ATtiny85 Watchdog-reboot Together With SLEEP And/or ISR
The ATtiny85 (and family) has a Watchdog-Timer in addition to it’s two normal 8-bit timers (Timer0 and Timer1).
This Watchdog-Timer can be used to auto-reboot the ATtiny if it has hung (after between 16ms and 8seconds depending on what you select). The easiest way to use this is to use the standard “avr/wdt.h” library and the commands: [wdt_disable(); wdt_enable(9); and wdt_reset();]. There are many examples out there detailing this use.
However, the Watchdog-Timer is also used to wake the ATtiny from sleep, in which case it can NOT also be used with the “avr/wdt.h” library as a standard reboot-if-hung-watchdog.
But it IS possible to configure the Watchdog-Timer to do BOTH the wake-from-sleep (both timed &/or ISR-on-pin-change) function, AND also the reboot-if-hung-watchdog function at the same time.
Similarly, you can also use the Watchdog-Timer as an ISR (ie. so you use Timer0 and Timer1 for something else), AND still use the reboot-if-hung-watchdog function at the same time.
The below two sketches demonstrate this:
(NB. these have been tested using SpenceKonde’s Arduino core for ATtiny.)
Example of ATtiny85 Sleep Together With “watchdog-reboot-if-hung” Functionality
#include <avr/sleep.h>
#define wdt_reset() __asm__ __volatile__ ("wdr") // this re-starts the watchdog clock/timer (ie. leaves current settings as is)
ISR(WDT_vect) {} // NB. MUST be present, otherwise ATTiny reboots instead of returning from Sleep!
void LED_toggle(byte count) {for (byte x=0;x<count;x++) {delay(500); PORTB ^= B1;}} // LED+resistor between PB0 and ground
void boot_reason_flash(byte reason) { // NB. after s/w-upload usually get 6 flashes
if ((reason&(1<<WDRF))!=0) LED_toggle(2*2); // Watchdog = 2 flashes
if ((reason&(1<<PORF))!=0) LED_toggle(3*2); // PowerOn = 3 flashes
if ((reason&(1<<BORF))!=0) LED_toggle(4*2); // BrownOut = 4 flashes
if ((reason&(1<<EXTRF))!=0) LED_toggle(6*2); // ExternalReset = 6 flashes
}
void setup() {
byte boot=MCUSR; MCUSR=0x00; // NB. MCUSR must be zeroed or watchdog will keep rebooting
WDTCR|=(1<<WDCE)|(1<<WDE); WDTCR=0x00; // disable watchdog
pinMode(0,OUTPUT); boot_reason_flash(boot); delay(2000);
WDTCR = (1 << WDP3) | (0 << WDP2) | (0 << WDP1) | (0 << WDP0); // set watchdog-timing to 4secs
//WDTCR = (1 << WDP3) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0); // set watchdog-timing to 8secs
WDTCR |= (1 << WDE); // Set watchdog timer to re-boot if triggered to begin with (only add WDIE just before we start sleep)
}
void loop() {
LED_toggle(2); // on/off-flash
ADCSRA&=~(1<<ADEN); // ADC off
WDTCR |= (1<<WDIE); // set WDIE=1 to wake up ATtiny (ie. stops the first watchdog trigger causing reboot)
wdt_reset(); // re-start timer here (if required)
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_mode(); // does a [sleep_enable(); sleep_cpu(); sleep_disable();]
static byte count1=0; count1++; if (count1>=4) {LED_toggle(1); while(true) delay(1000);} // after 4 sleep-cycles hang here (so watchdog-reboot triggers after 1 more cycle)
}
Example of ATtiny85 Watchdog-Timer As an ISR (eg. to Flash and LED) With “watchdog-reboot-if-hung” Functionality
ISR(WDT_vect) {
PORTB ^= B1; // toggle LED
WDTCR |= (1<<WDE); // reset WDE (but don't reset "WDIE" here, only do that in main loop as the "feed watchdog" command)
// ie. if WDIE not set in main loop, then next trigger of WDE will re-boot the ATTiny instead of calling this ISR
}
void LED_toggle(byte count) {for (byte x=0;x<count;x++) {delay(500); PORTB ^= B1;}} // LED+resistor between PB0 and ground
void boot_reason_flash(byte reason) { // NB. after s/w-upload usually get 6 flashes
if ((reason&(1<<WDRF))!=0) LED_toggle(2*2); // Watchdog = 2 flashes
if ((reason&(1<<PORF))!=0) LED_toggle(3*2); // PowerOn = 3 flashes
if ((reason&(1<<BORF))!=0) LED_toggle(4*2); // BrownOut = 4 flashes
if ((reason&(1<<EXTRF))!=0) LED_toggle(6*2); // ExternalReset = 6 flashes
}
void setup() {
byte boot_reason=MCUSR; MCUSR=0x00; // NB. MCUSR must be zeroed or watchdog will keep rebooting
WDTCR|=(1<<WDCE)|(1<<WDE); WDTCR=0x00; // disable watchdog
pinMode(0,OUTPUT); boot_reason_flash(boot_reason); delay(2000);
WDTCR = (0 << WDP3) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0); // set watchdog-timing to 2secs
//WDTCR = (1 << WDP3) | (0 << WDP2) | (0 << WDP1) | (0 << WDP0); // set watchdog-timing to 4secs
WDTCR |= (1 << WDE) | (1 << WDIE); // Set watchdog timer mode as BOTH WDE (reboot) and WDIE (ISR-interrupt)
}
void loop() {
if (millis()<20000) WDTCR|=(1<<WDIE); // effectively feed watchdog for the first 20 seconds (3 or 4 flashes)
delay(1000);
}