Introduction: 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.)

Step 1: 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)

}

Step 2: 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);

}