Great library and I am using it in my project.
I need to be able to get a more accurate duration of the watchdog timout period so I can correct for this in the application.
My measurements show that the watchdog timer is not very accurate at all! eg using SLEEP_4S produces a time of over 4.5 seconds on my Nano.
This is not a problem as long as I can correct for this.
What's needed is a way to call LowPower.powerDown (for example) with a flag so it doesn't actually go to sleep and keeping millis() running when it is set.
Then I could calculate the time before and after the call and get a reasonably accurate millisecond duration.
I made some changes my copy of the library and it all seems to work as I wanted:
LowPower.h
// add noLowPower argument to powerDown with default for backward compatability
void powerDown(period_t period, adc_t adc, bod_t bod, bool noLowPower = false) attribute((optimize("-O1")));
// add new static flag
static volatile bool wdtFinished;
LowPower.cpp
// add new wdtFinished flag
volatile bool LowPowerClass::wdtFinished;
// use new noLowPower argument to prevent entering low power and block until wdt has fired
void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod, bool noLowPower)
{
if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN);
if (period != SLEEP_FOREVER)
{
wdt_enable(period);
WDTCSR |= (1 << WDIE);
}
if (noLowPower) {
wdtFinished = false;
while (!wdtFinished) {;}
}
else {
if (bod == BOD_OFF)
{
#if defined (AVR_ATmega328P) || defined (AVR_ATmega168P)
lowPowerBodOff(SLEEP_MODE_PWR_DOWN);
#else
lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
#endif
}
else
{
lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
}
if (adc == ADC_OFF) ADCSRA |= (1 << ADEN);
}
}
// set wdt finished flag
ISR (WDT_vect)
{
// WDIE & WDIF is cleared in hardware upon entering this ISR
wdt_disable();
LowPowerClass::wdtFinished = true;
}
I then use it it:
// calibrate watchdog timeout
sleepPeriodMs = millis();
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_ON, true);
sleepPeriodMs = millis() - sleepPeriodMs;
Serial.println(sleepPeriodMs);
I have only implemented the change to powerDown but it could also be added to the other calls.
Cheers, Julian
Great library and I am using it in my project.
I need to be able to get a more accurate duration of the watchdog timout period so I can correct for this in the application.
My measurements show that the watchdog timer is not very accurate at all! eg using SLEEP_4S produces a time of over 4.5 seconds on my Nano.
This is not a problem as long as I can correct for this.
What's needed is a way to call LowPower.powerDown (for example) with a flag so it doesn't actually go to sleep and keeping millis() running when it is set.
Then I could calculate the time before and after the call and get a reasonably accurate millisecond duration.
I made some changes my copy of the library and it all seems to work as I wanted:
LowPower.h
// add noLowPower argument to powerDown with default for backward compatability
void powerDown(period_t period, adc_t adc, bod_t bod, bool noLowPower = false) attribute((optimize("-O1")));
// add new static flag
static volatile bool wdtFinished;
LowPower.cpp
// add new wdtFinished flag
volatile bool LowPowerClass::wdtFinished;
// use new noLowPower argument to prevent entering low power and block until wdt has fired
void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod, bool noLowPower)
{
if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN);
if (period != SLEEP_FOREVER)
{
wdt_enable(period);
WDTCSR |= (1 << WDIE);
}
if (noLowPower) {
wdtFinished = false;
while (!wdtFinished) {;}
}
else {
if (bod == BOD_OFF)
{
#if defined (AVR_ATmega328P) || defined (AVR_ATmega168P)
lowPowerBodOff(SLEEP_MODE_PWR_DOWN);
#else
lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
#endif
}
else
{
lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
}
}
}
// set wdt finished flag
ISR (WDT_vect)
{
// WDIE & WDIF is cleared in hardware upon entering this ISR
wdt_disable();
LowPowerClass::wdtFinished = true;
}
I then use it it:
// calibrate watchdog timeout
sleepPeriodMs = millis();
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_ON, true);
sleepPeriodMs = millis() - sleepPeriodMs;
Serial.println(sleepPeriodMs);
I have only implemented the change to powerDown but it could also be added to the other calls.
Cheers, Julian