Electrical – I can’t get WDT (watchdog timer) working on ATmega2560

atmegawatchdog

I have a running application on the ATmega2560 and it is working OK.
Now, I wanted to implement Watchdog feature in order to reset the chip when the application takes longer to operate for some reason.

I am using Visual Studio with Visual Micro extension.
And I flash the HEX file via AVRISP mkII.

So, I have simply started with couple of samples found on the net.
But, whatever WDT version I used they repeatedly restarted the chip on and on endlessly.

Here is one of them;

#include <avr/wdt.h>

int loop_count = 0;
int wdt_counter = 0;

void setup() {

    Serial.begin(9600);
    Serial.println("Starting up...");
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    delay(500);
    watchdogStart();
}

void watchdogStart(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) | (0 << WDE) | (0 << WDP3) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0);
    sei();
}

void watchdogArm(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(10, HIGH);
        delay(100);
        digitalWrite(10, LOW);
        delay(100);
    }
    loop_count++;
    wdt_reset();
    watchdogStart();
    wdt_counter = 0;
    Serial.print(loop_count);
    Serial.print(". Watchdog fed in approx. ");
    Serial.print(loop_count * 200);
    Serial.println(" milliseconds.");
}
/* this is called when the watchdog times out and before the reset */
ISR(WDT_vect) // Watchdog timer interrupt.
{
    if (wdt_counter == 0)
    {
        wdt_counter++;
        watchdogArm();
    }
    // Include your code here - be careful not to use functions they may cause the interrupt to hang and // prevent a reset.
}

Fuses used:
Fuses used:

I am about to conclude WDT is not really working with ATmega2560.
I would like to hear your opinions and most desirably a reliable working solution sample?

Best Answer

Here's a minimal example of using WDT on ATmega2560. Fuses on default (WDTON unprogrammed).

#include <avr/io.h>

int main(void)
{
    if(MCUSR & (1<<WDRF))    // check if reset by wdt
    {
        MCUSR = 0;   // clear flags
        DDRA = 1;    // indicate reset by wdt
        PORTA = 1;
    }

    // enable watchdog system reset
    WDTCSR |= (1<<WDCE) | (1<<WDE);
    // 256K cycles ~ 2 seconds
    WDTCSR = (1<<WDE) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0);

    while(1)
    {
        __asm__ __volatile__ ("wdr");    // feed wdt
    }
    return 0;
}

Comment out line __asm__ __volatile__ ("wdr"); and AVR will be reset by WDT after 2 seconds.

See the datasheet chapter 12.4 Watchdog Timer for more info.