Arduino doesn't stay in SLEEP_MODE_IDLE

Hi there,

after finishing a small project I now want to reduce the power consumption of the project hardware. So I also decided to set the microcontroller to SLEEP_MODE_IDLE. But the controller always wakes up immediately.

Till now, I don’t know why.

This is the code (in principle):

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

/* Function Prototypes */
//...


/* Configuration */
/* Pins */
#define PINNR_RX           0
#define PINNR_TX           1
#define PINNR_LED          13
#define PINNR_HANGUP       8
#define PINNR_DIALCNT      3
#define PINNR_DIALCNTEND   15
#define PINNR_BELL         7
/* Pinstates */
#define PINACT_LED         HIGH
#define PININACT_LED       LOW


/* Globals */
//...
volatile unsigned long     TimeDialEnd = 0;

/* **************** inlines **************** */

inline void wait16(void)
{
  for(int i=0; i<255; i++)
     __asm__("nop\n\t"); 
}


/* **************** main code **************** */

void setup() { 
  /* Initialize hardware pins */
  pinMode(PINNR_LED, OUTPUT);
  pinMode(PINNR_BELL,OUTPUT); 
  pinMode(PINNR_HANGUP, INPUT);
  digitalWrite(PINNR_HANGUP, HIGH);
  pinMode(PINNR_DIALCNTEND, INPUT);
  digitalWrite(PINNR_DIALCNTEND, HIGH);
  pinMode(PINNR_DIALCNT, INPUT);
  digitalWrite(PINNR_DIALCNT, HIGH);
 
  /* additional interrupts */
  PCICR  |= (1<<0);            // enable PCINT0
  PCMSK0 |= (1<<0);            // Set PB0 interrupt for INT0
  PCICR  |= (1<<1);            // enable PCINT1
  PCMSK1 |= (1<<1);            // set PC1 interrupt for INT1
  PCICR  |= (1<<2);            // enable PCINT2
  PCMSK2 |= (1<<3);            // set PD3 interrupt for INT2
  interrupts();
  
  /* Serial interface */
  Serial.begin(9600); 
} 


void loop() {
  
 //...
  
  while(true) {  
    
    if (Serial.available() > 0)
    {
      //read the incoming byte 
      String IncomingByte;
      char IncomingChar;
      
      // read incomming byte
      IncomingChar = char( Serial.read() );
      if( (IncomingChar == '\r') || (IncomingChar == '\n' ) )
      {
        //...
      }
      else
      {
        //...
      }
      
      // process data
      
      if(SerialIn.equals("test"))
      {
        //...
      }
      
    }
    
    if( (TimeDialEnd!=0) && ((millis()-TimeDialEnd)>3000) )
    {
      //...
    }
    
    
    set_sleep_mode(SLEEP_MODE_IDLE);
    sleep_enable(); 
            
    power_adc_disable();
    power_spi_disable();
    power_timer0_disable();
    power_timer1_disable();
    power_timer2_disable();
    power_twi_disable();
    
    sleep_mode();                   // in den Schlafmodus wechseln
    
    sleep_disable(); 
    power_all_enable();
    
    Serial.write("Up\r\n");
    
  } 
  
} 


/* **************** private functions **************** */

//...

/* **************** interrupts **************** */

ISR(PCINT0_vect)
{
  //...
  PCIFR |= (1<<0);
}  

ISR(PCINT1_vect)
{
  //...
  PCIFR |= (1<<1);
}

ISR(PCINT2_vect)
{
  //..
  PCIFR |= (1<<2);
}

ISR(WDT_vect) { }  //WatchDogTimer interrupt

The controller does not receive any uart data while i tested this. The used controller is the 328p.

Is there a way to find out what wakes up the controller?

Are you sure you want pin change interrupts enabled on your serial TX pin? Seems like that might be a problem when you send data since writing to the pin should trigger an INT (I think).

Secondly, is this right:
PCICR |= (1<<2); // enable PCINT2
PCMSK2 |= (1<<3); // set PD3 interrupt for INT2

Maybe the one of the two above is incorrect?

Hmm. I think this is right.

  PCICR  |= (1<<2);            // enable PCINT2
  PCMSK2 |= (1<<3);            // set PD3 interrupt for INT2

These lines have enabled the PCINT2 external interrupts group in general but only the PCINT19 interrupt is enabled in this group. The RX PCINT16 and TX PCINT17 pins, which are also in this group, are not enabled.

Timer 0 was the problem. Stopping it before going to sleep and reenabling it afterwards helps :wink: