Is there any simple/easy-to-use library that implements delay() (or similar function, that allows millisecond resolution sleeps), which would switch Arduino to low-power sleep mode. I'd expect it to be implemented using the WDT, to wake up and resume functioning.
The watchdog timer is not very accurate, so it depends what you mean by "millisecond resolution", but it ought to be possible by rewriting the code for delay() or by using something like Jeelabs Sleep class.
Thanks @MarkT. Had only read some fleeting mention of WDT in the scope of low-power operation, and wasn't aware that they aren't very accurate.
Found very useful information here thanks to your reference.
Maybe a dumb question - wondering if the AVR timer (Timer0?) continues ticking, when the system is in low-power mode ? I.e. will the standard Arduino time functions, like -- millis() & micros() return the elapsed time since the sketch started, or they would report elapsed time while system is in full power mode ? If it is the former, i.e. Timer0 ticks even in low-power mode, the Jeenode Sleepy class seems to be a fairly good enough for what I am trying to do. What I would like to do is to sleep as much as possible, not wake up early-enough (and frequently enough) to check for some data-pattern in a patch of memory. That patch gets over-written by noise all the time, and it is critical for me to check for valid data, frequently, lest I miss it.
Only IDLE mode keeps Timer 0 running. So in the lower-power modes you won't know elapsed time (without an external clock).
You could implement your own timing with Timer 2 and then use "power save" mode. In fact if you used an interrupt with that, then that is your "watchdog" timer. So just let Timer 2 wake you up at whatever intervals you (reasonably) want.
#include <avr/sleep.h>
volatile unsigned long ms;
ISR (TIMER2_COMPA_vect)
{
++ms;
digitalWrite (9, !digitalRead (9));
} // end of TIMER2_COMPA_vect
void setup () {
// reset Timer 2
TCCR2A = 0;
TCCR2B = 0;
// Timer 2 - gives us our 1 mS counting interval
// 16 MHz clock (62.5 nS per tick) - prescaled by 128
// counter increments every 8 uS.
// So we count 125 of them, giving exactly 1000 uS (1 mS)
TCCR2A = _BV (WGM21) ; // CTC mode
OCR2A = 124; // count up to 125 (zero relative!!!!)
// Timer 2 - interrupt on match (ie. every 1 mS)
TIMSK2 = _BV (OCIE2A); // enable Timer2 Interrupt
TCNT2 = 0;
// Reset prescalers
GTCCR = _BV (PSRASY); // reset prescaler now
// start Timer 2
TCCR2B = _BV (CS20) | _BV (CS22) ; // prescaler of 128
pinMode (9, OUTPUT);
} // end of setup
void loop () {
set_sleep_mode (SLEEP_MODE_PWR_SAVE);
sleep_enable();
sleep_cpu ();
sleep_disable ();
// should be here after 1 mS
} // end of loop
This uses an average of around 1.7 mA. However it behaves in a slightly strange way. According to my calculations it should wake up (and leave "loop") every 1 mS, but it actually does it every 2 mS.
With the sleep_cpu() line commented out, it does it every 1 mS. So somehow sleep is causing the clock to run slower. I'm not sure why at this stage. However even as it is, it shows how you can be in low power mode most of the time, but still count elapsed time accurately.
Theory: 62.5 nS * 1024 * 156 = 9.984 mS. That pretty-much agrees with measured results. In other words, a wake-up 100 times a second. Count those, and you know how much time has elapsed.
I ask because there did not appear to be a combination that would explain exactly what you were seeing. It looks like the possibilities are 3ms to a bit over 4ms or close to 65ms.
Of course. Trying to catch 1 mS interrupts with a 65 mS spool-up time was a bit silly of me. I'm surprised it worked as well as it did. (In fact, that is the mystery - maybe it had a maximum 65 mS start-up time).
Oh well, that will teach me to read the data sheet more closely.
At least it confirms my belief that these things work, as long as you understand exactly what they are supposed to do.