Sleep mode - what can be done with Arduino?

Context: I have Arduino DueMilaNove, Freeduino, Seeeduino, Mega, and my customized boards. Arduino IDE 0021. Involved processors: ATmega1280 and ATmega328P.

I am very disappointed with the lack of proper power management support of Arduino. I mean, I do not know if I understood correctly the messages related to this topic, but it seems to me that only external events can interrupt the processor. OK, this is what we expect, but the CLOCK/TIMER... it is always something that we want...

I read a huge number of messages asking for a simple solution, such as, go to sleep (and a start a kind of timer) / the timer timeouts and interrupts the processor / you main application resumes its operation, check stuff, performs actions and go to sleep again...

What I am asking here is the confirmed answers for these questions:

  1. If I am using millis() and I RESET the processor, the reference counter is reseted also. If the processor enters into sleep mode for 1minute and wakes up, what occurs with the millis() reference? Is it reseted? Is it resumes from the last counting, therefore causing a real delay of 1min.? Or it continues the correct counting, also considering the 1min-time when the processor was sleeping?

  2. Is there "an internal" clock/timer that can be used for sleeping purposes? More specifically, a timer that we can program a certain value for timeout and continues working in sleep mode (eventually waking up the processor)?

  3. Assuming that answer (3) is negative, what kind of "feasible" solution (simple to develop and/or cheap to purchase) exists to realize the above scenario?

Thanks for any suggestion or hint!!

  1. If I am using millis() and I RESET the processor, the reference counter is reseted also. If the processor enters into sleep mode for 1minute and wakes up, what occurs with the millis() reference?

Depends on the sleep mode. Most modes stop the processor's clock which stops all timer / counters including the one used for millis.

Is it reseted?

No. If the processor's clock is stopped, millis is frozen until the processor wakes. If the processor's clock is not stopped, millis continues counting.

  1. Is there "an internal" clock/timer that can be used for sleeping purposes?

The watchdog timer can be enabled to run independently from the processor's clock. But the watchdog is very inaccurate.

More specifically, a timer that we can program a certain value for timeout and continues working in sleep mode (eventually waking up the processor)?

In Idle mode, the clocks run. In all other modes they do not run except the watchdog timer.

  1. Assuming that answer (3) is negative, what kind of "feasible" solution (simple to develop and/or cheap to purchase) exists to realize the above scenario?

Real time clock. Watchdog timer. Or, external crystal driving a timer...
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1273507808

The 328p datasheet says that the current consumption in power down mode with watchdog timer running is about 6uA at 5V supply, and in idle mode with 16MHz clock about 2.4mA - not so impressive but timers all work. I don't know why the implementation of delay() doesn't use idle mode - see Enerlib, this seems to give a simple interface to idle mode.

Switching to the internal 128kHz clock gives about 20uA for idle mode - however millis() and delay() will run 128 times slower - possibly this could be made to work with software changes if you don't want accurate clock.

The DS1307 RTC chip might be a nice addition to future Arduino board?

[Of course micropower isn't really attainable on standard Arduino hardware with USB interface chips - but standalone projects and boards like the Mini and Mini Pro could really benefit from some improvement here I think]

Thanks for all comments.

After reading the suggestions and mentioned links, I am convinced that the watchdog option is the best general option. It is only a matter of selecting a factor of sleeping/total time. Due to the fact that you are using Timer2 with its known inaccuracy, such solution lacks precision and your application must work well with such clock variation. For instance, does not matter if the factor is actually, say 94%, instead of the planned 95% value.

However, it is not an option for my project. I am heavily millis()-addicted and all my solution is based on this function. Also, my final solution will work with low voltage/low clock (2V @ 2MHz) in a customized board and many of the external clock/timers solutions are still not feasible for me. For instance, many of the RTC solutions work with 3.3 and 5V and I really need to be able to run the ATmega328P under low-battery situation if necessary (normal operation is actually is around 2.7V - nominal voltage of 2 AA batteries).

Therefore, the questions for the forum are very specific now. The sleep modes available at the Arduino IDE are:

  • SLEEP_MODE_IDLE - the least power savings
  • SLEEP_MODE_ADC
  • SLEEP_MODE_PWR_SAVE
  • SLEEP_MODE_STANDBY
  • SLEEP_MODE_PWR_DOWN - the most power savings
    In order to use millis(), just the SLEEP_MODE_IDLE works OK.

Question 1) If using SLEEP_MODE_IDLE mode, is it possible to individually disable functions such as ADC? If positive, can you give a small code example? What are the functions that we can disable?

Question 2) What is the clock used by millis()? If using SLEEP_MODE_PWR_DOWN mode, is it possible to only enable the clock used by millis()?

Thanks

Question 1) If using SLEEP_MODE_IDLE mode, is it possible to individually disable functions such as ADC?

Yes. Don't forget about the UART, Timer 1, Timer 2, and the BOD.

If positive, can you give a small code example?

I can't.

What are the functions that we can disable?

Search for "arduino narcoleptic".
Search this forum for "PRR".
Search this forum for "aden disable adc power"

Question 2) What is the clock used by millis()?

Timer 0 (zero).

If using SLEEP_MODE_PWR_DOWN mode, is it possible to only enable the clock used by millis()?

No. Once you stop the processor's clock, all the timers stop. Search the datasheet for "9.1 Sleep Modes".

Thanks for the comments. My results so far (please, any improvement suggestion is welcome!!):

Context:
ATmega328P in a customized, almost "empty" board, 2MHz external clock, 2.63V (2AA batteries), chip with bootloader (for this test only, for the final version, the Arduino bootloader will be removed).

Code:
Arduino IDE core 0021 development. The device sends the current time to the Serial interface (9600bps), goes to sleep for about 4s, and continues the cycle. My intention is to check if the timer is being delayed. Sleep mode: SLEEP_MODE_IDLE (the only option that works with millis() which uses Timer0).

The BOD was disabled with the AVR Studio 4 (I saw code to do this at compiling time for the Arduino IDE, but I did not use it). (Note: disabling BOD is not a good idea at all, but I have an external watchdog solution that shutdowns all the devices when battery is below 1.8V.)

void setup() {
// Prevent interrupts during this phase
noInterrupts();

// Temporary turn off watchdog and kill watchdog if running
wdt_reset();
MCUSR = 0;
WDTCSR |= _BV(WDCE) | _BV(WDE);
WDTCSR = 0;

// turn OFF analog parts
ACSR = ACSR & 0b11110111 ; // clearing ACIE prevent analog interupts happening during next command
ACSR = ACSR | 0b10000000 ; // set ACD bit powers off analog comparator
ADCSRA = ADCSRA & 0b01111111 ; // clearing ADEN turns off analog digital converter
ADMUX &= B00111111; // Comparator uses AREF/GND and not internally generated references

delay(1);
power_adc_disable(); // redundant code if you check the above lines
power_spi_disable();
power_twi_disable();
//power_usart0_disable(); // I cannot disable this one...

// Disabling timers:
TCCR1B = 0b00000000; // I need timer0 and timer; only timer1 is disabled

// Default behavior: put all I/O pins into input mode and internal pull-up
int i;
for(i=0; i<32;i++)
{
pinMode(i, INPUT);
digitalWrite(i, HIGH);
}

// Establish the correct assignment for the pins which are exceptions:
pinMode(13, OUTPUT); // I have a LED that blinks every time the device sends a message to the serial port
Serial.begin(9600); // I need the serial port!!

//Timer2 Settings: Timer Prescaler /1024
TCCR2B |= ((1 << CS22) | (1 << CS21) | (1 << CS20));
//Timer2 Overflow Interrupt Enable
TIMSK2 |= (1 << TOIE2);
RESET_TIMER2;

// Now you can enable interrupts!!
interrupts();

} // end of setup()

Result: 0.255 mA during sleep.
From the datasheet TYPICAL value for 1MHz, 2V: 0.300 mA.

Therefore, I am very close to the optimum power consumption while in IDLE mode...

Questions for you guys:

  1. Any enhancements for the above solution? I forgot something that can be powered-down?

  2. I would like to compare this solution with one which uses an external RTC device. Do you know about any RTC option with an ultra-power consumption (< 0.010 mA) and power supply voltage that goes down to 1.8V or close?

Thanks

Do NOT call delay with interrupts disabled.

 // Default behavior: put all I/O pins into input mode and internal pull-up
 int i;
 for(i=0; i<32;i++)
 {

Which board has 31 pins? Because you're using Serial, you should leave pins 0 and 1 alone.

Thanks for the corrections.
Related to the last comments:

Do NOT call delay with interrupts disabled.

Yes, you are right. I had problems with this in other code...

Which board has 31 pins? Because you're using Serial, you should leave pins 0 and 1 alone.

Actually, it is a general code because I also have ATmega1280 (moving to 2560). I believe this code does not hurt at all. Related to the pins I eventually need to use,including 0 and 1 for serial,I make the exceptions after this code. The idea here is to make my code as portable as possible for different scenarios. However, to be more precise, one can choose just the inactive pins to include in the loop.

Tks.

I believe this code does not hurt at all

It does. There's no limit checking in pinMode or digitalWrite. You should only manipulate pins that are actually on the board.

OK. Thanks for the suggestion. Actually, I did not have any error message at the compilation time, but I am not sure if can cause bugs.
I will change the code accordingly.

I forgot to mention...
At the above code, you need to add the following lines at the beginning:

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>

Ionito

These are the final results using ATmega328P, Arduino bootloader REMOVED, clock 2MHz (NOT 16MHz), 2.7V (from batteries), BOD and WDT deactivated.

ATmega328P installed on a board with NOTHING connected to it, except the crystal, the power and the pull-up resistor at chip_pin4 = I/O_2 = INT0.

Wake-up method: external interrupt (INT0).

Results:

  • 01 microAmp while sleeping (POWER DOWN mode) !!! This result matches with the datasheet.
  • If internal watchdog is used: 4.1 microAmp

Ionito