Arduino won't go to sleep!

I can't get my Arduino to go to sleep. I have tried several examples from the web. This one seems simple enough that I understand it, but it doesn't work either. I have tried two boards, a Pro Mini and a Duemilanove and they behave the same so I don't think it is a hardware fault. Can anyone see what is wrong? If anyone can point me to an example that wakes from a timer interrupt that works, I would appreciate it too. I am using Arduino 1.0.

I expect this code to print xO every few seconds.
I get a long string of x's with a O every few seconds.
It is behaving as if the flag gets set properly when the timer overflows, so the interrupt is working, but it is never going to sleep. But the enterSleep() function looks bulletproof.

/*
 * Sketch for testing sleep mode with wake up on timer.
 * Minor edits from example by Donal Morrissey - 2011.
 */
#include <avr/sleep.h>
#include <avr/power.h>

#define LED_PIN (13)

volatile int f_timer=0;

/***************************************************
 *  Name:        ISR(TIMER1_OVF_vect)
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Timer1 Overflow interrupt.
 *
 ***************************************************/
ISR(TIMER1_OVF_vect)
{
  /* set the flag. */
   if(f_timer == 0)
   {
     f_timer = 1;
   }
}

/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Enters the arduino into sleep mode.
 *
 ***************************************************/
void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_IDLE);
  
  sleep_enable();
  
  /* Now enter sleep mode. */
  sleep_mode();
  
  /* The program will continue from here after the timer timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */
  
  /* Re-enable the peripherals. */
  power_all_enable();
}

/***************************************************
 *  Name:        setup
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Setup for the serial comms and the
 *                timer. 
 *
 ***************************************************/
void setup()
{
  Serial.begin(9600);
  
  /*** Configure the timer.***/
  
  /* Normal timer operation.*/
  TCCR1A = 0x00; 
  
  /* Clear the timer counter register.
   * You can pre-load this register with a value in order to 
   * reduce the timeout period, say if you wanted to wake up
   * ever 4.0 seconds exactly.
   */
  TCNT1=0x0000; 
  
  /* Configure the prescaler for 1:1024, giving us a 
   * timeout of 4.09 seconds.
   */
  TCCR1B = 0x05;
  
  /* Enable the timer overlow interrupt. */
  TIMSK1=0x01; 
}

/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Main application loop.
 *
 ***************************************************/
void loop()
{
  Serial.print("x");
  if(f_timer==1)
  {
    f_timer = 0;
    /* Toggle the LED */
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    Serial.println("O");
    /* Re-enter sleep mode. */
    enterSleep();
  }
}

I think this really simple program should blink a few times and go to sleep forever.
But it blinks 4 times, goes to sleep for about 60 seconds, and then starts blinking forever.
Arduino 1.0 Arduino Pro Mini 328 3.3V powered by FTDI basic 3.3V serial converter from USB

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

int I;

void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_IDLE);
  
  sleep_enable();
  
  /* Now enter sleep mode. */
  sleep_mode();
  
  /* The program will continue from here after the timer timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */
  
  /* Re-enable the peripherals. */
  power_all_enable();
}

void setup() {                
  pinMode(13, OUTPUT);  
  I = 5;  
}

void loop() {
  while (I-->1){
    digitalWrite(13, HIGH);   // set the LED on
    delay(1000);              // wait for a second
    digitalWrite(13, LOW);    // set the LED off
    delay(1000);    // wait for a second
  }
  enterSleep();
}

The Arduino core uses Timer 0 to keep track of time. You will get an interrupt about once every millisecond.

Perhaps you can disable the Timer 0 interrupt before going to sleep and re-enable it when you wake up. Of course that means the millis() timer will stop running while you are asleep.

Another option is to use a deeper sleep like Power-save Mode and use Timer 2 to wake up. If I'm reading the datasheet correctly, Timer 2 is the only timer running in Power-save Mode.

I have some examples of going into sleep here:

As johnwasser says, various modes will have different behaviours.

It looks like I am going to have to shut down Timer 0 if I am going to sleep for more than 1ms, yet keep the crystal running. I want to start a sampling loop every second and sleep when I am done until the start of the next second. This will require more research.

Thanks guys. Nick, your page is one of the best I have seen on the subject.

Thanks.

Shutting down Timer 0 isn't that hard. And see the init() function for how to get it back. Although saving and restoring TCCR0A and TCCR0B should do it.

eg.

byte oldTCCR0A = TCCR0A;  // save
byte oldTCCR0B = TCCR0B;
TCCR0A = 0;  //  stop timer
TCCR0B = 0;  

// ... sleep

TCCR0A = oldTCCR0A;
TCCR0B = oldTCCR0B;

Untested though.

I prefer the Narcoleptic library because it's so easy to use. You get most of the savings without any of the complicated code. Google it. Instead of using an interrupt pin to wake the chip, I wake every 5 seconds and digitalRead for any interesting conditions. This is much more flexible when there are multiple wake scenarios. The only disadvantage is how often I am checking. An interrupt pin effectively checks every millisec? And uses less power than my checking every 5 seconds.

Using the board from Yourduino, it only takes 10ma when sleeping, USB and 5v regulator.
Off the top of my head that's 10 days on AA batteries.
Pro mini only 1.5ma. Good enough or me!
It's about the same as the self-discharge rate of AA NiMh.
Much simpler than building your own. Much less than Uno 33ma, 3 days.

Watch out for Serial.print().
Depending on the baud rate you need about delay(2) before you go to sleep to finish sending a small buffer.
What's the largest buffer size in bytes?

I may find a use for the Narcoleptic.delay(), but not in this case. My sampling work may take a variable amount of time so I don't know how long till the start of the next second. I could use a timer and subtract the time used from 1 sec, but the round off errors would accumulate and the result wouldn't be very accurate.

More likely I will use Nick's suggestion to halt Timer 0 and use another timer for 1 second wakeups. Back to my books and datasheet.

You can easily measure how long it's awake and sampling for. If the Narcoleptic.delay() is also accurate then it will work perfectly!
It may not be. Let me test. Anyone?

Narcoleptic is not accurate, due to the overhead of calling it and millis(), but at least it's consistent. I came up with the 42 in the code by measuring the error after an hour. Now the error is less than 1ms for each second. 1000ppm. 1 in 1000. It doesn't matter if you change the code in the first 4 lines in loop. It doesn't matter if you uncomment the last 2 delays of 5000. It's still within 1ms, because I calibrated it that way with the 42. I think this will be the same for everyone since the crystal is more accurate than 100ppm. Is this good enough for you? It is much more accurate in ppm with a longer sleep of 15 sec. I'm using an external clock to calibrate it. I don't know why the 42 is so big, I would have expected much less, but it works! Is the clock while it's sleeping much different than the main program timer used by millis? They both use the same crystal.

#include <Narcoleptic.h>
float volatile f;
int i,j,k=0;
long ms;

void setup(){
Serial.begin(9600);
}
void loop(){
ms=millis();
Serial.println(k++);
for(i=0;i<1000;i++) j+=sin(f);
delay(150);
Narcoleptic.delay(1000-(millis()-ms)-42);
//Narcoleptic.delay(5000);
//Narcoleptic.delay(5000);
}

According to the Hitchhiker's Guide to the Galaxy, 42 is the answer to Life, the Universe, and Everything.

1000ppm (0.1%) may be good enough. But I still want to look into hardware timer interrupts. This project will be growing in stages. The Pro Mini is fine for now, but I will need an Arduino Mega eventually. And the Mega will have to run at 3.3V 8MHz (ATmega2560V on a custom PCB) so I will eventually have to monkey with the bootloader and lots of other under-the-hood stuff. This is going to be a long learning experience.

See here for interrupts:

and timers:

Stopping Timer0 might be excessive. I think turning off the interrupt should be sufficient.

byte oldTIMSK0 = TIMSK0;  // save Timer 0 Interrupt mask register
TIMSK0 = 0;  //  stop Timer 0 interrupts

// ... sleep

TIMSK0 = oldTIMSK0;  // This will probably cause pending interrupts to happen immediately.

True, that would almost certainly stop the waking problem. Stopping the timer might save a bit of current.

Come to think of it, if you used Timer 1, which can count up to 65535, and a prescaler of 1024, then the timer itself would take 4.194 seconds to overflow.

I want to start a sampling loop every second and sleep when I am done until the start of the next second.

Therefore with a suitable count, you could use Timer 1 to accurately wake you from sleep every second.

Do you think my idea will work if I want to sleep for 10s? Even if I change the code in loop?
Within a few ms? It seems to.
Any ideas where the extra 42ms comes from in overhead?

I think you are getting cumulative errors there. I would take the initial start time (say, zero), and then, after your calculations, sleep until start+1000 is up. Next time around, until start+2000. And so on. Don't try to recalculate the start time. The wake time should always be 1000 from the last wake time.

Not so simple with the Narcoleptic library. The clock is not running when it's asleep.

Oh I see. I haven't used it. The chip takes time to wake you know, that might be it.

I agree. I will use my method when I need 1-2ms accuracy for each sample. You are correct, this error accumulates. If I need more accuracy I will be forced to use the method you were discussing.