Issues with sleep modes and interrupts on Micro Pro

Cant get board to wake following interrupt

I'm using LED flashes to indicate the state of the program; and a switch to start the "sleep" process so that following a reset the arduino will not go to sleep and prevent reprogramming.

In the code that follows I have this line commented,

//sleep_cpu(); //activating sleep mode

and I can demonstrate that the interrupt is working with a message on the serial monitor "Interrupt Fired" in wakeUp();

However if I remove the comment marks so it goes to sleep one of two things happens; (listed at start of code)

SLEEP_MODE_IDLE: or SLEEP_MODE_ADC: does not stay asleep
all other sleep modes - pressing the button for the interrupt has no effect, it wont wake up

I've been fighting with this for a while now, grateful for any suggestions.

/**
   Author:Ab Kurk    version: 1.0     date: 24/01/2018
   Description:    This sketch is part of the beginners guide to putting your Arduino to sleep
   tutorial. It is to demonstrate how to put your arduino into deep sleep and how to wake it up.
   Link To Tutorial http://www.thearduinomakerman.info/blog/2018/1/24/guide-to-arduino-sleep-mode

   INFO
   Micro, Leonardo, other 32u4-based boards support interrupts on pins 0, 1, 2, 3, 7
   Sleep modes For the Atmega328P (Nick Gammon http://www.gammon.com.au/power
   SLEEP_MODE_IDLE: 15 mA  //does not stay asleep
   SLEEP_MODE_ADC: 6.5 mA //does not stay asleep
   SLEEP_MODE_PWR_SAVE: 1.62 mA  //wont wake up
   SLEEP_MODE_EXT_STANDBY: 1.62 mA //wont wake up
   SLEEP_MODE_STANDBY : 0.84 mA //wont wake up
   SLEEP_MODE_PWR_DOWN : 0.36 mA  //wont wake up
*/

#include <avr/sleep.h>//this AVR library contains the methods that controls the sleep modes
const byte interruptPin = 7; //Pin we are going to use to wake up the Arduino
const byte sleepPin = 9; //Pin we are going to use to sleep the Arduino - button to gnd
const byte LEDPin = 6; //connected to led & resisitor on pin 6

void flashLed(int count, int t) {
  //shows its not asleep
  for (int i = 0; i < count; i++) {
    digitalWrite(LEDPin, HIGH); //turning LED on
    delay(t); //happy to use delay() as it wont prevent an interrupt
    digitalWrite(LEDPin, LOW); //turning LED off
    delay(t); //total time per rep is 0.5 sec
  }
}


void setup() {
  Serial.begin(57600);//Start Serial Comunication
  pinMode(LEDPin, OUTPUT); //indicate when Arduino is Asleep
  pinMode(interruptPin, INPUT_PULLUP); //Set interruptPin as input
  pinMode(sleepPin, INPUT_PULLUP); //Set sleepPin as input
  flashLed(2, 1000); // show state and allow time for serial comms to start
  Serial.println("Initialisation complete");
  flashLed(6, 250);// allow 6 flashes = 3 sec to write above message or reprogram before it can sleep
  Serial.println("Setup completed");
  delay(1000);
}

void loop() {
  flashLed(2, 500);
  Serial.println("not ready to sleep");
  delay(1000);
  if (digitalRead(sleepPin)) flashLed(10, 100); //not going to sleep yet
  else {
    Serial.println("Going_To_Sleep in 5 sec");
    flashLed(5, 500); //slow flash 5 seconds before going to sleep
    Going_To_Sleep();
  }
}

void Going_To_Sleep() {
  sleep_enable();//Enabling sleep mode
  //attachInterrupt(0, wakeUp, LOW);//attaching a interrupt to pin d2
  //https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
  //changed above line to use recommended syntax, and trigger on rising edge
  attachInterrupt(digitalPinToInterrupt(interruptPin), wakeUp, RISING );
  //set_sleep_mode(SLEEP_MODE_PWR_DOWN);//Setting the sleep mode, in our case full sleep
  set_sleep_mode(SLEEP_MODE_IDLE);
  digitalWrite(LEDPin, LOW); //turning LED off
  delay(1000); //wait a second to allow the led to be turned off before going to sleep
  //sleep_cpu();//activating sleep mode
  Serial.println("just woke up!");//next line of code executed after the interrupt
  digitalWrite(LEDPin, HIGH); //turning LED on
}

void wakeUp() {
  Serial.println("Interrupt Fired");//Print message to serial monitor
  sleep_disable();//Disable sleep mode
  detachInterrupt(digitalPinToInterrupt(interruptPin)); //Removes the interrupt from interruptPin;
}

The timer 0 overflow wakes the processor.

The evidence indicates that a rising external interrupt isn't capable of waking your processor. For some AVR processors that is true.

Try using a pin change interrupt.

1 Like

Thanks!

changed to

attachInterrupt(digitalPinToInterrupt(interruptPin), wakeUp, LOW );

and the interrupt works - but the serial port is still inactive. - even if I do a

Serial.begin(57600);//re-start Serial Comunication
in the wakeup routine!

You are printing from your wake up routine, an ISR.

I’m too old to remember dets, so I don’t do any printing or reading of the serial stuff in an ISR.

Just be sure this isnt a (your) problem, like just print after the point to which control will return.

You can explain why it isn’t a problem, but don’t on my account as I will be unable to remember if a time comes when it might be handy to do.

HTH

a7

1 Like

FWIW I only have '328p handy, so moving the wakeup to pin 2, uncommenting the sleep_cpu(); and using SLEEP_MODE_PWR_DOWN, as well as switching to LOW in the interrupt attachment...

I think it operates as desired.

Initialisation complete
Setup completed
not ready to sleep
not ready to sleep
Going_To_Sleep in 5 sec


No activity, I assume the thing was asleep.

Interrupt Fired
just woke up!
not ready to sleep
not ready to sleep


I realize this is several steps away from what you are looking at.

I have a special interest in sleep, not only because I am an insomniac.

a7

1 Like

There is a specific correct sequence to power down / power up the USB pad that is independent of sleeping the processor. I've made a few unsuccessful attempts to get that working. What I remember is that sleeping the processor without going through the correct power down sequence triggers the host computer into believing the USB device is defective.

1 Like

And just in case I'm not the only one that might try, Wokwi.com doesn't simulate sleep, so there is not that substitute for real world experimentation.

a7

Thanks for all replies.
@Coding_Badly

That explains a LOT; why it wouldnt reprogram without a lot of port changing etc.
Maybe when ive got it working to my satisfaction I'll try it on my linux box under PUTTY.
Anyway the LED flashing sequence shows the sleep and interrupt restart is working.
I'll follow this up with an updated code soon.

1 Like

Well, I found this very useful old thread

and it DOES resolve the problem of the port becoming unusable;
however I cant get the serial output to restart after interrupt.

/**
   Author:Ab Kurk    version: 1.0     date: 24/01/2018
   Description:    This sketch is part of the beginners guide to putting your Arduino to sleep
   tutorial. It is to demonstrate how to put your arduino into deep sleep and how to wake it up.
   Link To Tutorial http://www.thearduinomakerman.info/blog/2018/1/24/guide-to-arduino-sleep-mode

   https://forum.arduino.cc/t/resolved-serial-hangs-after-wake-up-micro/182234/12

   INFO
   Micro, Leonardo, other 32u4-based boards support interrupts on pins 0, 1, 2, 3, 7
   Sleep modes For the Atmega328P (Nick Gammon http://www.gammon.com.au/power
   SLEEP_MODE_IDLE: 15 mA  //does not stay asleep
   SLEEP_MODE_ADC: 6.5 mA //does not stay asleep
   SLEEP_MODE_PWR_SAVE: 1.62 mA
   SLEEP_MODE_EXT_STANDBY: 1.62 mA
   SLEEP_MODE_STANDBY : 0.84 mA
   SLEEP_MODE_PWR_DOWN : 0.36 mA

   //attachInterrupt(digitalPinToInterrupt(interruptPin), wakeUp, LOW );  //LOW (default), CHANGE, RISING, FALLING
   does not wake from edge trigger, but LOW works
*/

#include <avr/sleep.h>//this AVR library contains the methods that controls the sleep modes
const byte interruptPin = 7; //Pin we are going to use to wake up the Arduino
const byte sleepPin = 9; //Pin we are going to use to sleep the Arduino - button to gnd
const byte LEDPin = 6; //connected to led & resisitor on pin 6

int ledState = 0;
int intFlag = 0;  //bool, byte, char, int all take same space so we'll just use int.

void flashLed(int count, int t) {  //show present state of program by led flashes
  for (int i = 0; i < count; i++) {
    delay(t);
    digitalWrite(LEDPin, 1);
    delay(t);
    digitalWrite(LEDPin, 0);
  }
}

void setup() {
  Serial.begin(57600);//Start Serial Comunication
  while (! Serial);
  pinMode(LEDPin, OUTPUT); //indicate when Arduino is Asleep
  pinMode(interruptPin, INPUT_PULLUP); //Set interruptPin as input
  pinMode(sleepPin, INPUT_PULLUP); //Set sleepPin as input
  flashLed(2, 500); // show state and allow time for serial comms to start
  Serial.println("Initialisation complete");
  flashLed(5, 200);// allow 5 flashes = 1 sec to write above message
  Serial.println("Setup completed");
  delay(2000);
}

void loop() {

  if (intFlag == 1) {
    Serial.println("Interrupt Fired");//Print message to serial monitor
    intFlag = 0;
  }
  if (digitalRead(sleepPin)) {
    flashLed(2, 400); //2 slow 4 fast
    Serial.println("not ready to sleep"); //not going to sleep yet
    flashLed(4, 150);
  }
  else {
    Serial.println("Going_To_Sleep in 5 sec");
    flashLed(5, 1000); //slow flash 5 seconds before going to sleep
    Going_To_Sleep();
  }
}

void Going_To_Sleep()
{
  // disable the USB
  USBCON |= _BV(FRZCLK);  //freeze USB clock
  PLLCSR &= ~_BV(PLLE);   // turn off USB PLL
  USBCON &= ~_BV(USBE);   // disable USB
  // this all takes the USB off the host. windows make USB sounds like the USB is physically disconnected.
  // now must close serial port in the host or it gets stuck
  sleep_enable();
  //https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
  attachInterrupt(digitalPinToInterrupt(interruptPin), wakeUp, LOW );  //LOW (default), CHANGE, RISING, FALLING
  set_sleep_mode(SLEEP_MODE_EXT_STANDBY);
  digitalWrite(LEDPin, LOW); //turning LED off
  delay(1000); //wait a second to allow the led to be turned off before going to sleep
  sleep_cpu();//activating sleep mode

  //we come back here after wakeup
  delay(100);
  Serial.println("just woke up!");//next line of code executed after the interrupt
  flashLed(10, 100);  //ten fast flashes
  sei();
  USBDevice.attach(); // now re-open the serial port, hope that it is assigned same 'COMxx'
  // windows make sounds like USB is physically connected?
  delay(1000);
  Serial.begin(57600);//Start Serial Comunication - but it doesnt
}

void wakeUp() {
  intFlag = 1;
  sleep_disable();  //Disable sleep mode
  detachInterrupt(digitalPinToInterrupt(interruptPin)); // Reattached in Going_To_Sleep();
}

Yeah. That's outside of my experience. Someone else will have to help. :crossed_fingers:

1 Like
USBCON |= _BV(FRZCLK);  //freeze USB clock
PLLCSR &= ~_BV(PLLE);   // turn off USB PLL
USBCON &= ~_BV(USBE);   // disable USB

Just spitballing here.

The lack of symmetry bothers me.

Have you tried undoing what these lines do before you attach USB?

Or after?

Also, I don't see that you are the one who detaches it. What is The Who, when and why of any detachment?

Could you try doing your own detachment before (or after) the voodoo lines above?

Just so all monkeying with the USB is in your code, plausibly.

I have no idea if this would change anything, it is just what I would try if I was on a dessert island.

The Who, haha, guess spell check is a fan of Pete Townshend…

a7

A simple test shows the problem goes deeper.
I modified the AnalogReadSerial example to add a led flash to show processor activity independent of the serial I/O; as shown below.
Following a reset the LED behaves as expected but the serial comms does not work.

/*
  AnalogReadSerial Example modified to add an LED to show processor activity

  Reads an analog input on pin 0, prints the result to the Serial Monitor.
  Graphical representation is available using Serial Plotter (Tools > Serial Plotter menu).
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/AnalogReadSerial
*/

void flashLed(int count, int t) {  //show present state of program by led flashes
  const byte LEDPin = 6; //connected to led & resistor on pin 6
  for (int i = 0; i < count; i++) {
    delay(t);
    digitalWrite(LEDPin, 1);
    delay(t);
    digitalWrite(LEDPin, 0);
  }
}

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  //added next two lines to show serial has started
  delay(1000);  //allow time for serial comms to start
  flashLed(4, 200); //to show setup activity
  Serial.println("Setup complete");
}

// the loop routine runs over and over again forever:
void loop() {
  flashLed(1, 500); //to show loop activity
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // print out the value you read:
  Serial.println(sensorValue);
}

However if I connect it to my linux box using the PUTTY serial monitor the window closes when I press reset; and if I restart the PUTTY monitor it shows serial comms is actually working. So it seems to be a quirk of the arduino serial monitor or windows. I'll try using a different seral monitor under windows to check

1 Like

I THINK I may understand the problem.
When it sleeps or is reset the connection between the serial monitor on the PC and the arduino is lost.
I've found that if I stop & restart the serial monitor (I've tried this with PUTTY and TERMITE) it shows data; showing that the arduino DOES continue (or restart) serial output after a reset.

My guess is that the handshaking that controls data transfer stops working when the board is reset; and its probably right that it should.

Anyway, problems solved;

1: edge triggered interrupt does not work from sleep;

2: USB needs to be disabled before going to sleep, else board wont connect to reprogram

3: need to restart the serial monitor to see serial I/O after sleep

Thanks all for your help

1 Like