Atmega328 watchdog

Hi,

Has anybody managed to put the watchdog timer (sole purpose to check for code lockups) and sleep together in one project?

There doesn't seem to be many examples of this.

Cheers

Have a look at this page: Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors 'Sketch I' is an example.

Thanks.

The sketch from Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors uses a watchdog timer to wake up from sleep mode. I would like to use an external interrupt on D2 or D3 to wake up the Arduino only, and only use the watchdog to protect against code lockups. The only problem is, when the Arduino is sleeping when using the watchdog, it resets the program after it times out.

Should the watchdog be disabled when sleeping or is there another way to handle this? Eventually, i would like to use a very low power board that can run for years and cannot lock up in any way.

Thank you

The watchdog has an independent clock generator. It does not care whether the processor is sleeping or not. So you MUST disable the WD before going to sleep

With the Arduino sleeping and the watchdog disabled, is there any chance that something could happen (locks up) that would prevent an external interrupt from waking it up, and hence it remains in sleep mode?

I'm just thinking whether there needs to be some sort of watchdog protection whilst sleeping also, or maybe this is not necessary?

In sleep mode, the processor does nothing, so there is nothing to "lock up".

Thanks for your responses.

I will use 2 external interrupts on pins D2 and D3 to wake up from sleep.

A watchdog is enabled to detect program lockups whilst not sleeping. This is disabled as this shouldn't be a problem when sleeping. I am after a super reliable setup that will never be powered down.

Below is the code: Does it look ok?

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


void setup()
{
    Serial.begin(9600);
    Serial.println("starting...");
    
    digitalWrite (2, HIGH);    // pull-up on button
    digitalWrite (3, HIGH);    // pull-up on button
    
    //enable watchdog to check for code lockups
    wdt_enable(WDTO_8S);
}


// interrupt service routine in sleep mode
void wake1 ()
{
  
}  // end of wake

// interrupt service routine in sleep mode
void wake2 ()
{
  
}  // end of wake


void sleepNow ()
{   
    wdt_disable();
    
    byte adcsra_save = ADCSRA;
    ADCSRA = 0;  // disable ADC
    power_all_disable ();   // turn off all modules
    set_sleep_mode (SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
    sleep_enable();
    attachInterrupt (0, wake1, LOW);   // allow grounding pin 2 to wake us
    attachInterrupt (1, wake2, LOW);   // allow grounding pin 2 to wake us
    interrupts ();
    sleep_cpu ();            // now goes to Sleep and waits for the interrupt
    detachInterrupt (0);     // stop LOW interrupt
    detachInterrupt (1);     // stop LOW interrupt
    
    ADCSRA = adcsra_save;  // stop power reduction
    power_all_enable ();   // turn on all modules 
}  // end of sleepNow


void loop()
{
    //reset watchdog timer
    wdt_reset(); 
    
    delay(1000);
    Serial.println("1");
    delay(1000);
    Serial.println("2");
    delay(1000);
    Serial.println("3");
    delay(1000);
    
    sleepNow();
    //while(1);
}

Thanks

Do the repeated attach/detach interrupts serve some purpose?

Do the repeated attach/detach interrupts serve some purpose?

Yes, the board can wake up from sleep in two different ways and perform different functions based on which is selected:

  1. button is pressed to wake up from sleep
  2. signal from battery charger IC to wake up and show battery status via led

Is there any dangers with this approach?

I still see no purpose for the repeated attach/detach. The most reliable code does as as little as the task requires.

I wouldn't even trust that process, and would use the ISR vectors as they were originally designed to be used with avr-gcc.

I wouldn't even trust that process, and would use the ISR vectors as they were originally designed to be used with avr-gcc.

How exactly should the ISR vectors be incorporated instead?

Thanks

Instead of writing functions named wake1 and wake2 and using attach/detach you simply have instead

ISR (INT0_vect) { //handle external interrupt 0
// do something
}

In setup(), you need to configure the interrupt source once (i.e. trigger levels, etc.). Details are in the avr-libc documentation and of course, the ATMega328 data sheet.

Please check below.

I added the watchdog protection for lockups for when the board is awake.

After waking up, the program just prints a few numbers then goes back to sleep until interrupted by D2 or D3 on a low. Again, i am after a very reliable setup.

#include <avr/sleep.h>                  
#include <avr/power.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>    // Needed to use interrupts
 
 
volatile int int0_flag;
volatile int int1_flag;

#define TRUE 1
#define FALSE 0

ISR(INT0_vect)
{
    int0_flag = TRUE;    
}


ISR(INT1_vect)
{
    int1_flag = TRUE;    
}


void sleepNow()
{   
    wdt_disable();
    
    byte adcsra_save = ADCSRA;
    ADCSRA = 0;  // disable ADC
    power_all_disable ();   // turn off all modules
    set_sleep_mode (SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
    
    noInterrupts();
    
    sleep_enable(); 
    
    interrupts();
    sleep_cpu ();            // now goes to Sleep and waits for the interrupt 
    sleep_disable ();      // precaution
    ADCSRA = adcsra_save;  // stop power reduction
    power_all_enable ();   // turn on all modules 
    
    //enable watchdog to check for code lockups
    wdt_enable(WDTO_8S);
}  // end of sleepNow


void setup()
{
 
   Serial.begin(9600);
   Serial.println("starting...");      
     
   pinMode(2, INPUT);
   pinMode(3, INPUT);
   
   digitalWrite(2, HIGH);
   digitalWrite(3, HIGH);
       
   EICRA = B00001010; // configure pin 2 and 3 for falling
   EIMSK = B00000011; // mask for INT1 and INT0
   
   int1_flag = FALSE;
   int0_flag = FALSE;  
   
   wdt_enable(WDTO_8S);
   
   Serial.println("ready...");  
}

void loop()
{       
       if (int0_flag == TRUE)
       {
            Serial.println("wake up from INT0");   
            int0_flag = FALSE;
       } 
       if (int1_flag == TRUE)
       {
            Serial.println("wake up from INT1");  
            int1_flag = FALSE;
       }
       
       Serial.println("1");
       delay(1000);
       Serial.println("2");
       delay(1000);
       Serial.println("3");
       delay(1000);
       sleepNow();
       //while (1);
}

Thanks

Can anyone confirm my code below? Reliability is crucial. It uses 2 interrupts to wake up from sleep.

#include <avr/sleep.h>                  
#include <avr/power.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>    // Needed to use interrupts
 
 
volatile int int0_flag;
volatile int int1_flag;

#define TRUE 1
#define FALSE 0

ISR(INT0_vect)
{
    int0_flag = TRUE;    
}


ISR(INT1_vect)
{
    int1_flag = TRUE;    
}


void sleepNow()
{   
    wdt_disable();
    
    byte adcsra_save = ADCSRA;
    ADCSRA = 0;  // disable ADC
    power_all_disable ();   // turn off all modules
    set_sleep_mode (SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
    
    noInterrupts();
    
    sleep_enable(); 
    
    interrupts();
    sleep_cpu ();            // now goes to Sleep and waits for the interrupt 
    sleep_disable ();      // precaution
    ADCSRA = adcsra_save;  // stop power reduction
    power_all_enable ();   // turn on all modules 
    
    //enable watchdog to check for code lockups
    wdt_enable(WDTO_8S);
}  // end of sleepNow


void setup()
{
 
   Serial.begin(9600);
   Serial.println("starting...");      
     
   pinMode(2, INPUT);
   pinMode(3, INPUT);
   
   digitalWrite(2, HIGH);
   digitalWrite(3, HIGH);
       
   EICRA = B00001010; // configure pin 2 and 3 for falling
   EIMSK = B00000011; // mask for INT1 and INT0
   
   int1_flag = FALSE;
   int0_flag = FALSE;  
   
   wdt_enable(WDTO_8S);
   
   Serial.println("ready...");  
}

void loop()
{       
       if (int0_flag == TRUE)
       {
            Serial.println("wake up from INT0");   
            int0_flag = FALSE;
       } 
       if (int1_flag == TRUE)
       {
            Serial.println("wake up from INT1");  
            int1_flag = FALSE;
       }
       
       Serial.println("1");
       delay(1000);
       Serial.println("2");
       delay(1000);
       Serial.println("3");
       delay(1000);
       sleepNow();
       //while (1);
}

Thank you