I'm working on a battery powered project and want to use the SLEEP_MODE_PWR_DOWN setting to save power. My sensor appears to need some uptime of about 250ms between readings but inserting a "delay(250);" locks up the WatchDog Timer cycle.
Any idea what causes the WDT to fail when using longer delays?
I'm basing the WDT on work by Donal Morrisey.
Inserting a 100ms delay in the loop() section works fine but a 200ms delay locks up.
Note: If you're not familiar with using sleep modes, I learned a valuable lesson about how to recover your board after you think you've bricked it from the Adafruit site: Feather HELP! | Adafruit Feather 32u4 Adalogger | Adafruit Learning System
Also, the USB connection drops so don't be alarmed.
Thanks lastchancename. As it turns out I figured out the solution (without knowing the exact cause however).
I had done several searches and reviewed several examples; some setting the WDT registers during setup and some setting them with every cycle. I was doing the former and tried changing to the latter, which works!
Would still like to understand why.
For completeness and to make sure I understand protocol for future posts, here's the working code:
/*
* Sketch for testing sleep mode with wake up on WDT.
* Donal Morrissey - 2011.
*
* JHS - WORKS but loses USB connection! Use verbose mode and double click board when IDE looking for COM port
* Tested with SLEEP_MODE_PWR_DOWN, BUT setting BLINK_DELAY higher locks up the WDT
* WORKS!!! Needed to reset the registers one each cycle
*/
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
#define LED_PIN (13)
#define BLINK_DELAY 200 // NOTE: setting this to 50 works,
// setting it to 100 USED TO lock up the board
volatile int f_wdt=1;
/***************************************************
* Name: ISR(WDT_vect)
*
* Returns: Nothing.
*
* Parameters: None.
*
* Description: Watchdog Interrupt Service. This
* is executed when watchdog timed out.
*
***************************************************/
ISR(WDT_vect)
{
if(f_wdt == 0)
{
f_wdt=1;
}
else
{
Serial.println("WDT Overrun!!!");
}
}
/***************************************************
* Name: setWDTregisters
*
* Returns: Nothing.
*
* Parameters: None.
*
* Description: set the WDT registers
*
***************************************************/
void setWDTregisters()
{
/* Clear the reset flag. */
MCUSR &= ~(1<<WDRF);
/* In order to change WDE or the prescaler, we need to
* set WDCE (This will allow updates for 4 clock cycles).
*/
WDTCSR |= (1<<WDCE) | (1<<WDE);
/* set new watchdog timeout prescaler value */
WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */
/* Enable the WD interrupt (note no reset). */
WDTCSR |= _BV(WDIE);
}
/***************************************************
* Name: enterSleep
*
* Returns: Nothing.
*
* Parameters: None.
*
* Description: Enters the arduino into sleep mode.
*
***************************************************/
void enterSleep(void)
{
setWDTregisters(); // <<<< added to prevent board from locking up
set_sleep_mode(SLEEP_MODE_PWR_DOWN); /* EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption. */
sleep_enable();
/* Now enter sleep mode. */
sleep_mode();
/* The program will continue from here after the WDT timeout*/
sleep_disable(); /* First thing to do is disable sleep. */
/* Re-enable the peripherals. */
power_all_enable();
}
/***************************************************
* Name: setup
*
* Returns: Nothing.
*
* Parameters: None.
*
* Description: Setup for the serial comms and the
* Watch dog timeout.
*
***************************************************/
void setup()
{
Serial.begin(9600);
Serial.println("Initialising...");
delay(100); //Allow for serial print to complete.
pinMode(LED_PIN,OUTPUT);
/*** Setup the WDT ***/
setWDTregisters();
Serial.println("Initialisation complete.");
delay(100); //Allow for serial print to complete.
}
/***************************************************
* Name: enterSleep
*
* Returns: Nothing.
*
* Parameters: None.
*
* Description: Main application loop.
*
***************************************************/
void loop()
{
// Blink(LED_PIN, 80,3);
digitalWrite(LED_PIN,!digitalRead(LED_PIN));
delay(BLINK_DELAY); //<<<<< setting this and the next delay to 50 works but 100 locks up the WDT
digitalWrite(LED_PIN,!digitalRead(LED_PIN));
delay(BLINK_DELAY);
if(f_wdt == 1)
{
/* Toggle the LED */
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
/* Don't forget to clear the flag. */
f_wdt = 0;
/* Re-enter sleep mode. */
enterSleep();
}
else
{
/* Do nothing. */
}
}