Ich habe ein Problem, bei dem das Ausführen einer Watchdog-Deaktivierungssequenz auf einem AVR ATtiny84A den Chip zurücksetzt, obwohl der Timer noch genügend Zeit haben sollte. Dies geschieht inkonsistent und wenn auf vielen physischen Teilen derselbe Code ausgeführt wird. Einige werden jedes Mal zurückgesetzt, andere manchmal und wieder andere nie.
Um das Problem zu demonstrieren, habe ich ein einfaches Programm geschrieben, das ...
- Aktiviert den Watchdog mit einem Timeout von 1 Sekunde
- Setzt den Watchdog zurück
- Blinkt die weiße LED für 0,1 Sekunden
- Blinkt die weiße LED für 0,1 Sekunden aus
- Deaktiviert den Watchdog
Die Gesamtzeit zwischen dem Aktivieren und Deaktivieren des Watchdogs beträgt weniger als 0,3 Sekunden. Manchmal tritt jedoch ein Watchdog-Reset auf, wenn die Deaktivierungssequenz ausgeführt wird.
Hier ist der 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.
}
}
Beim Start prüft das Programm, ob der vorherige Reset durch ein Watchdog-Timeout verursacht wurde. In diesem Fall leuchtet die rote LED und das Flag zum Zurücksetzen des Watchdogs wird gelöscht, um anzuzeigen, dass ein Watchdog-Reset stattgefunden hat. Ich bin der Meinung, dass dieser Code niemals ausgeführt werden sollte und die rote LED niemals aufleuchten sollte, was jedoch häufig der Fall ist.
Was geht hier vor sich?