Artemis Nano hardware interrupt triggering as soon as it is attached to function.

I’m running into a problem with the Artemis Nano where I want it to go into sleep mode when a pushbutton is pressed, then exit it as soon as the button is pressed again. the sleep and wakeup functions are within interrupts and are set to trigger on a falling edge. The problem is that as soon as the the interrupt gets attached, it immediately triggers to go into sleep mode, then hard-faults and starts blinking the LED in the S.O.S. pattern.

The relevant code is below, as is the output on my serial monitor

#define SLEEP_INTERRUPT   4

setup
{
    pinMode(SLEEP_INTERRUPT, INPUT);
#ifdef DEBUG
  Serial.print("About to attach interrupt");
#endif
  attachInterrupt(digitalPinToInterrupt(SLEEP_INTERRUPT), sleepModeSwitch, FALLING);
#ifdef DEBUG
  Serial.print("Interrupt attached");
#endif
}

void sleepModeSwitch()
{
#ifdef DEBUG
  Serial.print("Interrupt triggered! button status: "); Serial.println(digitalRead(SLEEP_INTERRUPT));
#endif
  if(sleep_mode_status == false)
  {
    goToSleep();
  }
  else
  {
    wakeUp();
  }
}

void goToSleep()
{
  sleep_mode_status = true;
#ifdef DEBUG
  Serial.println("Going to sleep");
  delay(50);  //Wait for serial to finish
  Serial.end(); //Power down UART(s)
#endif
  // turn off the led.
  digitalWrite(LED_BUILTIN, LOW);

  // Stop the BLE advertising.
  BLE.stopAdvertise() ;

  powerControlADC(false);
  
  for(int x = 0; x < 50; x++)
  {
    if(x != 18)
    {
      am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE);
    }
  }
  //Power down Flash, SRAM, cache
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_CACHE); //Turn off CACHE
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_512K); //Turn off everything but lower 512k
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); //Turn off everything but lower 64k
  //am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); //Turn off all memory (doesn't recover)
  
  // // Enable interrupts to the core.
  am_hal_interrupt_master_enable();
  
  // //Enable the timer interrupt in the NVIC.
  // NVIC_EnableIRQ(STIMER_CMPR6_IRQn);

  //Go to Deep Sleep.
  am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
}

void wakeUp()
{
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX);
  
  // Renable UART0 pins
  am_hal_gpio_pinconfig(48, g_AM_BSP_GPIO_COM_UART_TX);
  am_hal_gpio_pinconfig(49, g_AM_BSP_GPIO_COM_UART_RX);

  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_UART0);

  initializeADC();

#ifdef DEBUG
  Serial.begin(115200);
  Serial.println("Waking up! Hello world!");
#endif
  deepSleepTimer = millis() ;
  sleep_mode_status = false;
}

DATARX 055 INITIAL TEST

About to attach interrupt

Interrupt triggered! button status: 1

Going to sleep

++ MbedOS Error Info ++

Error Status: 0x80FF0144 Code: 324 Module: 255

Error Message: Assertion failed: status == osOK

Location: 0x29FED

File: mbed-os/rtos/source/ThisThread.cpp+225

Error Value: 0x0

Current Thread: main Id: 0x10006E2C Entry: 0x2B141 StackSize: 0x1000 StackMem: 0x10005E08 SP: 0x1005FED4

For more info, visit: https://mbed.com/s/error?error=0x80FF01 … TEMIS_NANO

– MbedOS Error Info –

Attached to the relevant pin is a basic RC debounce circuit, seen below:


I’m still testing, but I wanted to get some thoughts on what was happening here. According my multimeter and oscilloscope, the signal isn’t oscillating so I don’t know what could be generating the falling edge that should be needed to trigger the interrupt. Any thoughts on what might be happening?

Some further information. It appears that, while the interrupt is being called very prematurely as soon as its attached to a pin, it only seems to run once. I added some code to toggle two different LEDs based on whether or not the Artemis is in sleep mode. These LEDs toggle inversely to one another; When the Artemis is asleep, one is on and the other is off. Vice Versa when awake. However, as soon as the LEDs are indicating sleep mode, there’s about half a second of illumination before they are both completely dark. Additionally, there’s no hardfault message or S.O.S flashing from one of the LEDs, which is strange to me.

An update based on further testing:

I cut out all the stuff inside the interrupt related to sleeping and waking up just so I could see the interrupt itself in action by toggling two LEDs on and off (one is on when the other is off, vice versa). The interrupt is still being called as soon as its attached, and I’ve received suggestions to clear the interrupt flag before attaching it. I’m working trying something like that now

The problem with your code is that you are attaching the interrupt to the pushbutton before you have initialized the sleep mode subsystem. This is causing the interrupt to trigger immediately and put the board into sleep mode before the sleep mode subsystem is ready.

To fix the problem, you need to initialize the sleep mode subsystem before you attach the interrupt. You can do this by calling the initSleepMode() function before you call the attachInterrupt() function.

Here is a revised version of your code that should fix the problem:

C++

#define SLEEP_INTERRUPT 4

void setup() {

// Initialize the sleep mode subsystem.

initSleepMode();

// Set the pushbutton pin to input mode.

pinMode(SLEEP_INTERRUPT, INPUT);

// Attach the interrupt to the pushbutton.

attachInterrupt(digitalPinToInterrupt(SLEEP_INTERRUPT), sleepModeSwitch, FALLING);

}

void sleepModeSwitch() {

// If the board is in sleep mode, wake it up.

if (isSleepMode()) {

wakeUp();

} else {

// Put the board into sleep mode.

goToSleep();

}

}

With this revised code, the interrupt will only trigger when the pushbutton is pressed, and the board will not go into sleep mode until the sleep mode subsystem is ready.

ReahaTaul:
The problem with your code is that you are attaching the interrupt to the pushbutton before you have initialized the sleep mode subsystem. This is causing the interrupt to trigger immediately and put the board into sleep mode before the sleep mode subsystem is ready.

To fix the problem, you need to initialize the sleep mode subsystem before you attach the interrupt. You can do this by calling the initSleepMode() function before you call the attachInterrupt() function.

Here is a revised version of your code that should fix the problem:

C++

#define SLEEP_INTERRUPT 4

void setup() {

// Initialize the sleep mode subsystem.

initSleepMode();

// Set the pushbutton pin to input mode.

pinMode(SLEEP_INTERRUPT, INPUT);

// Attach the interrupt to the pushbutton.

attachInterrupt(digitalPinToInterrupt(SLEEP_INTERRUPT), sleepModeSwitch, FALLING);

}

void sleepModeSwitch() {

// If the board is in sleep mode, wake it up.

if (isSleepMode()) {

wakeUp();

} else {

// Put the board into sleep mode.

goToSleep();

}

}

With this revised code, the interrupt will only trigger when the pushbutton is pressed, and the board will not go into sleep mode until the sleep mode subsystem is ready.

Well, that would hopefully fix the sleep mode stuff, but I actually commented out everything related to putting the Artemis to sleep in the interrupt and replaced it with alternating two LEDs (When in “sleep mode” one turns on, other turns off. When “awake” vice versa). Turns out that as soon as the interrupt is attached to the pin, it triggers without a button press.

From what I understand, me declaring the button pin as an INPUT_PULLUP is creating enough of a falling edge to qualify, and the Artemis is remembering that it happened and triggering the interrupt immediately. Assuming that’s the case, I need to clear the “interrupt has occurred” flag before I attach the interrupt, which I still can’t figure out how to do. Yet.

I have just checked some of the code. As you set a attachinterrupt() the first time, it will initialize the complete IRQ system and subsequently clear any interrupt-flag that might be pending, before setting the interrupt. As I have a Nano I tried it as well and I run into the same issue as you. Still trying to find out way, but as soon as the interrupt is being set it triggers.

For now a workaround: debounce structure which is always good to implement with a switch.

#define SLEEP_INTERRUPT  9

bool ledstat = false;       // led start condition
bool prevstat = ledstat;    // remember the previous led condition
unsigned long debounce;     // Stores the last millis()
#define DEBOUNCETIME 1000   // number of milli seconds needed between pushes

void setup() {
  Serial.begin(115200);
  while (!Serial); //Wait for the serial port to come online

  Serial.println(F("check interrupt with led"));
  pinMode(LED_BUILTIN, OUTPUT);
 
  // Set the pushbutton pin to input mode.
  pinMode(SLEEP_INTERRUPT, INPUT);
  
  debounce = millis();
  
  // Attach the interrupt to the pushbutton.
  attachInterrupt(digitalPinToInterrupt(SLEEP_INTERRUPT), sleepModeSwitch, FALLING);
}

void sleepModeSwitch() {
  if (millis() -debounce < DEBOUNCETIME ) return;  // debounce wait 

  ledstat = !ledstat;
  digitalWrite(LED_BUILTIN,ledstat);

  debounce = millis();
}

void loop() {
  if (prevstat != ledstat) {
    if (ledstat) Serial.println("Led is on");
    else Serial.println("Led is off");
    
    prevstat = ledstat;
  }
}

found it… and fixed

During the first initialization, the interrupts are enabled, and thus before really setting the interrupt.

copy attached file to: arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/arduino/mbed-bridge/core-implement to replace CommonInterrupt.cpp. Recompile your sketch and it should work now.

note: the patch is on my Ubuntu, if you use Windows it is in another place.

CommonInterrupt.zip (1.59 KB)

Just one more thing… Make sure to keep the debounce-timeout structure in place to prevent re-triggers due to switch-glitches/ jitter.

Looks like there’s a problem with your fix , at least for Windows machines. I found where it’s supposed to go and I got “Error compiling for board RedBoard Artemis Nano”. I’m still parsing out exactly where the problem is, but when I find it I’ll let you know

paulvha:
found it… and fixed

During the first initialization, the interrupts are enabled, and thus before really setting the interrupt.

copy attached file to: arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/arduino/mbed-bridge/core-implement to replace CommonInterrupt.cpp. Recompile your sketch and it should work now.

note: the patch is on my Ubuntu, if you use Windows it is in another place.

This is about as far as it got before things went wonky

C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\cores\arduino\mbed-bridge\core-implement\CommonInterrupt.cpp:177:6: error: no declaration matches ‘void arduino::InterruptInParam::_irq_handler(uintptr_t, gpio_irq_event)’

void InterruptInParam::_irq_handler(uintptr_t id, gpio_irq_event event) // {feb 2023}

^~~~~~~~~~~~~~~~

In file included from C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge/core-extend/ArduinoAPI.h:9,

from C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge/Arduino.h:20,

from C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/sdk/ArduinoSDK.h:9,

from :

C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge/core-extend/Common.h:111:17: note: candidate is: ‘static void arduino::InterruptInParam::_irq_handler(uint32_t, gpio_irq_event)’

static void _irq_handler(uint32_t id, gpio_irq_event event);

^~~~~~~~~~~~

C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge/core-extend/Common.h:64:7: note: ‘class arduino::InterruptInParam’ defined here

class InterruptInParam : public mbed::InterruptIn {

^~~~~~~~~~~~~~~~

“C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\tools\arm-none-eabi-gcc\8-2018-q4-major/bin/arm-none-eabi-g++” -include “C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO/mbed/mbed_config.h” -include “C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/sdk/ArduinoSDK.h” -iprefix “C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/” “@C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO/mbed/.cxx-flags” -MMD -DARDUINO=10813 -DARDUINO_APOLLO3_SFE_ARTEMIS_NANO -DARDUINO_ARCH_MBED -DARDUINO_ARCH_APOLLO3 -DMBED_NO_GLOBAL_USING_DIRECTIVE -DCORDIO_ZERO_COPY_HCI “@C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO/mbed/.cxx-symbols” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\cores\arduino” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge/core-api” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge/core-api/api/deprecated” “@C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO/mbed/.includes” “C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\cores\arduino\mbed-bridge\core-implement\CommonTiming.cpp” -o “C:\Users\Farnaz\AppData\Local\Temp\arduino_build_513726\core\mbed-bridge\core-implement\CommonTiming.cpp.o”

“C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\tools\arm-none-eabi-gcc\8-2018-q4-major/bin/arm-none-eabi-g++” -include “C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO/mbed/mbed_config.h” -include “C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/sdk/ArduinoSDK.h” -iprefix “C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/” “@C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO/mbed/.cxx-flags” -MMD -DARDUINO=10813 -DARDUINO_APOLLO3_SFE_ARTEMIS_NANO -DARDUINO_ARCH_MBED -DARDUINO_ARCH_APOLLO3 -DMBED_NO_GLOBAL_USING_DIRECTIVE -DCORDIO_ZERO_COPY_HCI “@C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO/mbed/.cxx-symbols” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\cores\arduino” "-IC:

\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO" “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge/core-api” “-IC:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1/cores/arduino/mbed-bridge/core-api/api/deprecated” “@C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_NANO/mbed/.includes” “C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\cores\arduino\mbed-bridge\core-implement\HardwareSerial.cpp” -o “C:\Users\Farnaz\AppData\Local\Temp\arduino_build_513726\core\mbed-bridge\core-implement\HardwareSerial.cpp.o”

Using library Wire at version 2.0.0 in folder: C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\libraries\Wire

Using library ArduinoBLE at version 1.2.2 in folder: C:\Users\Farnaz\Documents\Arduino\libraries\ArduinoBLE

Using library EEPROM at version 2.0.0 in folder: C:\Users\Farnaz\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\libraries\EEPROM

Using library Adafruit_Unified_Sensor at version 1.1.2 in folder: C:\Users\Farnaz\Documents\Arduino\libraries\Adafruit_Unified_Sensor

Using library Adafruit_BNO055 at version 1.1.11 in folder: C:\Users\Farnaz\Documents\Arduino\libraries\Adafruit_BNO055

try the attached one.

CommonInterrupt.zip (1.57 KB)

Alright, this is compiling perfectly now. Many thanks! Seriously, I really appreciate all the help I’ve been getting with this

COOL, great to hear !.. what a ride :slight_smile:

Seriously, working with hardware/firmware feels like you’re wrestling a wild animal. You think it’s beat, you’re starting to walk away, then you hear it snort, you turn around it its just staring at you with a malicious grin and a crazed look in its eyes for round two…