I have been struggling to get my Adafruit 5v pro mini to loop in deep sleep mode several times, then awake to perform something then return to the deep sleep mode loop. While it is out of deep sleep mode I want the watchdog timer to be active to protect against system hangups. Although I can get in and out of deep sleep mode easy enough, and I can also use a loop that performs one deep sleep/awake cycle. I want to maximize the power savings by having a prolonged deep sleep period of several minutes. I have read many posts related to this subject, but have not yet found a response works for me. Attached is my code, which loops through the sleep cycle twice, but not if ISR(WDT_vect) on row 85 calls my hardwareReset() function. If my call to hardwareReset is used, my test loop on rows 25-30 times out as expected, but my waitSleep function no longer loops twice. Can anyone please offer guidance? Many thanks
// thanks to KeyChainino for basic code. I added ADC disable to further reduce power from 0.67mA to 0.54mA
//
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
const int ledPin = 13;
const int resetPin = 9;
// the setup function runs once when you press reset or power the board
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin,HIGH);
Serial.begin(9600);
Serial.println("Resetting..");
delay(100);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
for(int i=0; i<9; i++){; //set up loop to force timeout of WDT
delay(1000);
Serial.print("Loop ");
Serial.println(i);
delay(100);
}
waitSleep(2); //go sleep for x loops of WDT settings (8 sec max per loop)
}
void waitSleep(int sleep_cycles) {
while (sleep_cycles) {
goSleep();
sleep_cycles--;
}
}
void goSleep() {
watchdogSetup(); //enable watchDog
// disable ADC (analog to digital conversion)
byte old_ADCSRA = ADCSRA;
ADCSRA = 0;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_mode();
//disable watchdog after sleep
wdt_disable();
ADCSRA = old_ADCSRA;
}
void watchdogSetup() {
//WDP3 - WDP2 - WPD1 - WDP0 - time
// 0 0 0 0 16 ms
// 0 0 0 1 32 ms
// 0 0 1 0 64 ms
// 0 0 1 1 0.125 s
// 0 1 0 0 0.25 s
// 0 1 0 1 0.5 s
// 0 1 1 0 1.0 s
// 0 1 1 1 2.0 s
// 1 0 0 0 4.0 s
// 1 0 0 1 8.0 s
// Reset the watchdog reset flag
bitClear(MCUSR, WDRF);
//The following bit have to be set at the same time otherwise the system doesn't set the right value
/* Start timed equence */
//Watchdog Change Enable to clear WD (by setting the WDCE bit) and Enable WD (by setting the WDE bit)
WDTCSR |= (1 << WDCE) | (1 << WDE);
//Set new watchdog timeout value to 8 seconds (WDP3 and WDP0 to 1) and enable interrupts instead of reset (WDIE to 1)
WDTCSR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0) ;
}
void hardwareReset(){;
digitalWrite(resetPin,LOW);
}
ISR(WDT_vect) {
//hardwareReset();
}
loop to force timeout
is called before the watchdog is setup. So this only works the second time around. Maybe you do this for testing, but I always put this in mysetup
function (minus the WDIE bit, that is). Remember that later on you need to call wdt_reset(); if you expect the loop the take more than 8 seconds.I didn't want the interrupt to fire only once
; you can. You just have to set the WDIE bit after each time the interrupt is called. In you case that would be, setting the WDIE bit each time the MCU goes to sleep. Maybe you could tell what it is you are trying to achieve in the end, instead of what isn't working as you expect in your piece of test-code. As I'm still not fully getting what it is you are asking/expecting.