How can I disable SLEEPMODE

Hello,

I’m using an arduino mega 1280 and am running into a small issue. I enter sleep mode but cannot disable it once I enter sleep mode.

My code is the following:

#include <avr/sleep.h>

int counter =0;

void setup()
{
  
 Serial.begin(9600);
  attachInterrupt(0,wake, RISING); 
  
}


void loop()
{
  counter++;
  delay(1000);
  if (counter == 5)
  {
   sleepNow(); 
  }
  
}


void wake()
{
  Serial.println("WORKING");
  
}


void sleepNow()
{
  
   Serial.println("SET_SLEEP_MODE");
  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  
  Serial.println("SLEEP_ENABLE");
  sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 
  
  attachInterrupt(0,wake, RISING);
  
    
  Serial.println("SLEEP_MODE");  
                               
  sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
  
  Serial.println("SLEEP_DISABLE");
  
  sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
   Serial.println("MCU is back in business");
  
}

My output is the following:

WORKING //Press the button to make sure interrupt is working BEFORE entering sleep mode
SET_SLEEP_MODE
SLEEP_ENABLE
SLEEP_MODE

//I press the button as many times as I want but never seem to get any response from the arduino.

Can someone please tell me what I’m doing wrong ?

Your code looks OK to me.

I encountered a same-sounding problem trying to wake from INTx pin interrupts on ATmega644PA as of 0022. Try renaming 'WInterrupts.c' in the Arduino core (under something like \hardware\arduino\cores\arduino) and replacing it with the one from 0020. If this helps, let me know! This will narrow down the source of the problem for both of us.

RISING requires the processor clock to be running. SLEEP_MODE_PWR_DOWN turns off the processor clock.

Locate “Table 10-1. Active Clock Domains and Wake-up Sources in the Different Sleep Modes.” in the datasheet for working interrupt / sleep combinations.

Hello,

Thanks for the reply. I have looked at table 10-1 and it seems INT7:0 and Pin Change is labeled as a wake up source. I have modified the code as follows:

#include <avr/sleep.h>

int counter =0;

void setup()
{
  
 Serial.begin(9600);
  attachInterrupt(0,wake, CHANGE); 
  
}


void loop()
{
  counter++;
  delay(1000);
  if (counter >= 20)
  {
   sleepNow(); 
  }
  else
  {
   Serial.print("Count: ");
   Serial.println(counter);
  }
  
}


void wake()
{
  delay(30);
  Serial.println("WORKING");
  
}


void sleepNow()
{
  
   Serial.println("SET_SLEEP_MODE");
  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  
  Serial.println("SLEEP_ENABLE");
  sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 
  
 // attachInterrupt(0,wake, HIGH);
  
    
  Serial.println("SLEEP_MODE");  
                               
  sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
  
  Serial.println("SLEEP_DISABLE");
  
  sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
   Serial.println("MCU is back in business");
  
}

I’m still encountering the same problem… I’m unable to wake up the arduino from sleep mode even though I have it set to CHANGE on interrupt 0 (pin 2). What I’m I doing wrong ?

icom5217:
Hello,

Hello.

Thanks for the reply

You are welcome.

I have looked at table 10-1 and it seems INT7:0

There is a footnote that goes with INTx as a wake-up source…

  1. For INT7:4, only level interrupt.

This is from the 10.4 Power-down Mode section … an external interrupt on INT3:0 … but I have no idea what that means.

I have modified the code as follows:
attachInterrupt(0,wake, CHANGE);

Same problem. CHANGE requires the processor clock to be running.

If your application really will work with change interrupts I suggest using a “pin change interrupt” as the wake-up source. They are fairly easy to code and there are lots of examples. And I know they work to wake the processor.

This is from the 14. External Interrupts section... Low level interrupts and the edge interrupt on INT3:0 are detected asynchronously. This implies that these interrupts can be used for waking the part also from sleep modes other than Idle mode.

So, you should be able to wake the processor using RISING or FALLING on INT0 through INT3. Which implies that your original code should work. Hmm. The problem is very likely the result of the processor clock being stopped. But, I have no idea what to suggest to get attachInterrupt working.

I got it to work with a few modifications …

#include <avr/sleep.h>

int counter =0;

void setup()
{
  
 Serial.begin(115200);
 digitalWrite (2, HIGH);  // pull-up
 
 pinMode (13, OUTPUT);
 digitalWrite (13, HIGH);  // awake
 
 Serial.println ("But does it get goat's blood out?");
  
}  // end of setup


void loop()
{
  delay(1000);
  if (++counter % 5 == 0)
    sleepNow(); 
}  // end ofloop


// interrupt service routine
void wake()
{
  sleep_disable();         // first thing after waking from sleep:
  detachInterrupt (0);     // stop many many interrupts
}


void sleepNow()
{
  
  Serial.println("SET_SLEEP_MODE");
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  Serial.println("SLEEP_ENABLE");
  sleep_enable();          // enables the sleep bit in the mcucr register
  
  Serial.println("SLEEP_MODE");  
  digitalWrite (13, LOW);  // asleep
 
  attachInterrupt(0, wake, LOW); 
  sleep_mode();            // here the device is actually put to sleep!!
  
  digitalWrite (13, HIGH);   // awake
 
  Serial.println("MCU is back in business");
  
}  // end of sleepNow

Pin 2 is pulled high with the pull-ups. This is so it is default high, and you then ground pin 2, thus trigger the LOW interrupt on interrupt 0. (A “low” interrupt is a level interrupt).

Then when you want to sleep it sets the ISR, goes to sleep, and grounding pin 2 wakes it. Then it repeats 5 seconds later. Works fine.

Try adding this:

#include <avr/interrupt.h> // interrupts library

Thank youuuu Nick ! got it to work :D

Great! Meanwhile while I was measuring current, I discovered a flaw. If you went to sleep with the switch pressed it never woke up. I think this is because after the attachInterrupt but before sleep_mode (), the interrupt would fire, which disables interrupts, thus it never wakes.

I changed my demo to not attempt to go to sleep if the switch was closed.

#include <avr/sleep.h>

#define LED 13

void setup()
{
 Serial.begin(115200);
 digitalWrite (2, HIGH);  // pull-up
 pinMode (LED, OUTPUT);
 digitalWrite (LED, HIGH);  // awake
 Serial.println ("But does it get goat's blood out?");
}  // end of setup

void loop()
{
static int counter = 0;
  delay(1000);
  if (digitalRead (2))
    if (++counter % 5 == 0)
      sleepNow(); 
}  // end ofloop

// interrupt service routine
void wake()
{
  sleep_disable();         // first thing after waking from sleep:
  detachInterrupt (0);     // stop many many interrupts
}

void sleepNow()
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  sleep_enable();          // enables the sleep bit in the mcucr register
  Serial.println("Going to sleep");  
  digitalWrite (LED, LOW);  // asleep
  attachInterrupt(0, wake, LOW); 
  sleep_mode();            // here the device is actually put to sleep!!
  digitalWrite (LED, HIGH);   // awake
  Serial.println("Awake again!");
}  // end of sleepNow

Meanwhile, measuring the current showed the following. I used the “bare bones” device I assembled here:

This does not have power LEDs, a voltage regulator, a USB conversion chip etc., so its power use is pretty minimal.

My figures were:

  • Awake: 19 mA
  • Awake with the LED disconnected: 17 mA
  • Asleep: 131 uA (that is, 0.131 mA)

So it uses about 130 times as much power when awake (excluding the power used by the LED).

And if you change the resonator over to an 8 MHz one (rather than 16 MHz) the figures are:

  • Awake: 13.8 mA
  • Awake with the LED disconnected: 11.4 mA
  • Asleep: 131 uA (that is, 0.131 mA)

So asleep it consumes the same amount, but awake the slower speed uses less power.

Nice a perfect way to test: questions: why did you disable interrupts at wake up ? may i rotate pin 2 use to enable sleep mode when power supply goes away( it is a charging battery powered circuit) ?

thanks tommy

The LOW interrupt continually fires. If you don't disable it the processor will limp along extremely slowly. Knowing what I know now, you should probably change:

  attachInterrupt(0, wake, LOW); 
  sleep_mode();            // here the device is actually put to sleep!!

to:

  noInterrupts ();
  attachInterrupt(0, wake, LOW); 
  interrupts ();
  sleep_mode();            // here the device is actually put to sleep!!

Otherwise you might get the interrupt before going to sleep, which then disables the interrupt, and then you don't wake.

The next instruction after "interrupts()" is guaranteed to be executed.

may i rotate pin 2 use to enable sleep mode when power supply goes away( it is a charging battery powered circuit) ?

What do you mean by "rotate pin 2"?