How to tell if restart from WDT timeout

Is there a way to determine if an Arduino restarted as a result of a WDT timeout?

Yes, bit 3 in the MCUSR - MCU Status register is set when a watchdog System reset occurs.

See page 54 of the 328 data sheet

Grumpy_Mike:
Yes, bit 3 in the MCUSR - MCU Status register is set when a watchdog System reset occurs.

See page 54 of the 328 data sheet

Thanks. Is this how I would check that bit:

bool wdt_reset  = (MCUSR >> 3) & 1;

Is this how I would check that bit:

No it is how you would isolate the bit, check it with an if statement.

Grumpy_Mike:

Is this how I would check that bit:

No it is how you would isolate the bit, check it with an if statement.

Like this?

if( (MCUSR >> 3) & 1 == 1) 
{ 
// restarted with WDT 
}

I would put the extra brackets in so there is no ambiguity as to the order of the operators.

if( ((MCUSR >> 3) & 1) == 1) 
{ 
// restarted with WDT 
}

I just tried this test sketch. The Arduino (Uno) reboots after a while but I’m not reading MCUSR bit 3 as high afterwards. The LED should blink every 50mS if bit 3 is set.

  #include <avr/wdt.h>
  int loop_count = 0;
   
  void setup()
  {
    watchdogSetup();
    Serial.begin(9600);
    delay (1000);
    Serial.println("Starting up...");
    pinMode(13,OUTPUT);
    digitalWrite(13,HIGH);

  }
   
  void watchdogSetup(void)
  {
    cli();       // disable all interrupts
    wdt_reset(); // reset the WDT timer
   
    // Enter Watchdog Configuration mode:
    WDTCSR |= (1<<WDCE) | (1<<WDE);
    // Set Watchdog settings -  Interrupt enabled, Reset enabled, 8 second timeout
    WDTCSR = (1<<WDIE) | (1<<WDE) | (1<<WDP3) | (0<<WDP2) | (0<<WDP1) | (1<<WDP0);
   
    sei();  // Enable interrupts
  }
   
  void loop()
  {
    int ledDelay;
    if ((MCUSR >> 3) & 1 == 1)
    { ledDelay = 50; }
    else
    { ledDelay = 500; }
    
    static uint32_t millisLast = millis();
    for (int i = 0; i <= loop_count;i++)
    {
      digitalWrite(13, HIGH);
      delay(ledDelay);
      digitalWrite(13, LOW);
      delay(ledDelay);
    }
   
    loop_count++;
    wdt_reset();
    
    Serial.print(loop_count);
    Serial.print(". Watchdog fed in approx. ");
    Serial.print( millis()-millisLast );
    Serial.println(" milliseconds.");
    millisLast = millis();
  }

if( ((MCUSR >> 3) & 1) == 1)

Why not just

if (MCUSR&8)

KenF:

if( ((MCUSR >> 3) & 1) == 1)

Why not just

if (MCUSR&8)

That would work too. It's a bit simpler.

The MCUSR register is cleared by the bootloader. You will have to install the latest bootloader and use code similar to this...

Can’t be done with the bootloader. External resets get reported as WDRF, not EXTRF; if you’re using the WDT, that doesn’t help. When I want the straight dope, I lose the bootloader. See discussion here:

I looked at the code in the post you linked too. Where would I put that code, just in my main sketch?
It sounds like I would need to use optiboot 5.0a with my Uno. Or am I misunderstanding this and I would have upload my program using an ISP and not have a bootloader at all - never tried that.

ScottG:
I looked at the code in the post you linked too. Where would I put that code, just in my main sketch?
It sounds like I would need to use optiboot 5.0a with my Uno. Or am I misunderstanding this and I would have upload my program using an ISP and not have a bootloader at all - never tried that.

Complete but basic code here, and yes ISP programming is required (near as I can tell) to get an accurate copy of MCUSR for all conditions. An ISP is well worth having and learning to use.

The latest version of Optiboot will give a less-than-perfect representation of MCUSR when the reset occurred. This is an improvement over previous versions which gave none. If it's not required to distinguish between an external reset and a watchdog reset, I think Optiboot would work.

If you want to know if the device was just powered on or not, checking for a signature in RAM can do it:

#include <avr/wdt.h>

void checkIfColdStart ()
  {
  const char signature [] = "NickGammon";
  char * p = (char *) malloc (sizeof (signature));
  if (strcmp (p, signature) == 0)   // signature already there
    Serial.println ("Watchdog activated.");
  else
    {
    Serial.println ("Cold start.");
    memcpy (p, signature, sizeof signature);  // copy signature into RAM
    }
  }  // end of checkIfColdStart

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  checkIfColdStart ();
  
  wdt_reset();  // pat the dog
  wdt_enable(WDTO_1S);
  }  // end of setup

void loop () { }

This assumes that the signature string “NickGammon” won’t just happen to be in RAM after you power on the device. :slight_smile:

However this won’t detect hard resets (someone hitting the Reset button) but would be pretty good to tell the difference between being powered on from cold, and a watchdog timeout.

Interestingly, that does not always work. Apparently, the very very miniscule power generated by an LED connected to a pin is enough to maintain the SRAM contents. The current makes its way to the power rail through the protection diodes. The current is not nearly enough to bring the processor to life but is enough to keep the SRAM contents intact.

I'll let you know if / when I find the article. Udo Klein may have posted something about it.

Found it…

That’s pretty clever. I could even use some EEPROM memory to count how many times a WDT restarts happen.

ScottG:
That's pretty clever. I could even use some EEPROM memory to count how many times a WDT restarts happen.

I didn't want to use EEPROM because there is a limit to the number of times you can write to it (a fairly large limit, but still). Anyway, with EEPROM, how do you know what the significance of the number is? Say you read 42. How do you know it was last 41?

Probably the simplest thing to do is disable the bootloader (by changing one fuse bit) and directly reading MCUSR at reset. You can always put the bit back, or program using ICSP.

Hmm. Measuring a standard green LED under fairly dim light in the early morning I read 1.1V output, rising to about 1.6V with a LED torch shining on it. The current is pretty-much unmeasurable under low light, rising to about 0.9 µA with the torch shining on it.

I can't reproduce the described behaviour on a Uno, even with the torch shining right at a LED+resistor. Perhaps the load of the devices on the board consumes too much. The article you refer to described a "bare bones" ATTINY4313.

Or, the voltage drop across the protection diodes is too much. Or, the brown-out detector is devouring the LED-power. But I suspect your theory is correct.

Your LED-produced voltage is high enough. Despite the datasheet floor being 1.8V I know AVR processors will actually run from 1.6V. Maintaining the SRAM state at 1.6V should be a breeze.

Your LED-current is well above what the processor needs when asleep. Maintaining the SRAM state at 0.9 µA should be a breeze.

In any case, it is possible for SRAM to not be erased from a power-cycle.