ATmega328P: Watchdog timer stops program, but doesn't reset...

Hi all

I'm building a data logger using Seeeduino Stalker V2.3 and a GPRS V2.0 shield. It will be functioning at a remote location for very long(years, hopefully), so I don't want it to freeze up in the first week, and just stop working. I'm storing all data on an SD card, and I'm making it accessible via SMS, so an occasional reset won't hurt.

I want to use the built-in watchdog timer to reset it if the program freezes. As far as I understand it should work as follows (using the avr/wdt.h library):
You activate it with the "wdt_enable(CONST)" command in the setup. I used "wdt_enable(WDTO_8S)" for an 8 second watchdog timer.
After this the watchdog should regularly petted with the "wdt_reset()" command.
If the watchdog isn't petted within the specified time(in my case: 8 seconds), it bites, and resets the Stalker. This reset should have the same effect as pressing the reset button on the controller itself, causing the program to run from setup().

IMPORTANT: If my understanding of the watchdog timer is wrong, please correct it.

So if you look at my attached code, you will see this is what I have done. I activated the timer at the very top of my setup(), and I reset it in the function "stateTransitionMonitor", which is called at the top of loop(). Please note that I use a state machine architecture, and that I initialize the program to an error state only to demonstrate my problem. The idea is that it resets either when the error state is reached, or if it is stuck in any state other than IDLE for too long.

If I run my code, the following happens:
The program gets through setup() fine, printing "Entering loop..." at it's end. Then it goes into stateTransitionMonitor(), where it prints "Watchdog missed" and "ERROR" for 8 seconds, just like it should.

Then it stops. Indefinitely. Which is wrong, right? It should be starting with setup() again, printing "Entering loop...", and repeating the events that happened just before.

So what's going wrong? How can I make it reset?

I googled this, and found slightly similar cases, but most of them had different hardware and solved their problems by burning a new bootloader. As an only slightly experienced Arduino enthusiast, I thought it might be wise to seek the forums advice before messing with the bootloader.

Thanks

Logger_plus_gprs.ino (20.1 KB)

What is this gobbledygook....

... || ( millis() <= millisTimer && ( (millis() + millisTimer)%4294967295ul ) >= 60000ul ) ...

How does the board behave with a simple test case...

#include <avr/wdt.h> // watchdog timer

void setup( void )
{
  Serial.begin(9600); // Serial line is opened. Used mostly for testing.
  Serial.println( F( "Eight seconds and..." ) );
  wdt_enable(WDTO_8S); // we enable the watchdog timer to bite after 8 seconds
}

void loop( void )
{
}

Hi

I tested your code, and it only printed one line of "Eight seconds and...", and then froze. The same as my big sketch.

As for the gobbledygook: It is supposed to to use millis as a timer for 60 seconds before actually starting to neglect the watchdog, thus leaving me with a 68 second watchdog timer. But the error state in which the program is initialized bypasses this ( "...gobbledygook... || state == ERROR" ), so I don't think we need to worry about that right now. The only reason it looks a little big and scary is because I also catered for a millis rollover. Feel free to remove it.

Thanks so far :slight_smile:

snugRugBug:
Hi

I tested your code, and it only printed one line of "Eight seconds and...", and then froze. The same as my big sketch.

It didn't freeze, it went to loop() (which doesn't print any messages).

You may have to clear the "WDRF" bit in MCUSR. You're supposed to check this bit in setup to find out if the reset was caused by the watchdog. Isn't cleared by RESET, you have to reset it manually before watchdog will work.

OK, the timer works now, and restarts everything every 8 seconds like it should. I used this code I got from Low-Power Arduino Using the Watchdog Timer – Fiz-ix

void watchdogOn() {
  
// Clear the reset flag, the WDRF bit (bit 3) of MCUSR.
MCUSR = MCUSR & B11110111;
  
// Set the WDCE bit (bit 4) and the WDE bit (bit 3) 
// of WDTCSR. The WDCE bit must be set in order to 
// change WDE or the watchdog prescalers. Setting the 
// WDCE bit will allow updtaes to the prescalers and 
// WDE for 4 clock cycles then it will be reset by 
// hardware.
WDTCSR = WDTCSR | B00011000; 

// Set the watchdog timeout prescaler value to 1024 K 
// which will yeild a time-out interval of about 8.0 s.
WDTCSR = B00100001;

// Enable the watchdog timer interupt.
WDTCSR = WDTCSR | B01000000;
MCUSR = MCUSR & B11110111;

}

Now I'm just trying to come up with a way to pet the dog...

Thanks for the pointer, Coding Badly and fungus :slight_smile:

For petting the dog, wdt_reset() works fine. Only the wdt_enable() function seems to have a problem. So I'm happy :slight_smile:

Thank you, the hint with

	// Clear the reset flag, the WDRF bit (bit 3) of MCUSR.
MCUSR = MCUSR & B11110111;

solved my issue.
The issue was that the watchdog stopped the program on my Arduino Mega reliably. However the restart of the program only worked sporadically.
Now it restarts reliably.

I have the standard arduino bootloader from the IDE version 1.6.3., found in
C:\Program Files (x86)\Arduino\hardware\arduino\avr\bootloaders\atmega8\ATmegaBOOT.hex
It seems the source code for this bootloader can be found at
https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/bootloaders/atmega8

It is version 1.0.3 and is from December 2012.

hydrocontrol:
Thank you, the hint with

 // Clear the reset flag, the WDRF bit (bit 3) of MCUSR.

MCUSR = MCUSR & B11110111;



solved my issue.
The issue was that the watchdog stopped the program on my Arduino Mega reliably. However the restart of the program only worked sporadically.
Now it restarts reliably.

I have the standard arduino bootloader from the IDE version 1.6.3., found in
C:\Program Files (x86)\Arduino\hardware\arduino\avr\bootloaders\atmega8\ATmegaBOOT.hex
It seems the source code for this bootloader can be found at 
https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/bootloaders/atmega8

It is version 1.0.3 and is from December 2012.

Forget this post of mine. The issue is solved here: Arduino Mega watchdog and bootloader - Microcontrollers - Arduino Forum

More corrections:
MCUSR is always zero anyway, because it gets cleared by the mega bootloader.
The correct location of the mega bootloader can be found in the linked thread.