Tutorial: Basic Watchdog Timer Setup

Za Nick,

Za Nick, In your program you mention about code that will cause the arduino to hang,
" Include your code here - be careful not to use functions they may cause the interrupt to hang and // prevent a reset."

I am a newbie to Arduino, and I wonder what functions would cause it to hang, In my program I am using a watchdog timer to reset a Christmas light project, so I have a bunch of delays to trigger relays for lights, but one small problem, I have a hell of time trying to get it to call a reset and run a bunch delays. Here is my code that I have been working with.

#include <avr/wdt.h>
int loop_count = 0;
const int buttonPin = 12;
int ledpin13=13;
int ledpin11=11;
int ledpin1=2;
int ledpin2=3;
int ledpin3=4;
int ledpin4=5;
int ledpin5=6;
int ledpin6=7;
int ledpin7=8;
int ledpin8=9;
int ledpin9=10;
int buttonState = 0;

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

}

void watchdogSetup(void)
{
cli();
wdt_reset();
WDTCSR |=(1<<WDCE) | (1<<WDE);
WDTCSR = (1 <<WDIE) | (1<<WDE) | (0<<WDP3) |(1<<WDP2) | (1<<WDP1) | (1<<WDP0);
sei();

}

void loop()
{ pinMode(12, INPUT);
int GreenWire = digitalRead(12);
if (GreenWire ==HIGH)
{
program();
}
else if(GreenWire ==LOW);
{
WatchDog();
}
}

void program()
{ unsigned long time;
time = millis()/1000;
Serial.println(time);

if (time < 17 )
{
SeqA();

}
else if (time ==17 || time ==18)
{

SeqA();
}
return;

}

void SeqA()
{
digitalWrite(ledpin1,HIGH);
digitalWrite(ledpin2,HIGH);
digitalWrite(ledpin3,HIGH);
digitalWrite(ledpin4,HIGH);
digitalWrite(ledpin5,HIGH);
digitalWrite(ledpin6,HIGH);
digitalWrite(ledpin7,HIGH);
digitalWrite(ledpin8,HIGH);
delay(525);
digitalWrite(ledpin8,LOW);
digitalWrite(ledpin7,LOW);
delay(525);//3
digitalWrite(ledpin8,HIGH);
digitalWrite(ledpin7,HIGH);
return;
}
void WatchDog()
{

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.");
return;

}

Pardon my stupidity, but I'm just starting to play with the concept of the watch dog timer. Originally I was going to use an external timer (ie:555) to reset several scattered modules associated with my growing project when I came across this thread. I am confused though about some of the statements in the sketch presented by za_nic, probably because I'm new to arduino as well. Anyway what I'm confused about is the statements like WDTCSR |= (1<<WDCE) | (1<<WDE); that use << I'm assuming that sets the variable to 1? and the vertical line between (which in my previous experience we called "pipe". Is this a delimiter? I can't seem to find reference to these. I could probably just copy/past and check the outcome, but I'd like to attempt to understand first. I'm also curious if the reset caused by the WDT is visible on the reset pin, so that it may be used externally.
thanks for any help.

I'm also curious if the reset caused by the WDT is visible on the reset pin, so that it may be used externally.

I don't think so. Internal only as the Reset pin can also be configured to be used as a general IO pin (with a fuse change).

flagtrax:
...that use << I'm assuming that sets the variable to 1?

Bit shift left. WDCE are WDE simple numeric constants.

https://www.google.com/search?q=c%2B%2B+operator+shift+left

...and the vertical line between (which in my previous experience we called "pipe". Is this a delimiter?

Bitwise or.

https://www.google.com/search?q=c%2B%2B+operator+bitwise+or

"Bit shift left. WDCE are WDE simple numeric constants."

Thanks for that, Coding Badly I searched for << to no avail :blush: .

So I gather he's using this method to set the WDT characteristics so that it may be done within the 4 clock cycles stated in the Data sheets?

  WDTCSR = (1 <<WDIE) | (1<<WDE) | (0<<WDP3) |(1<<WDP2) | (1<<WDP1) | (1<<WDP0);

The compiler will turn the RHS of that statement into a single constant. For example, WDIE is the number 6, so 1 << WDIE will be the 6th bit along (counting from zero).

A bit of disassembling of that function shows that it is done within 4 clock cycles (3, in fact):

void watchdogSetup(void);
  cli();
  a6:   f8 94           cli   (1)

  wdt_reset();
  a8:   a8 95           wdr   (1)

// load Z register with address 0x0060
  aa:   e0 e6           ldi     r30, 0x60       ; 96   (1)   // WDTCSR
  ac:   f0 e0           ldi     r31, 0x00       ; 0   (1)

  WDTCSR |=(1<<WDCE) | (1<<WDE);
  ae:   80 81           ld      r24, Z   (2)    // get existing WDTCSR
  b0:   88 61           ori     r24, 0x18       ; 24   (1)  // OR in new value
  b2:   80 83           st      Z, r24   (2)    // save to WDTCSR

  WDTCSR = (1 <<WDIE) | (1<<WDE) | (0<<WDP3) |(1<<WDP2) | (1<<WDP1) | (1<<WDP0);
  b4:   8f e4           ldi     r24, 0x4F       ; 79   (1)
  b6:   80 83           st      Z, r24   (2)

  sei();
  b8:   78 94           sei   (1)
 
} 
  ba:   08 95           ret   (4)

(Cycle counts in brackets)

From the moment that WDTCSR is written to the first time, it only takes 3 clock cycles to write to it again.

I'm also curious if the reset caused by the WDT is visible on the reset pin, so that it may be used externally.

No I doubt that. The reset pin is an input, not an output.

Thanks Nick, excellent explanation! And I have indeed verified that reset is not visible on the (reset) pin. Perhaps using a spare GPIO pin in a setup function could be used to reset "downstream" modules. FYI this all relates to sending commands from a remote laptop via 8266 wifi modules. The one I'm working with seems to be a bit qwerky, and seems to have a delay in responding at times. Thanks again!

Perhaps using a spare GPIO pin in a setup function could be used to reset "downstream" modules.

Assuming the downstream modules have an active low reset: tie their reset to ground with a pulldown resistor. Connect that to an Arduino pin. To bring the modules out of reset change the pin to OUTPUT / HIGH. Doing it this way guarantees when the Arduino is in reset so are the modules. It also allows the Arduino to reset the modules at will.

Hi, nice tutorial, thanks!

Is there a reason NOT to use wdt_enable() instead of writing the bits to WDTCSR? It was nice to learn how to do it by setting the different bits and knowing about cli() etc. but the single function is kinda nice :stuck_out_tongue:

The wdt_enable() is just a macro doing the same thing. So do as you please :slight_smile:

Hello,

I'm digging up this topic from 09 2015.
Here is my code :

#include <avr/wdt.h>

boolean ledState = LOW;
int ledPin = 13;

volatile int loop_count;
volatile boolean wdtState = false;

void watchdogSetup () {
 cli ();
 wdt_reset ();
 WDTCSR |= (1<<WDCE) | (1<<WDE);
 WDTCSR = (1<<WDIE) | (1<<WDE) | (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0);
 sei ();
}

ISR (WDT_vect) {
 wdtState = true;
 loop_count ++;
}

void setup () {
 Serial.begin (9600);
 Serial.println ("Starting up ...");
 pinMode (ledPin, OUTPUT);
 digitalWrite (ledPin, ledState);
 watchdogSetup ();
 loop_count = 0;
}

void loop () {
 if (wdtState) {
   wdtState = false;
   Serial.print ("WDT ISR : ");
   Serial.println (loop_count);
   wdt_reset ();
 }
 
 if (loop_count == 10 ) {
   while (1) {
     ledState = !ledState;
     digitalWrite (ledPin, ledState);
     delay (500);
   }
 }
 
 ledState = !ledState;
 digitalWrite (ledPin, ledState);
 delay (100);
}

As you can see, WDE and WDIE are set. So, when my program goes into the infinite while loop, my Nano v3 should reset as there is no wdt_reset call.

Instead of that, the Nano seems to go into a strange status because the led 13 blinks without the delays I programmed (also if I don't program led blink too).

When WDE is set to 0, the program goes into the infinite while loop and the system doesn't reset (only watchdog interrupts are allowed in this case).

I wonder why my Nano card does that. I can't figure why the WDE set to 1 does not work. So, after reading and searching the internet, I did not found anyone that has this kind of problem. Do you think my Nano card is out of service for watchdog resets ? If not, can you see what is wrong in my code ? If my code is good, do you understand what happens ? Does my code work well on your own arduino ?

I own a Saintsmart Nano v3.

Thank you for your help. I'm a bit lost.

BR,
Fabrice.

Please edit your post, select the code, and put it between [code] ... [/code] tags.

You can do that by hitting the "Code" icon above the posting area. It is the first icon, with the symbol: </>

Sounds like you have one of the bootloaders that doesn't reset the watchdog timer. The flash you see is the bootloader initial flash of pin 13. Then it resets again and flashes it again.

I burnt my nano clone (sainsmart nano v3) bootloader and did some other tests :

  • set WDIE and WDE to 1 : nano goes in fast reset (as supposed by Nick Gammon in last post)
  • set WDIE to 0 and WDE to 1 : same effect
  • set WDIE to 1 and WDE to 0 : nano works in the right way and there is no need to wdt_reset() as no system reset is wanted.

I deduced that my nano does not support WDE sets to 1 (so no wdt system reset is possible).
Is it only my nano clone (I mean sainsmart nano v3) that works this way or all nanos work this way ?

I did the same things on a MEGA2560 and there is no problem.

Thank you for your contributions.

BR,
Fabrice.

You should be able to put Optiboot on a Nano.

Thanks man. the dog barks!! :wink:

void wdtEnable()
{
wdt_reset(); // reset the WDT timer
MCUSR &= ~(1<<WDRF); // because the data sheet said to
// Enter Watchdog Configuration mode:
WDTCSR |= (1<<WDCE) | (1<<WDE) | (1<<WDIE);
// Set Watchdog settings: interrupte enable, 0110 for timer
WDTCSR = (1<<WDIE) | (0<<WDE) | (1<<WDP3) | (0<<WDP2) | (0<<WDP1) | (1<<WDP0);
}

void wdtStart()
{
cli();
wdt_reset(); // reset the WDT timer
MCUSR |= (1 << WDRF);
WDTCSR = (1<<WDIE)|(1<<WDCE)|(1<<WDE)|(1<<WDP3)|(0<<WDP2)|(0<<WDP1)|(1<<WDP0);
sei();
}

void wdtStop()
{
cli();
wdt_reset(); // reset the WDT timer
MCUSR &= (0xFF & (0<<WDRF));
WDTCSR |= (1<<WDCE)|(1<<WDE)|(0<<WDIE);
WDTCSR = (0<<WDE)|(0<<WDIE);
sei();
}

Is there a question there? Please use code tags.

I just bought an elegoo UNO (that should work like arduino) and tested the blink example, then I wrote a code for the RGB-fade example that was described without a code in the documentation that came with the starter kit.

I noticed that the LED L still flashes after a while even if the sketch says nothing about it, so I figured out that the watchdog resets the board so the sketch restarts (usually in the middle of it). I tried adding various commands to disable the watchdog, or to reset as often as possible its counter, but there is no effect.

I tried to load the standard blink-code for the L LED (1 second on, 1 second off), and I notice that after 32 seconds the L LED flashes.

The best I could do is by disconnecting the USB cable and plugging it back, the watchdog seems to be asleep for much longer (about 120 Seconds), but eventually wakes up after a while (after that, it seems to reset the sketch every 32 seconds). I got these time estimations by using the standard blink sketch.

Does it mean the hardware is faulty?

Should I send it back?

Thanks for your help.