idle mode with timer0_ON
Hi, I am trying to put arduino pro mini to sleep in idle mode with timer0 enabled. Arduino does not seem to sleep at all. The following code reproduces the problem.
unsigned long t1 = millis();
Serial.println(t1);
delay(10);
LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_ON, SPI_OFF, USART0_OFF, TWI_OFF);
delay(10);
unsigned long t2 = millis(); Serial.println(t2);`
I am using atmega328p with optiboot bootloader Any ideas? Thanks
I just stumbled upon this too. Also Pro Mini but with default bootloader I guess.
Hello everybody, Same issue here ! pro mini + default bootloader.
LowPower.idle(SLEEP_4S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_ON, USART0_ON, TWI_ON); => I have a 4sec delay.
LowPower.idle(SLEEP_4S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_ON, SPI_ON, USART0_ON, TWI_ON);
=> No delay.
Hi,
Same here with Atmega32u4 on breadboard, when trying to keep USB ON
LowPower.idle(SLEEP_8S, ADC_OFF, TIMER4_OFF, TIMER3_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART1_OFF, TWI_OFF, USB_ON);
No delay..
Just to add another +1 to the mix - I have it too.
Do we know what's causing this to happen? Is it something with the LowPower library? The Pro Mini chip itself? Arduino core? etc?
This example flashes the LED (pin 8) on and off with no pauses - timer 0 (for millis etc) has been left on:
#include <LowPower.h>
const int LED_PIN = 8;
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void powerDown() {
LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_ON, SPI_OFF, USART0_OFF, TWI_OFF);
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
delay(500);
}
void loop() {
powerDown();
}
Turning Timer 0 off with TIMER0_OFF fixes the flashes so that there's a 8 second delay (SLEEP_8S) between every on/off, however the internal clock is now broken (millis won't be true any longer), see:
#include <LowPower.h>
const int LED_PIN = 8;
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void powerDown() {
LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF);
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
delay(500);
}
void loop() {
powerDown();
}
+1 for me too, on a Mega2560.
#include <LowPower.h>
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, LOW); // show that we're sleeping, turn off the lights
LowPower.idle(SLEEP_1S, ADC_OFF, TIMER5_OFF, TIMER4_OFF, TIMER3_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_ON, SPI_OFF, USART3_OFF, USART2_OFF, USART1_OFF, USART0_OFF, TWI_OFF);
// LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
digitalWrite(LED_BUILTIN, HIGH); // show that we're doing something
delay(1000);
}
No flashing of LED. Change to TIMER0_OFF and it works properly, but then millis() is broken (which is one of the main reasons to use idle instead of powerDown. And powerDown works properly too (but again, millis() doesn't work).
I second reddog's questions: Do we know what's causing this to happen? Is it something with the LowPower library? The chip itself? Arduino core? etc?
Hey all,
I think I found the reason behind the problems with idle sleep and timer 0. The following response is accurate for Arduino UNO, but I believe it is similar in other boards as well.
TL;DR
To the best of my understanding it is impossible to use idle sleep and keep track of time simultaneously without external components (e.g. RTC).
Long Version
The first thing that surprised me was that timer 0 was on during idle sleep. I thought it is powered by the CPU clock which should be halted even during idle sleep. After a bit of experimentation I found out that timer 0 is configured to work with the IO clock prescaled by 641. This explains why the problem appears only in idle mode, as it's the only one that leaves the IO clock running.
But why is timer 0 waking the CPU up? In order to count the time of course! The way time is kept in Arduino is using timer 0. But this timer is only 8 bits, meaning it could not possibly hold large enough values. In order to manage this task, the timer fires an interrupt that updates a larger global variable (see <Arduino Installation Path>/hardware/arduino/avr/cores/arduino/wiring.c for exact details).
Since the interrupt is fired very often, it appears that the arduino is not sleeping at all. The truth is that it sleeps for up to 64 * 256 cycles (or about 1024 microseconds) every time you try to put it to sleep. A simple test that turns off interrupts on timer 0 shows that sleep works with the timer still on2.
To conclude, the only way that sleep and time keeping can work without external hardware is by somehow telling the CPU to go back to sleep after it's done processing this specific interrupt. I'm not aware of a way to achieve this.
1If you're interested in testing this yourselves you can simply add a Serial.println(TCCR1B); in setup which should yield 3. You can then look in the datasheet on page 87 to see how this relates to the clock sources.
2If you're interested in testing this yourselves you can simply add a TIMSK0 = 0; in setup. The call to PowerDown.idle() should now succeed even if you pass TIMER0_ON. See the datasheet on page 88 to understand how to enable and disable interrupts on timer 0.