Mam problem polegający na tym, że wykonanie sekwencji wyłączania watchdoga w AVR ATtiny84A faktycznie resetuje układ, mimo że zegar powinien mieć na to dużo czasu. Dzieje się to niekonsekwentnie i podczas uruchamiania tego samego kodu na wielu częściach fizycznych; niektóre resetują się za każdym razem, niektóre resetują czasami, a niektóre nigdy.
Aby zademonstrować problem, napisałem prosty program, który ...
- Włącza watchdoga z 1-sekundowym limitem czasu
- Resetuje watchdog
- Miga białą diodą LED przez 0,1 sekundy
- Błysnęła biała dioda LED na 0,1 sekundy
- Wyłącza organ nadzoru
Całkowity czas między włączeniem i wyłączeniem watchdoga jest krótszy niż 0,3 sekundy, ale czasami resetowanie watchdoga następuje po wykonaniu sekwencji wyłączania.
Oto kod:
#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.
}
}
Podczas uruchamiania program sprawdza, czy poprzedni reset został spowodowany przekroczeniem limitu czasu watchdoga, a jeśli tak, to zapala czerwoną diodę LED i usuwa flagę resetowania watchdoga, aby wskazać, że nastąpiło resetowanie watchdoga. Uważam, że ten kod nigdy nie powinien zostać wykonany, a czerwona dioda LED nigdy nie powinna się zapalić, ale często tak się dzieje.
Co tu się dzieje?
Odpowiedzi:
W procedurze biblioteki wdt_reset () występuje błąd.
Oto kod ...
Czwarta linia rozwija się do ...
Intencją tego wiersza jest zapisanie 1 do WD_CHANGE_BIT, który umożliwi następnej linii zapisanie 0 do bitu włączającego watchdog (WDE). Z arkusza danych:
Niestety, to przypisanie ma również efekt uboczny polegający na ustawieniu dolnych 3 bitów rejestru kontrolnego Watchdog (WDCE) na 0. To natychmiast ustawia preskaler na jego najkrótszą wartość. Jeśli nowy prescaler został już uruchomiony w momencie wykonania tej instrukcji, procesor zostanie zresetowany.
Ponieważ zegar nadzorujący uruchamia się niezależnie od fizycznie oscylatora 128 kHz, trudno jest przewidzieć, jaki będzie stan nowego preskalera w stosunku do uruchomionego programu. Uwzględnia to szeroki zakres zaobserwowanych zachowań, w których błąd może być skorelowany z napięciem zasilania, temperaturą i partią produkcyjną, ponieważ wszystkie te rzeczy mogą wpływać na prędkość oscylatora nadzorującego i zegara systemowego asymetrycznie. To był bardzo trudny błąd do znalezienia!
Oto zaktualizowany kod, który pozwala uniknąć tego problemu ...
Dodatkowa
wdr
instrukcja resetuje licznik czasu watchdoga, więc gdy następna linia potencjalnie przełączy się na inny prescaler, na pewno nie upłynął limit czasu.Można to również naprawić poprzez ORing WD_CHANGE_BIT i bitów WDE w WD_CONTROL_REGISTER, jak sugerowano w arkuszach danych ...
... ale wymaga to więcej kodu i dodatkowego rejestru scratch. Ponieważ licznik watchdoga jest zresetowany, gdy jest wyłączony, dodatkowy reset niczego nie blokuje i nie ma żadnych niezamierzonych skutków ubocznych.
źródło