¿Cómo evito un restablecimiento cuando uso el watchdog en modo de interrupción y cambio el tiempo de espera?

3

Estoy escribiendo un programa para un ATtiny85. Quiero usar el watchdog para despertarme del apagado en ciertos intervalos. Todo funciona bien siempre y cuando los intervalos para un evento de perro guardián no cambien dentro del programa (es decir, no cambio los bits WDP0-3 después de que se configuren una vez).

Tan pronto como cambio el tiempo de espera del perro guardián, realiza un reinicio no deseado. No tengo el fusebit WDTON habilitado, por lo que el perro gordo no siempre está encendido, sino que tiene que estar habilitado por el software. (De hecho, los bits de los fusibles son: Bajo = 0xe2, Alto = 0xdf y Extendido = 0xff hacen que el controlador funcione a 8 Mhz desde el oscilador interno).

Aquí hay un recorte de mi código:

#include <avr/wdt.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>

void Config_wdt(uint8_t timeout) {
    cli();
    wdt_reset();                  // reset watchdog timer
    MCUSR &= ~(1<<WDRF);          // clear reset flag
    WDTCR = (1<<WDE) | (1<<WDCE); // enable watchdog
    WDTCR = (1<<WDIE) | timeout;  // watchdog interrupt instead of reset
    //+reset, timeout can be 15,30,60,120,250,500ms or 1,2,4,8s
    sei();
}

EMPTY_INTERRUPT(WDT_vect)

void Sleep_now(uint8_t i, uint8_t timeout) {
  Config_wdt(timeout);
  for(i=i; i>0; --i) {
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // set type of sleepmode
    power_all_disable();                  // disable unneeded loads
    wdt_reset();                          // timer should start at zero
    sleep_enable();                       // approach sleep mode
    sleep_mode();                         // enter sleep mode (confirm)
    sleep_disable();                      // entrance point when woken up
    // Another Config_wdt(timeout); here or re-enabling WDIE doesn't help either
    power_all_enable();                   // re-enable the loads
  }
}

int main() {
  Config_wdt(WDTO_500MS);

  Do_some_stuff();
  Sleep_now(5, WDTO_500MS); // WORKS AS EXPECTED, SLEEPS 5 TIMES 500ms = 2.5s

  while(1) {
      Make_other_things();
      Sleep_now(3, WDTO_30MS); // DOES AN UNWANTED RESET, ...
      \+I.E. STARTS FROM THE BEGINNING BEFORE "Do_some_sfuff()"...
      \+IF I REPLACE "WDTO_30MS" HERE by "WDTO_500MS" FROM ABOVE...
      \+THE CODE WORKS FINE.
  }
}

La hoja de datos tiene esto que decir:

  

Si se establece WDE, WDIE se borra automáticamente por el hardware cuando se produce un tiempo de espera. Esto es útil para mantener el   Watchdog Reinicia la seguridad mientras usas la interrupción Una vez que se borra el bit WDIE, el siguiente tiempo de espera generará un   Reiniciar. Para evitar el restablecimiento de Watchdog, WDIE debe configurarse después de cada interrupción.

Pero incluso si configuro el bit WDIE inmediatamente después de levantarme del modo de suspensión, todavía se hace un reinicio no deseado.

Entonces, ¿cómo cambio el tiempo de espera de vigilancia en mi código, sin el reinicio no deseado?

    
pregunta con-f-use

1 respuesta

2

No puedo reproducir este comportamiento. Estoy usando un ATTINY85 con los valores de fusible dados.

Para probar, creé Do_some_stuff () que hace parpadear un LED blanco durante 1 segundo, y Make_other_things () hace que parpadee un LED rojo durante 1 segundo.

En el encendido ...

  1. El LED blanco parpadea durante ~ 1 segundo mientras se ejecuta Do_some_stuff ()
  2. Hay una pausa de ~ 2.5 segundos mientras se ejecuta Sleep_now (5, WDTO_500MS)
  3. El LED rojo parpadea durante ~ 1 segundo mientras se ejecuta Make_other_things ()
  4. Hay una pausa de ~ 100ms mientras se ejecuta Sleep_now (3, WDTO_30MS)
  5. Los pasos 3-4 se repiten indefinidamente

Aquí hay una vista de alcance después del encendido ...

Traza amarilla = LED blanco
Traza púrpura = LED rojo

El código que estoy usando está aquí ...

/*
 * CrazyWatchDogResetTest.c
 * Target: ATTINY85 default fuses
 * Created: 1/30/2015 12:22:44 PM
 *  Author: josh
 */ 

#define F_CPU 8000000                       // Name used by delay.h. We are running 1Mhz (default fuses)

#include <avr/io.h>
#include <util/delay.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>

// White LED connected to pin 5

#define WHITE_LED_PORT PORTB
#define WHITE_LED_DDR DDRB
#define WHITE_LED_BIT 0


// Red LED connected to pin 6 

#define RED_LED_PORT PORTB  
#define RED_LED_PIN PINB
#define RED_LED_DDR DDRB
#define RED_LED_BIT 1


// Blink white LED for 1 second

void Do_some_stuff() {

    WHITE_LED_DDR |= _BV(WHITE_LED_BIT);
    WHITE_LED_PORT |= _BV(WHITE_LED_BIT);   
    _delay_ms(1000);
    WHITE_LED_PORT &= ~_BV(WHITE_LED_BIT);

}


// Blink red LED for 1 second

void Make_other_things() {

    RED_LED_DDR |= _BV(RED_LED_BIT);    
    RED_LED_PORT|=_BV(RED_LED_BIT);
    _delay_ms(1000);
    RED_LED_PORT&=~_BV(RED_LED_BIT);

}

void Config_wdt(uint8_t timeout) {
    cli();
    wdt_reset();                  // reset watchdog timer
    MCUSR &= ~(1<<WDRF);          // clear reset flag
    WDTCR = (1<<WDE) | (1<<WDCE); // enable watchdog
    WDTCR = (1<<WDIE) | timeout;  // watchdog interrupt instead of reset
    //+reset, timeout can be 15,30,60,120,250,500ms or 1,2,4,8s
    sei();
}

EMPTY_INTERRUPT(WDT_vect)

void Sleep_now(uint8_t i, uint8_t timeout) {
    Config_wdt(timeout);
    for(i=i; i>0; --i) {
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // set type of sleepmode
        power_all_disable();                  // disable unneeded loads
        wdt_reset();                          // timer should start at zero
        sleep_enable();                       // approach sleep mode
        sleep_mode();                         // enter sleep mode (confirm)
        sleep_disable();                      // entrance point when woken up
        // Another Config_wdt(timeout); here or re-enabling WDIE doesn't help either
        power_all_enable();                   // re-enable the loads
    }
}


int main(void)
{

 Config_wdt(WDTO_500MS);

 Do_some_stuff();

 Sleep_now(5, WDTO_500MS); // WORKS AS EXPECTED, SLEEPS 5 TIMES 500ms = 2.5s

 while(1) {
     Make_other_things();
     Sleep_now(3, WDTO_30MS); // DOES AN UNWANTED RESET, ...
 }

}

... que creo que es idéntico al tuyo, excepto por las funciones adicionales.

¿Puedes probar este código y ver si obtienes resultados inesperados? Si es así, ¿puede pensar en alguna diferencia introducida por su código que pueda explicar el comportamiento diferente?

    
respondido por el bigjosh

Lea otras preguntas en las etiquetas