wake atmega328 from sleep with rising event

I belive it is possible.

cite: "you can use any type of interrupt (Rising edge/ Falling edge / Low level / Any logical change) to wake up from sleep mode."

Does somebody can implement wake with rising edge?
I only managed to wake with LOW.

The table in the 328P datasheet says that FOR SLEEP MODES OTHER THAN 'IDLE' the INT0 or INT1 wake-up has to be a level interrupt. Does an edge interrupt work in IDLE sleep? Pin Change interrupts can also cause a wake-up. I don't know if Pin Change interrupts are supposed to be considered level interrupts or edge interrupts.

John, if you follow the link above you will see that Atmel confirmed that their documentation is incorrect and that external interrupts will wake the processor from the deeper sleep modes with any of the four interrupt senses. And pin change interrupts are edge detects.

I just tried it with a stock Uno R3. I wired the PPS output of a GPS into digital pin 2 (INT0) and wrote a short sketch to set up INT0 for rising edge and put the processor into power down mode. It woke up every second.

Weirdly it woke up twice per second when configured to detect a falling edge. Huh. I would have expected the PPS signal to have a more defined trailing edge. But maybe it's noisy.

jboyton, thank you.
I wonder if you can reproduce with simple button.When shorted - arduino's pin connected to gnd, when open - pulled up.
I've tryed with int.1 (pin D3) and it dont waken.

tock:
I only managed to wake with LOW.

Please show your code and schematic.

My example code, works fine:

#include <avr/sleep.h>                  

const byte LED = 13;

// interrupt service routine in sleep mode
void wake ()
{
  sleep_disable ();         // first thing after waking from sleep
}  // end of wake

void sleepNow ()
{
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);   
  noInterrupts ();          // make sure we don't get interrupted before we sleep
  sleep_enable ();          // enables the sleep bit in the mcucr register
  EIFR = bit (INTF0);       // clear flag for interrupt 0
  attachInterrupt (0, wake, RISING);  // wake up on rising edge
  interrupts ();           // interrupts allowed now, next instruction WILL be executed
  sleep_cpu ();            // here the device is put to sleep
  detachInterrupt (0);      // stop this interrupt until next time
}  // end of sleepNow

void setup ()
  {
  pinMode (LED, OUTPUT);
  }  // end of setup

void loop ()
  {
  sleepNow ();
  digitalWrite (LED, HIGH);
  delay (1000);
  digitalWrite (LED, LOW);
  }  // end of loop

johnwasser:
The table in the 328P datasheet says that FOR SLEEP MODES OTHER THAN 'IDLE' the INT0 or INT1 wake-up has to be a level interrupt. Does an edge interrupt work in IDLE sleep? Pin Change interrupts can also cause a wake-up. I don't know if Pin Change interrupts are supposed to be considered level interrupts or edge interrupts.

They are a bit slow in releasing an updated datasheet, but they did indeed confirm it is wrong in that respect.

After all, if a pin change will wake it, surely an edge would wake it? It's basically the same thing.

Nick, thank you.
Unfortunately your example code does not works in my setup. And I don't know why.
My schematic is simple

  1. Arduino IDE 1.0.1
  2. Clone of Nano with atmega168. It's my mistake. Title contains 328. But I'm sure both chips share same datasheet.
  3. pin D2 connected trought 1M resistor with GND.
  4. also pin D2 coonected with reed switch. Two pins. Disconnected (open) without magnet.
  5. Second pin of reed switch connected with 5v pin.
  6. your code don't work.
  7. if I change rising to low in your code , it works fine. It wakes when I release magnet.
    7+. also I found that processor still wakes if I change interrupt number from 0 to 1 in code with same schematic.
    :confused:

Why the 1M? Try smaller, 100K, 10K.

Of course it works with a button. Or just moving the jumper from gnd to Vcc.

Maybe there's an error in your code?

  1. your code don't work.

Can you define "don't work"? The LED doesn't come on? It doesn't turn off?

I just tested on my Uno, with a 1 MΩ resistor between D2 and Gnd as you described. The LED turns on when I connect D2 to +5V, and goes off a second later.

Does someone else want to try it? You need a Uno, some sort of resistor of 1k or more, and a piece of wire.

Disconnected (open) without magnet.
...
It wakes when I release magnet.

You mean, when you close the switch by bringing the magnet close?

I've tested HIGH with UNO (328) too. It works. There seems to be an async device that generates pulses so the ex-INT can detect HIGH,LOW,EDGE when the MCU is sleeping with the crystal oscillator powered off. Same for the PCINT. I don't know the frequency of the async device. On the other hand, the ATMEGA2560 chip has only 4 ex-INT pins driven by async devices and the arduino interrupts 0 and 1 (arduino pins 2 and 3) are NOT driven by an async device so they can only detect LOW level when the MCU is sleeping. Learned it hard way.

liudr:
I've tested HIGH with UNO (328) too. It works.

You mean RISING. There is no HIGH interrupt.

Yes, it was typo. Rising and falling then low.

Hi,
I have to do something similar, put my Arduino Uno to deep sleep when the input to pin 3 is LOW and wake it up when the input to pin 3 is high. Many thanks to Ralph Bacon for his post on youtube. I copy his code with a small change because my application is on a BMS for an electric vehicle, so the ignition ON/OFF will send the signal to my Arduino on one pin only to send it to sleep or wake it up. In the example below, you will get a message on your Serial Monitor and an LED will blink to show that the board is awake. The link to the tutorial is at the beginning, I kept Ralph's comments.

/*
Low Power SLEEP modes for Arduino UNO/Nano
using Atmel328P microcontroller chip.
For full details see my video #115
at Ralph S Bacon - YouTube
(Direct link to video: https://TBA)
All details can be found at RalphBacon (Ralph Bacon) · GitHub
*/
#include "Arduino.h"
#include <avr/sleep.h>

#define sleepPin 8 // When low, makes 328P go to sleep
#define wakePin 3 // when low, makes 328P wake up, must be an interrupt pin (2 or 3 on ATMEGA328P)
#define ledPin 2 // output pin for the LED (to show it is awake)

void setup() {
Serial.begin(9600);

// Keep pins high until we ground them
//pinMode(sleepPin, INPUT_PULLUP); // I commented this because I don't use pin 8 in the sleep condition, I use the same pin 3
pinMode(wakePin, INPUT_PULLUP);

// Flashing LED just to show the µController is running
digitalWrite(ledPin, LOW);
pinMode(ledPin, OUTPUT);
pinMode(13,OUTPUT); // I set up pin 13 to output mode so the LED attached will go OFF
Serial.println("Setup completed.");
}

// The loop just blinks an LED when not in sleep mode
void loop() {

// Just blink LED twice to show we're running
doBlink();

// Is the "go to sleep" pin now LOW?
if (digitalRead(wakePin) == LOW) {

// Disable the ADC (Analog to digital converter, pins A0 [14] to A5 [19])
static byte prevADCSRA = ADCSRA;
ADCSRA = 0;

/* Set the type of sleep mode we want. Can be one of (in order of power saving):
SLEEP_MODE_IDLE (Timer 0 will wake up every millisecond to keep millis running)
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE (TIMER 2 keeps running)
SLEEP_MODE_EXT_STANDBY
SLEEP_MODE_STANDBY (Oscillator keeps running, makes for faster wake-up)
SLEEP_MODE_PWR_DOWN (Deep sleep)
*/
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();

// Turn of Brown Out Detection (low voltage)
// Thanks to Nick Gammon for how to do this (temporarily) in software rather than
// permanently using an avrdude command line.
//
// Note: Microchip state: BODS and BODSE only available for picoPower devices ATmega48PA/88PA/168PA/328P
//
// BODS must be set to one and BODSE must be set to zero within four clock cycles. This sets
// the MCU Control Register (MCUCR)
MCUCR = bit (BODS) | bit (BODSE);

// The BODS bit is automatically cleared after three clock cycles so we better get on with it
MCUCR = bit (BODS);

// Ensure we can wake up again by first disabling interupts (temporarily) so
// the wakeISR does not run before we are asleep and then prevent interrupts,
// and then defining the ISR (Interrupt Service Routine) to run when poked awake
noInterrupts();
attachInterrupt(digitalPinToInterrupt(wakePin), sleepISR, RISING);

// Send a message just to show we are about to sleep
Serial.println("Good night!");
Serial.flush();

// Allow interrupts now
interrupts();

// And enter sleep mode as set above
sleep_cpu();

// --------------------------------------------------------
// µController is now asleep until woken up by an interrupt
// --------------------------------------------------------

// Wakes up at this point when wakePin is brought LOW - interrupt routine is run first
Serial.println("I'm awake!");

// Re-enable ADC if it was previously running
ADCSRA = prevADCSRA;
}
}

// When wakePin is brought LOW this interrupt is triggered FIRST (even in PWR_DOWN sleep)
void sleepISR() {
// Prevent sleep mode, so we don't enter it again, except deliberately, by code
sleep_disable();

// Detach the interrupt that brought us out of sleep
detachInterrupt(digitalPinToInterrupt(wakePin));

// Now we continue running the main Loop() just after we went to sleep
}

// Double blink just to show we are running. Note that we do NOT
// use the delay for final delay here, this is done by checking
// millis instead (non-blocking)
void doBlink() {
static unsigned long lastMillis = 0;

if (millis() > lastMillis + 1000) {
digitalWrite(ledPin, HIGH);
delay(10);
digitalWrite(ledPin, LOW);
delay(200);
digitalWrite(ledPin, HIGH);
delay(10);
digitalWrite(ledPin, LOW);
lastMillis = millis();
}
}

It's been a while since I did sleep/wake. I'll read it sometimes to remind me what's what. Posted in code tag.

/*
  Low Power SLEEP modes for Arduino UNO/Nano
  using Atmel328P microcontroller chip.
  For full details see my video #115
  at https://www.youtube.com/ralphbacon
  (Direct link to video: https://TBA)
  All details can be found at https://github.com/ralphbacon
*/
#include "Arduino.h"
#include <avr/sleep.h>

#define sleepPin 8  // When low, makes 328P go to sleep
#define wakePin 3   // when low, makes 328P wake up, must be an interrupt pin (2 or 3 on ATMEGA328P)
#define ledPin 2    // output pin for the LED (to show it is awake)

void setup() {
 Serial.begin(9600);

 // Keep pins high until we ground them
 //pinMode(sleepPin, INPUT_PULLUP); // I commented this because I don't use pin 8 in the sleep condition, I use the same pin 3
 pinMode(wakePin, INPUT_PULLUP);  

 // Flashing LED just to show the µController is running
 digitalWrite(ledPin, LOW);
 pinMode(ledPin, OUTPUT);
 pinMode(13,OUTPUT); // I set up pin 13 to output mode so the LED attached will go OFF
 Serial.println("Setup completed.");
}

// The loop just blinks an LED when not in sleep mode
void loop() {

 // Just blink LED twice to show we're running
 doBlink();

 // Is the "go to sleep" pin now LOW?
 if (digitalRead(wakePin) == LOW) {

   // Disable the ADC (Analog to digital converter, pins A0 [14] to A5 [19])
   static byte prevADCSRA = ADCSRA;
   ADCSRA = 0;

   /* Set the type of sleep mode we want. Can be one of (in order of power saving):
       SLEEP_MODE_IDLE (Timer 0 will wake up every millisecond to keep millis running)
       SLEEP_MODE_ADC
       SLEEP_MODE_PWR_SAVE (TIMER 2 keeps running)
       SLEEP_MODE_EXT_STANDBY
       SLEEP_MODE_STANDBY (Oscillator keeps running, makes for faster wake-up)
       SLEEP_MODE_PWR_DOWN (Deep sleep)
   */
   set_sleep_mode (SLEEP_MODE_PWR_DOWN);
   sleep_enable();

   // Turn of Brown Out Detection (low voltage)
   // Thanks to Nick Gammon for how to do this (temporarily) in software rather than
   // permanently using an avrdude command line.
   //
   // Note: Microchip state: BODS and BODSE only available for picoPower devices ATmega48PA/88PA/168PA/328P
   //
   // BODS must be set to one and BODSE must be set to zero within four clock cycles. This sets
   // the MCU Control Register (MCUCR)
   MCUCR = bit (BODS) | bit (BODSE);

   // The BODS bit is automatically cleared after three clock cycles so we better get on with it
   MCUCR = bit (BODS);

   // Ensure we can wake up again by first disabling interupts (temporarily) so
   // the wakeISR does not run before we are asleep and then prevent interrupts,
   // and then defining the ISR (Interrupt Service Routine) to run when poked awake
   noInterrupts();
   attachInterrupt(digitalPinToInterrupt(wakePin), sleepISR, RISING);

   // Send a message just to show we are about to sleep
   Serial.println("Good night!");
   Serial.flush();

   // Allow interrupts now
   interrupts();

   // And enter sleep mode as set above
   sleep_cpu();

   // --------------------------------------------------------
   // µController is now asleep until woken up by an interrupt
   // --------------------------------------------------------

   // Wakes up at this point when wakePin is brought LOW - interrupt routine is run first
   Serial.println("I'm awake!");

   // Re-enable ADC if it was previously running
   ADCSRA = prevADCSRA;
 }
}


// When wakePin is brought LOW this interrupt is triggered FIRST (even in PWR_DOWN sleep)
void sleepISR() {
 // Prevent sleep mode, so we don't enter it again, except deliberately, by code
 sleep_disable();

 // Detach the interrupt that brought us out of sleep
 detachInterrupt(digitalPinToInterrupt(wakePin));

 // Now we continue running the main Loop() just after we went to sleep
}


// Double blink just to show we are running. Note that we do NOT
// use the delay for final delay here, this is done by checking
// millis instead (non-blocking)
void doBlink() {
 static unsigned long lastMillis = 0;

 if (millis() > lastMillis + 1000) {
   digitalWrite(ledPin, HIGH);
   delay(10);
   digitalWrite(ledPin, LOW);
   delay(200);
   digitalWrite(ledPin, HIGH);
   delay(10);
   digitalWrite(ledPin, LOW);
   lastMillis = millis();
 }
}