Skip to content

Suggestion for improvement to allow calibration of Watchdog Timer period #111

@julianmorrison

Description

@julianmorrison

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions