Low-Power icon indicating copy to clipboard operation
Low-Power copied to clipboard

idle mode with timer0_ON

Open ylowfat opened this issue 8 years ago • 6 comments

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

ylowfat avatar Apr 28 '17 13:04 ylowfat

I just stumbled upon this too. Also Pro Mini but with default bootloader I guess.

Raidok avatar May 01 '17 13:05 Raidok

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.

bonjour81 avatar Jun 29 '17 16:06 bonjour81

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

funoverip avatar Sep 19 '17 21:09 funoverip

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();
}

reddog avatar Jan 29 '18 18:01 reddog

+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?

we9v avatar Feb 27 '20 04:02 we9v

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.

dan1994 avatar Sep 30 '20 10:09 dan1994