Watchdog Timers (WDT)
make your installations robust
[written by Tom, October 2015]
*Tested with an Industruino 1286 topboard
Introduction
A watchdog timer is a timer that, if not interacted with for a certain period of time, will reset the microcontroller. In case the microcontroller gets stuck somewhere in its code, the watchdog timer will be triggered and the microcontroller will reset, and restart normal operation. This is the most basic implementation of a watchdog; it is also possible to attach an interrupt routine to the watchdog timer so a specific piece of code will be executed when the watchdog timer is triggered but we won’t cover that here.
There are 2 different ways to implement a watchdog timer: hardware and software.
HARDWARE watchdog timer
The AVR family of microcontrollers (including the Industruino topboards 32u4 and 1286) have a hardware watchdog timer built in that can be set to periods of 15 milliseconds up to 8 seconds. Be careful when setting the watchdog to very short periods: that might trigger the watchdog reset while you are trying to upload a new sketch. In this example we will only use periods of 1, 2, 4, 8 seconds.
Include the watchdog timer library avr/wdt.h
In setup(), enable the watchdog timer with the desired period:
wdt_enable(WDTO_8S); // options: WDTO_1S, WDTO_2S, WDTO_4S, WDTO_8S
In loop(), reset the watchdog timer before it reaches the set period
wdt_reset(); // confirm to watchdog timer that all is well
This example sketch sets the watchdog timer to 4 seconds, and then in each loop increases the amount of time in a delay(), eventually triggering the watchdog timer and resetting the Industruino. Note that the watchdog timer is not exact, as described elsewhere. We usually got up to 1020% longer than the set period before the watchdog timer was triggered.
Also see AVR documentation at
http://www.nongnu.org/avrlibc/usermanual/group__avr__watchdog.html
// INDUSTRUINO basic example for hardware watchdog // with topboard 1286 #include#include static UC1701 lcd; void setup() { lcd.begin(); //sets the resolution of the LCD screen lcd.clear(); lcd.setCursor(2,2); lcd.print("watchdog timer RESET"); pinMode(26, OUTPUT); for (int i=0;i<5;i++) { digitalWrite(26, LOW); delay(500); digitalWrite(26, HIGH); delay(500); } analogWrite(26,200); lcd.clear(); wdt_enable(WDTO_4S); // options: WDTO_1S, WDTO_2S, WDTO_4S, WDTO_8S } void loop() { wdt_reset(); // confirm to watchdog timer that all is well lcd.setCursor(2,2); lcd.print("delay_time: "); lcd.print(delay_time); delay(delay_time); delay_time += 100; } int delay_time = 0;
SOFTWARE watchdog timer
If you need a watchdog timer interval above 8 seconds, you cannot use the above hardware solution. But it’s rather easy to write a software watchdog timer based on the timers available on the microcontroller. To make this easy, you will need to install the TimerOne library from here http://code.google.com/p/arduinotimerone/downloads/list
We configure this timer to trigger a routine at 1 second intervals, and the routine checks if a certain period (variable timeout) has passed since the last reset. The reset time is kept in a variable lastUpdate, which we update regularly with m illis(). So the variable timeout has to be set in milliseconds. The structure of the code is very similar to the hardware timer, but a little longer, and more flexible.
Below example resets the microcontroller when the watchdog is not updated for 20 seconds. The code is based on the example at http://blog.frogslayer.com/creatinganarduinowatchdogtimer/
and as mentioned there, this is not the equivalent of a hard reset so pins might keep their previous state.
// INDUSTRUINO basic example for software watchdog // with topboard 1286 #include#include static UC1701 lcd; long timeout = 20000; long lastUpdate; void setup() { lcd.begin(); //sets the resolution of the LCD screen lcd.clear(); lcd.setCursor(2,2); lcd.print("watchdog timer RESET"); pinMode(26, OUTPUT); for (int i=0;i<5;i++) { digitalWrite(26, LOW); delay(500); digitalWrite(26, HIGH); delay(500); } analogWrite(26,200); lcd.clear(); lastUpdate = millis(); Timer1.initialize(1000000); Timer1.attachInterrupt(longWDT); //code to execute } void loop() { lcd.setCursor(2,2); lcd.print("delay_time: "); lcd.print(delay_time); delay(delay_time); delay_time += 1000; lastUpdate = millis(); } void (*resetFunc)(void) = 0; void longWDT(void) //1 second pulses { if((millis()lastUpdate) > timeout) { Timer1.detachInterrupt(); resetFunc(); } } int delay_time = 0;