Go Down

Topic: Any library with delay() implemented by switching to low-power-mode w/ WDT (Read 650 times) previous topic - next topic

falcon74

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.

br,
-f74

MarkT

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.
[ I won't respond to messages, use the forum please ]

falcon74

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.

Nick Gammon

A writeup on low power modes:

http://www.gammon.com.au/forum/?id=11497

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.

Nick Gammon

This is an example of what I am talking about:

Code: [Select]
#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.

Go Up