XIAO SAMD21 interrupt triggered when it shouldn't be

Hi! I want to have two interrupts that are triggered by button click:

  • interrupt 2 will be always attached and their isr will attach interrupt 1
  • interrupt 1 will be attached at the beginning but its ISR will deatach and it couldn’t be called until interrupt2’s ISR is executed

In practice ISR2 is kind of a reset for ISR1.

The problem i am having is in this flow:
btn1 clicked → ISR1 executed → btn2 clicked → ISR1 executed → ISR2 executed

here is a code i was testing with:

#include <Arduino.h>

#define INTERRUPT_ONE_PIN 6
#define INTERRUPT_TWO_PIN 4

// put function declarations here:
void interruptOne();
void interruptTwo();

volatile uint8_t state = 3;
volatile uint8_t called = 0;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  while (!Serial);
  
  pinMode(INTERRUPT_ONE_PIN, INPUT_PULLDOWN);
  pinMode(INTERRUPT_TWO_PIN, INPUT_PULLDOWN);
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_ONE_PIN), interruptOne, FALLING);
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_TWO_PIN), interruptTwo, FALLING);
}

void loop() {
  // put your main code here, to run repeatedly:
  uint8_t localState = state;

  if (localState == 0)
  {
    Serial.println("state is 0");
    Serial.print("called is");
    Serial.println(called);
    state = 3;
    called = 0;
  }
  if (localState == 1)
  {
    Serial.println("state is 1");
    Serial.print("called is");
    Serial.println(called);
    state = 3;
  }
}

void interruptOne() {
  detachInterrupt(digitalPinToInterrupt(INTERRUPT_ONE_PIN));
  state = 0;
  called = 1;
}

void interruptTwo() {
  state = 1;
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_ONE_PIN), interruptOne, FALLING);
}

Hi there and welcome,
Without seeing your schematic and just reviewing the logic, Typically button inputs are PULLUP defined because the push button is connected to Ground via a current limit resistor and or a bypass capacitor.

Your interrupt will fire if the pin goes from HIGH (1) (FALLING) to LOW(0)
Are you using two buttons?
Try the PULLUP on the input and go again.
HTH
GL :slight_smile: PJ

1 Like

Hey @PJ_Glasso thanks for reply!
i’ve updated code and wiring as per your suggestions. situation stayed the same. I just figured out that there are two weird behaviours:

  1. output:
<switch one clicked>
---------
--state is 0
--called is 1
--state is 3
--called is 0
<switch two clicked>
*********
**state is: 1
**called is: 1
**state is: 3
**called is: 1
*********
**state is: 1
**called is: 1
**state is: 3
**called is: 1
*********

What is happening:

sw1 clicked → isr1 called → interrupt detached; state = 0; called = 1; → loop continues → print state = 0, called = 1; set state = 3, called = 0;

some time passes

sw2 clicked → isr2 called → state = 1; interrupt attached; → loop continues → print state = 1, called = 0; set state = 3;
and here is where problem occurs, called is printed 1.

  1. output:
*********
**state is: 1
**called is: 0
**state is: 3
**called is: 0
---------
--state is 0
--called is 1
--state is 3
--called is 0
---------
--state is 0
--called is 1
--state is 3
--called is 0
*********
**state is: 1
**called is: 1
**state is: 3
**called is: 1

this is what i expected to happen:

sw2 clicked → isr2 called → state = 1; interrupt attached; → loop continues → print state = 1, called = 0; set state = 3;

sw1 clicked → isr1 called → interrupt detached; state = 0; called = 1; → loop continues → print state = 0, called = 1; set state = 3, called = 0;

sw2 clicked → isr2 called → state = 1; interrupt attached; → loop continues → print state = 1, called = 0; set state = 3;

and again problem happened on sw2 click, in logs there are two successive “state 0” logs which should not be possible since on first sw1 click interrupt is detached.

I even tried to set pins to input and added pullup resistors, still no luck. I’ve tested the same code on esp8266 and there it works perfectly fine, no double “status = 0” logs, no fantom “called = 1”.

here is updated code:

#include <Arduino.h>

#define INTERRUPT_ONE_PIN 6
#define INTERRUPT_TWO_PIN 4

// put function declarations here:
void interruptOne();
void interruptTwo();

volatile uint8_t state = 0;
volatile uint8_t called = 0;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  //while (!Serial);
  delay(10);
  pinMode(INTERRUPT_ONE_PIN, INPUT);
  pinMode(INTERRUPT_TWO_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_ONE_PIN), interruptOne, RISING);
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_TWO_PIN), interruptTwo, RISING);
}

void loop() {
  // put your main code here, to run repeatedly:
  uint8_t localState = state;

  if (localState == 0)
  {
    Serial.println("---------");
    Serial.print("--state is ");
    Serial.println(state);
    Serial.print("--called is ");
    Serial.println(called);
    noInterrupts();
    state = 3;
    called = 0;
    interrupts();
    Serial.print("--state is ");
    Serial.println(state);
    Serial.print("--called is ");
    Serial.println(called);
  }
  if (localState == 1)
  {
    Serial.println("*********");
    Serial.print("**state is: ");
    Serial.println(state);
    Serial.print("**called is: ");
    Serial.println(called);

    state = 3;
    Serial.print("**state is: ");
    Serial.println(state);
    Serial.print("**called is: ");
    Serial.println(called);
  }
  delay(10);
}

void interruptOne() {
  detachInterrupt(digitalPinToInterrupt(INTERRUPT_ONE_PIN));
  state = 0;
  called = 1;
}

void interruptTwo() {
  state = 1;
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_ONE_PIN), interruptOne, RISING);
}

Hi there
Strange behavior for sure, first I would Increase the delay to 250, or longer and test again, are you hardware debouncing the switch or no then I would move the attach and detach interrupts functions outside of the ISR’s (I feel that’s where something is breaking)
set a flag and do it in a if , else logic in the main code block.
That will fix it.
HTH
GL :slight_smile: PJ

ps. just be sure your button push get’s just one interrupt by slowing things down.

check out how I do the sleep button interrupt and ISR’s in this code example demo

this has to happen outside the case , you can’t have both…
:wink:

update: i cleared interrupt flag EIC->INTFLAG.bit.EXTINT6 = 1; before attaching interrupt and it works fine now. :partying_face:

1 Like