Estou tendo um problema em que a execução de uma sequência de watchdog de desativação em um AVR ATtiny84A está realmente redefinindo o chip, mesmo que o temporizador deva ter bastante tempo nele. Isso acontece inconsistentemente e ao executar o mesmo código em várias partes físicas; alguns são redefinidos toda vez, outros são redefinidos algumas vezes e outros nunca.
Para demonstrar o problema, escrevi um programa simples que ...
- Ativa o cão de guarda com um tempo limite de 1 segundo
- Redefine o watchdog
- Pisca o LED branco por 0,1 segundos
- Piscou o LED branco por 0,1 segundos
- Desativa o cão de guarda
O tempo total entre a ativação e desativação do watchdog é inferior a 0,3 segundos, mas às vezes ocorre uma redefinição do watchdog quando a sequência de desativação é executada.
Aqui está o código:
#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.
}
}
Na inicialização, o programa verifica se a redefinição anterior foi causada por um tempo limite do watchdog e, nesse caso, acende o LED vermelho e apaga o sinalizador de redefinição do watchdog para indicar que ocorreu uma redefinição do watchdog. Acredito que esse código nunca deve ser executado e o LED vermelho nunca deve acender, mas geralmente ocorre.
O que está acontecendo aqui?
Respostas:
Há um erro na rotina da biblioteca wdt_reset ().
Aqui está o código ...
A quarta linha se expande para ...
A intenção desta linha é escrever um 1 no WD_CHANGE_BIT, o que permitirá que a linha a seguir escreva um 0 no bit de ativação do watchdog (WDE). A partir da folha de dados:
Infelizmente, essa atribuição tem o efeito colateral de também definir os 3 bits inferiores do Watchdog Control Register (WDCE) como 0s. Isso define imediatamente o pré-calibrador para seu valor mais curto. Se o novo pré-calibrador já foi acionado no momento em que esta instrução é executada, o processador será redefinido.
Como o timer do watchdog roda em um oscilador fisicamente independente de 128 kHz, é difícil prever qual será o estado do novo pré-calibrador em relação ao programa em execução. Isso explica a ampla gama de comportamentos observados, nos quais o erro pode ser correlacionado com a tensão de alimentação, temperatura e lote de fabricação, pois todas essas coisas podem afetar a velocidade do oscilador do watchdog e do relógio do sistema assimetricamente. Este foi um bug muito difícil de encontrar!
Aqui está o código atualizado que evita esse problema ...
As
wdr
instruções extras redefinem o timer do watchdog; portanto, quando a linha a seguir potencialmente mudar para um pré-calibrador diferente, é garantido que o tempo limite ainda não foi atingido.Isso também pode ser corrigido ORing os bits WD_CHANGE_BIT e WDE no WD_CONTROL_REGISTER, conforme sugerido nas folhas de dados ...
... mas isso requer mais código e um registro extra de rascunho. Como o contador do watchdog é redefinido quando desativado, a redefinição extra não atrapalha nada e não tem efeitos colaterais não intencionais.
fonte