You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This suggestion is similar to issue #111 in that a flag is to be set when the watch dog timer interrupt service routine is executed, but it this case, it is used to re-sleep the CPU if it is awakened by some other interrupt to ensure that the power saving function does not exit before the WDT interrupt happens. As I see it, the problem is that when the CPU wakes up in powerDown it doesn't know which interrupt awakened it, so it just assumes that it was the WDT. Since the interrupt service routine for the WDT is in that same module, it is easy to add a flag that is set when the WDT interrupt is entered, and cleared when the powerDown function first sleeps the CPU. The CPU is just put back to sleep if it is awakened and the wdtFinished flag is still false. When the wdtFinished flag is true, the powerDown function exits as usual.
With this modification, the time in the powerDown function is not short circuited by an unexpected interrupt.
// add new wdtFinished flag class variable
volatile bool LowPowerClass::wdtFinished;
...
void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod)
{
if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN);
if (period != SLEEP_FOREVER)
{
wdt_enable(period);
WDTCSR |= (1 << WDIE);
}
if (bod == BOD_OFF)
{
wdtFinished = false; // added code
while (!wdtFinished) // added code
#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168P__)
lowPowerBodOff(SLEEP_MODE_PWR_DOWN);
#else
lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
#endif
wdtFinished = false; // added code
}
else
{
wdtFinished = false; // added code
while (!wdtFinished) // added code
lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
wdtFinished = false; // added code
}
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; // added code
}
The powerSave, powerStandby, and powerExtStandby functions could be modified in a similar manner.
The text was updated successfully, but these errors were encountered:
When I implemented these suggestions, I realized two things:
The wdtFinished flag cannot be defined in the header file as a class variable; the interrupt service routine is not a class function (and cannot be one) and so does not have access to private or protected attributes of the class. I think it would be very dangerous to make this attribute public. The solution is to make the variable local to the .cpp file.
If the user specifies to SLEEP_FOREVER, the routines would never return since the WDT interrupt in not enabled. The solution is to not loop if SLEEP_FOREVER is specified.
LowPower.cpp
// variable global to this file.
volatile static bool wdtFinished;
...
void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod)
{
if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN);
// set wdtFinished true if SLEEP_FOREVER so single test will terminate sleep
wdtFinished = period == SLEEP_FOREVER; // assigned before IE to prevent race
if (period != SLEEP_FOREVER)
{
wdt_enable(period);
WDTCSR |= (1 << WDIE);
}
do { // Do this at least once even if SLEEP_FOREVER
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);
}
} while (!wdtFinished);
if (adc == ADC_OFF) ADCSRA |= (1 << ADEN);
}
...
ISR (WDT_vect)
{
// WDIE & WDIF is cleared in hardware upon entering this ISR
wdt_disable();
wdtFinished = true;
}
The other functions would have similar modifications.
This suggestion is similar to issue #111 in that a flag is to be set when the watch dog timer interrupt service routine is executed, but it this case, it is used to re-sleep the CPU if it is awakened by some other interrupt to ensure that the power saving function does not exit before the WDT interrupt happens. As I see it, the problem is that when the CPU wakes up in powerDown it doesn't know which interrupt awakened it, so it just assumes that it was the WDT. Since the interrupt service routine for the WDT is in that same module, it is easy to add a flag that is set when the WDT interrupt is entered, and cleared when the powerDown function first sleeps the CPU. The CPU is just put back to sleep if it is awakened and the wdtFinished flag is still false. When the wdtFinished flag is true, the powerDown function exits as usual.
With this modification, the time in the powerDown function is not short circuited by an unexpected interrupt.
The powerSave, powerStandby, and powerExtStandby functions could be modified in a similar manner.
The text was updated successfully, but these errors were encountered: