Sto riscontrando un problema in cui l'esecuzione di una sequenza di watchdog di disabilitazione su un AVR ATtiny84A sta effettivamente ripristinando il chip anche se al timer dovrebbe essere rimasto un sacco di tempo. Ciò accade in modo incoerente e quando si esegue lo stesso codice su molte parti fisiche; alcuni ripristinano ogni volta, alcuni ripristinano a volte e altri mai.
Per dimostrare il problema, ho scritto un semplice programma che ...
- Abilita il watchdog con un timeout di 1 secondo
- Reimposta il cane da guardia
- Lampeggia il LED bianco acceso per 0,1 secondi
- Lampeggiava il LED bianco spento per 0,1 secondi
- Disabilita il cane da guardia
Il tempo totale tra l'abilitazione e la disabilitazione del watchdog è inferiore a 0,3 secondi, tuttavia a volte si verifica un reset del watchdog quando viene eseguita la sequenza di disabilitazione.
Ecco il codice:
#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.
}
}
All'avvio, il programma verifica se il ripristino precedente è stato causato da un timeout del watchdog e, in tal caso, accende il LED rosso e cancella il flag di reset del watchdog per indicare che si è verificato un reset del watchdog. Credo che questo codice non dovrebbe mai essere eseguito e il LED rosso non dovrebbe mai accendersi, eppure lo fa spesso.
Cosa sta succedendo qui?