Code not executing after LowPowerSleep timed wakeup

Hello all,

I'm working on my first Arduino project and new to coding. I've searched and searched for an answer and found some solutions that still haven't solved my issue. Apologies in advance for the long post, but trying to provide all the detail needed.

I am working on a project with a moisture sensor that's logging data via wifi to Adafruit (board is MKR1000). My plan is to power it with a battery, so I was trying to implement a timed sleep/wake up between measurements to extend battery life. I was having some issues with my sketch, so I decided to try implementing the sleep in a basic example sketch and I'm still having an issue. The problem is that the code that should execute after the wake up from sleep isn't executing. After it wakes up it's going directly back to the loop.

I'm using the ArduinoLowPower Library GitHub - arduino-libraries/ArduinoLowPower: Powersave features for SAMD boards
and based the below test sketch on the TimedWakeup example that's included with the library with just some basic modifications.

Here's the intention of the below sketch

  1. Blink the LED once (500ms on, 500ms off) then sleep for 5 seconds.
  2. After it wakes, blink twice (200ms on, 200ms off, 200ms on, 200ms off). (then back to the loop)
/*
  TimedWakeup

  This sketch demonstrates the usage of Internal Interrupts to wakeup a chip in sleep mode.
  Sleep modes allow a significant drop in the power usage of a board while it does nothing waiting for an event to happen. Battery powered application can take advantage of these modes to enhance battery life significantly.

  In this sketch, the internal RTC will wake up the processor every 2 seconds.
  Please note that, if the processor is sleeping, a new sketch can't be uploaded. To overcome this, manually reset the board (usually with a single or double tap to the RESET button)

  This example code is in the public domain.
*/

#include "ArduinoLowPower.h"

volatile int alarm_source = 0;

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  // Uncomment this function if you wish to attach function dummy when RTC wakes up the chip
  LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, alarmEvent0, CHANGE);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  // Triggers a 5000 ms sleep (the device will be woken up only by the registered wakeup sources and by internal RTC)
  // The power consumption of the chip will drop consistently
  LowPower.sleep(5000);
}

void alarmEvent0() {
    alarm_source = 0;
    digitalWrite(LED_BUILTIN, HIGH);
    delay(200);
    digitalWrite(LED_BUILTIN, LOW);
    delay(200);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(200);
    digitalWrite(LED_BUILTIN, LOW);
    delay(200);
  // This function will be called once on device wakeup
  // You can do some little operations here (like changing variables which will be used in the loop)
  // Remember to avoid calling delay() and long running functions since this functions executes in interrupt context
}

I added the part with the volatile int alarm_source = 0 (within the setup); and the alarm_source = 0; in the void.alarmEvent0 function after reading this thread but it still isn't working: LowPower.sleep(120000) does not work - MKRFOX1200 - Arduino Forum (that thread is a couple years old, which is why I didn't post back to it).

What appears to be happening is that it does the 500ms blink then goes to sleep and upon wakeup it goes directly back into the loop and completely skips the voild.alarmEvent0 function. What I observe watching the LED is that it is only doing the single 500ms blink, waiting 5 seconds, then loops. It never does the double 200ms blink.

So I'm not sure what's wrong or why this is not executing the void.alarmEvent function. Any help is much appreciated!

  LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, alarmEvent0, CHANGE);

void alarmEvent0() {
    alarm_source = 0;
    digitalWrite(LED_BUILTIN, HIGH);
    delay(200);
...
}

delay() doesn't work in an interrupt handler as it depends on interrupts and interrupts are disabled inside interrupt context (so in interrupt handlers). You shouldn't do lengthy stuff in interrupt handlers anyway, so your code is simply badly designed. You may put your blinking code inside loop() and just set a flag in the interrupt handler which you then check in the loop().

pylon:

  LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, alarmEvent0, CHANGE);

void alarmEvent0() {
    alarm_source = 0;
    digitalWrite(LED_BUILTIN, HIGH);
    delay(200);
...
}




delay() doesn't work in an interrupt handler as it depends on interrupts and interrupts are disabled inside interrupt context (so in interrupt handlers). You shouldn't do lengthy stuff in interrupt handlers anyway, so your code is simply badly designed. You may put your blinking code inside loop() and just set a flag in the interrupt handler which you then check in the loop().

oh yeah I do remember reading that you shouldn't put a delay() in the interrupt handler. I'll definitely remove that. Can you show an example of how to implement setting a flag in the interrupt handler and checking that in the loop? I think that would work well for how I'm going to implement this, but not sure how to do it (or is that what's already being done with the alarm_source = 0?). Thanks!

A very simple sketch might look like this:

volatile bool flag = false;

void setup() {
  attachInterrupt(0, gotEvent, CHANGE);
}

void loop() {
  if (flag) {
    Serial.println("Got the event");
    flag = false;
  }
  // do other stuff here, try to avoid using delay() even here
}

void gotEvent() {
  flag = true;
}

Thanks for the example. That's very helpful. I'll give this a try. I'll also try replacing delay() with millis().

pylon:
A very simple sketch might look like this:

volatile bool flag = false;

void setup() {
 attachInterrupt(0, gotEvent, CHANGE);
}

void loop() {
 if (flag) {
   Serial.println("Got the event");
   flag = false;
 }
 // do other stuff here, try to avoid using delay() even here
}

void gotEvent() {
 flag = true;
}