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
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:
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