Any library with delay() implemented by switching to low-power-mode w/ WDT

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.

A writeup on low power modes:

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.

This is an example of what I am talking about:

#include <avr/sleep.h>

volatile unsigned long 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_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.

According to my calculations it should wake up (and leave "loop") every 1 mS, but it actually does it every 2 mS.

The clock select / BOD fuse settings may be the culprit. It looks like the delay-from-wake time can be as long as 65ms.

Oh yeah, lol, it was that.

Well, this modified setup behaves as predicted:

void setup () {
   // reset Timer 2
  TCCR2A = 0;
  TCCR2B = 0;

  TCCR2A = _BV (WGM21) ;   // CTC mode
  OCR2A  = 155;   // zero relative

  // Timer 2 - interrupt on match 
  TIMSK2 = _BV (OCIE2A);   // enable Timer2 Interrupt
  TCNT2 = 0;     

  // Reset prescalers
  GTCCR = _BV (PSRASY);        // reset prescaler now
  // start Timer 2
  TCCR2B =  _BV (CS20) | _BV (CS21) | _BV (CS22) ;  // prescaler of 1024
  pinMode (9, OUTPUT);
} // end of setup

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.

Oh yeah, lol, it was that.

Seriously? I was correct?

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. :wink:

At least it confirms my belief that these things work, as long as you understand exactly what they are supposed to do.