I am having a problem where executing a disable watchdog sequence on an AVR ATtiny84A is actually resetting the chip even though the timer should have plenty of time left on it. This happens inconsistently and when running the same code on many physical parts; some reset every time, some reset sometimes, and some never.
To demonstrate the problem, I have written a simple program which...
- Enables the watchdog with a 1 second timeout
- Resets the watchdog
- Flashes the white LED on for 0.1 seconds
- Flashed the white LED off for 0.1 seconds
- Disables the watchdog
The total time between the watchdog enable and disable is less than 0.3 seconds, yet sometimes a watchdog reset occurs when the disable sequence is executed.
Here is the code:
#define F_CPU 1000000 // Name used by delay.h. We are running 1Mhz (default fuses)
#include <avr/io.h>
#include <util/delay.h>
#include <avr/wdt.h>
// White LED connected to pin 8 - PA5
#define WHITE_LED_PORT PORTA
#define WHITE_LED_DDR DDRA
#define WHITE_LED_BIT 5
// Red LED connected to pin 7 - PA6
#define RED_LED_PORT PORTA
#define RED_LED_DDR DDRA
#define RED_LED_BIT 6
int main(void)
{
// Set LED pins to output mode
RED_LED_DDR |= _BV(RED_LED_BIT);
WHITE_LED_DDR |= _BV(WHITE_LED_BIT);
// Are we coming out of a watchdog reset?
// WDRF: Watchdog Reset Flag
// This bit is set if a watchdog reset occurs. The bit is reset by a Power-on Reset, or by writing a
// logic zero to the flag
if (MCUSR & _BV(WDRF) ) {
// We should never get here!
// Light the RED led to show it happened
RED_LED_PORT |= _BV(RED_LED_BIT);
MCUCR = 0; // Clear the flag for next time
}
while(1)
{
// Enable a 1 second watchdog
wdt_enable( WDTO_1S );
wdt_reset(); // Not necessary since the enable macro does it, but just to be 100% sure
// Flash white LED for 0.1 second just so we know it is running
WHITE_LED_PORT |= _BV(WHITE_LED_BIT);
_delay_ms(100);
WHITE_LED_PORT &= ~_BV(WHITE_LED_BIT);
_delay_ms(100);
// Ok, when we get here, it has only been about 0.2 seconds since we reset the watchdog.
wdt_disable(); // Turn off the watchdog with plenty of time to spare.
}
}
At startup, the program checks to see if the previous reset was caused by a watchdog timeout, and if so it it lights the red LED and clears the watchdog reset flag to indicate that a watchdog reset happened. I believe that this code should never be executed and the red LED should never come on, yet it often does.
What is going on here?