Basic Watchdog Timer: (Arduino Uno/Atmega328) by Nicolas Larsen

Download as pdf or txt
Download as pdf or txt
You are on page 1of 3

# 11 June 2011

relevant bits to ʻONʼ. To the right is a table of the


different bits and their function.

WDIF - Sets an interrupt flag but you wont need to


worry about this. It is automatically flagged high
and low by the system.

WDIE - Enables Interrupts. This will give you the


chance to include one last dying wish (or a few
lines of code...) before the board is reset. This is a
great way of performing interrupts on a regular
interval should the watchdog be configured to not
reset on time-out.

BASIC WATCHDOG TIMER WDCE - This is a safety to enable a configuration


(Arduino UNO/ATmega328) mode that will last 4 clock cycles. Set this bit and
by Nicolas Larsen WDE high before attempting any changes to the
watchdog register. There isnʼt really any logic
There seems to be a lot confusion regarding the behind this, you just have to set WDCE and WDE
setup of the watchdog timer which is what I hope to to ʻ1ʼ to enter a sort of ʻsetup modeʼ in the
clarify in a very basic manner. I will try my best to watchdog timer.
explain things in clear english. This is only
applicable to boards running the Opti-bootloader WDE - Enables system reset on time-out.
(standard Uno bootloader) and those running Lady Whenever the Watchdog timer times out the
Adaʼs bootloader (although I have yet to test it on micocontroller will be reset. This is probably what
the latter). Using Arduino IDE 0022 you were all looking for. Set this to ʻ1ʼ to activate.

The watchdog timer is a very useful feature for WDP0/WDP1/WDP2/WDP3 - These four bits
projects that are intended to run for extended determine how long the timer will count for before
periods of time or contain unstable loops of code. resetting. The exact time is set by setting
The watchdog is essentially a small timer that will combinations of the 4 bits in such a pattern.
force a full system restart should it not receive a
“system ok” signal from the microcontroller within a WDP WDP WDP WDP Time-out
preset time. Should in any application the micro- 3 2 1 0 (ms)
controller freeze, hang, stall or crash the watchdog 0 0 0 0 16
will time out and force a reset to the same effect as 0 0 0 1 32
pressing the reset button on your board. 0 0 1 0 64
0 0 1 1 125
0 1 0 0 250
Begin by importing the watchdog timer into your 0 1 0 1 500
code. 0 1 1 0 1000
0 1 1 1 2000
#include <avr/wdt.h>
1 0 0 0 4000
1 0 0 1 8000
Youʼll now need to configure your watchdog timer
through one of the registers known as WDTCSR.
A register is a byte or several in the systemʼs
So you can see the watchdog can be set anywhere
memory that is reserved for saving
between 16ms and 8 seconds. To let the watchdog
system settings (in lay-mans
timer know that everything is running ok and that it
terms). Every feature will have a Bit Name
neednʼt panic or take any action your going to have
register allocated to it. The 7 WDIF
to keep reseting the timer within your main loop.
microcontroller knows where to go 6 WDIE This is done by periodically entering in:
in its memory to get these 5 WDP3
registers. The watchdog is no 4 WDCE wdt_reset();
different. The watchdog register,
3 WDE
composed of one byte, thus has 8
2 WDP2 Remember: the watchdog is a timer, if you donʼt
bits in on/off settings. A ʻ1ʼ
indicates ʻONʼ and a ʻ0ʼ indicates 1 WDP1 reset it regularly it will time-out, prompting the reset
ʻOFFʼ. By default everything is set 0 WDP0 and or interrupt.
to ʻOFFʼ so we only need to set the
# 1
# 11 June 2011

Now you know the basic setting we are going to included that so you can quickly modify the time-
create a function that sets up the watchdog timer to settings should you wish to make changes.
include interrupts, a reset and time-out after
1000ms. It is good practice to comment in what you // Set Watchdog settings:
are setting each of the bits to for later reference. WDTCSR = (1<<WDIE) | (1<<WDE) |
(0<<WDP3) | (1<<WDP2) | (1<<WDP1) |
void watchdogSetup(void) (0<<WDP0);
{
cli(); If you are unfamiliar with bitwise and compound
operations the syntax may appear a bit odd to you.
wdt_reset(); I suggest you have a look on the Arduino
Reference Page for better understanding. The
/* same settings could just have easily been applied
WDTCSR configuration: in binary by:
WDIE = 1: Interrupt Enable
WDE = 1 :Reset Enable // Enter Watchdog Configuration mode:
See table for time-out variations: WDTCSR |= B00011000;
WDP3 = 0 :For 1000ms Time-out // Set Watchdog settings:
WDP2 = 1 :For 1000ms Time-out WDTCSR = B01001110;
WDP1 = 1 :For 1000ms Time-out
WDP0 = 0 :For 1000ms Time-out
*/
Now that your done with the setup you can re-
enable interrupts by typing “sei()”. The watchdog
// Enter Watchdog Configuration mode:
includes interrupts so be sure to re-enable this.
WDTCSR |= (1<<WDCE) | (1<<WDE);
The only thing left to insert in your code is the
// Set Watchdog settings:
interrupt, should you have chosen to include it.
WDTCSR = (1<<WDIE) | (1<<WDE) |
Note that the interrupt, like all interrupts cannot
(0<<WDP3) | (1<<WDP2) | (1<<WDP1) |
make use of the “delay()” function. It is also poor
(0<<WDP0);
practice to call functions such as “Serial.println()”
in the interrupt as any error in the function may
sei();
cause the microcontroller to hang in the interrupt
}
preventing the watchdog from restarting.

Lets cover this line by line. “cli();” disables all ISR(WDT_vect)


interrupts on the microcontroller so that {
configuration is never disrupted and left unfinished. // Include your interrupt code here.
}
“wdt_reset();” resets the watchdog timer. This isnʼt
always necessary but you certainly donʼt want your
watchdog timing out and resetting while you are
trying to set it.
The example code included on the next page sets
the watchdog timer to 2 seconds with an interrupt.
// Enter Watchdog Configuration mode:
An expanding loop is included so that the watchdog
WDTCSR |= (1<<WDCE) | (1<<WDE);
will eventually time-out and cause a reset. What
you will hopefully notice from the serial feed is that
The above will prompt configuration mode enabling the watchdog is not reset exactly after 2 seconds.
you to make changes to the register. These The watchdog is a very inaccurate timer and as
changes need to be set within 4-cycles so the such should not be used for time critical
settings should follow immediately after this line. It applications. With that said - nor is my ʻtimingʼ code
is unusual for registers to require a configuration strictly accurate...
like this which may account for all the watchdog
timer confusion. Regardless, its in the ATmega328
data sheet so thats what we must all abide by. I hope this clarifies the basic setup of the watchdog timer
and some of its features. It is certainly not an exhaustive
Now we enter in the various bits as we laid out in list of features! If you find any errors please let me know.
the comments. It is not necessary to set anything to
zero as I have done for WDP3/0, as by default DISCLAIMER: I am by no means an expert regarding
everything in the register is already at zero. I this topic and as such this document is provided as is.
Use this information at your own risk.

# 2
# 11 June 2011

/*
Watchdog Timer Basic Example
10 June 2011
Nicolas Larsen
*/

#include <avr/wdt.h>

int loop_count = 0;

void setup()
{
Serial.begin(9600);
Serial.println("Starting up...");
pinMode(13,OUTPUT);
digitalWrite(13,HIGH);
delay (500);
watchdogSetup();
}

void watchdogSetup(void)
{
cli(); # # // disable all interrupts
wdt_reset();# // reset the WDT timer
/*
WDTCSR configuration:
WDIE = 1: Interrupt Enable
WDE = 1 :Reset Enable
WDP3 = 0 :For 2000ms Time-out
WDP2 = 1 :For 2000ms Time-out
WDP1 = 1 :For 2000ms Time-out
WDP0 = 1 :For 2000ms Time-out
*/
// Enter Watchdog Configuration mode:
WDTCSR |= (1<<WDCE) | (1<<WDE);
// Set Watchdog settings:
WDTCSR = (1<<WDIE) | (1<<WDE) | (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0);
sei();
}

void loop()
{
for (int i = 0; i <= loop_count;i++){
digitalWrite(13,HIGH);
delay(100);
digitalWrite(13,LOW);
delay(100);
}
loop_count++;
wdt_reset();
Serial.print(loop_count);
Serial.print(". Watchdog fed in approx. ");
Serial.print(loop_count*200);
Serial.println(" milliseconds.");
}

ISR(WDT_vect) // Watchdog timer interrupt.


{
// Include your code here - be careful not to use functions they may cause the interrupt to hang and
// prevent a reset.
}

# 3

You might also like