XIAO nRF52840 (Sense) is locking up when trying to use an interrupt

I have a XIAO nRF52840 (Sense) and have the IMU working to detect tilt. I have it set/reset two persistent relays I have for a project. I hear them toggle, and see the LED change colors for the two tilt states.

But then I was trying to use one more pin for an input interrupt. I have been able to get the interrupt to fire but can’t seem to get it working reliably or with any accuracy/clarity what it’s doing. Here is my script:

#include "LSM6DS3.h"
#include "Wire.h"

//Create a instance of class LSM6DS3
LSM6DS3 myIMU(I2C_MODE, 0x6A);    //I2C device address 0x6A

const int relayASetPin = 0;
const int relayAResetPin = 1;
const int relayBSetPin = 2;
const int relayBResetPin = 3;
const int signalPin = 4;

volatile byte state = LOW;

float zAccel = 0;
float hysterisis = 0;

bool lastZStateUp = true;
 
void setup() {
  //Serial.begin(115200);
  //while (!Serial);

  pinMode(LED_BUILTIN, OUTPUT);
  myIMU.begin();

  pinMode(relayASetPin, OUTPUT);
  pinMode(relayAResetPin, OUTPUT);
  pinMode(relayBSetPin, OUTPUT);
  pinMode(relayBResetPin, OUTPUT);

  pinMode(signalPin, INPUT);

  digitalWrite(relayASetPin, LOW);
  digitalWrite(relayAResetPin, LOW);
  digitalWrite(relayBSetPin, LOW);
  digitalWrite(relayBResetPin, LOW);

  digitalWrite(LEDB, HIGH);
  digitalWrite(LEDG, LOW);

  zAccel =  myIMU.readFloatAccelZ();

  // give accel time to settle
  delay (100);

  pinMode(signalPin, INPUT);
  attachInterrupt(signalPin, blink, FALLING);
  //attachInterrupt(digitalPinToInterrupt(signalPin), blink, CHANGE);

}
 
void loop() {
  zAccel =  myIMU.readFloatAccelZ();
 
  //Serial.print(" Z1 = ");
  //Serial.println(myIMU.readFloatAccelZ(), 4);

  if (zAccel >  0.60 + hysterisis) {
    if (lastZStateUp != true) {
      //Serial.println("new up state");

      digitalWrite(LEDB, HIGH);
      digitalWrite(LEDG, LOW);

      digitalWrite(relayASetPin, HIGH);
      delay(20);
      digitalWrite(relayASetPin, LOW);
      delay(500);
      digitalWrite(relayBSetPin, HIGH);
      delay(20);
      digitalWrite(relayBSetPin, LOW);
      
      lastZStateUp = true;
      hysterisis = 0.0;
    } 
  } else {
    if (lastZStateUp == true) {
      //Serial.println("new down state");
      digitalWrite(LEDB, LOW);
      digitalWrite(LEDG, HIGH);

      digitalWrite(relayAResetPin, HIGH);
      delay(20);
      digitalWrite(relayAResetPin, LOW);
      delay(500);
      digitalWrite(relayBResetPin, HIGH);
      delay(20);
      digitalWrite(relayBResetPin, LOW);

      lastZStateUp = false;
      hysterisis = 0.2;
    }
  }

  delay(500);
}

void blink () {
  //Serial.println(" got int");
  state = !state;

   if (state == LOW ) {
     digitalWrite(LEDR, LOW);
       delay(500);
   } else {
         digitalWrite(LEDR, HIGH);
       delay(500);
   }
}

I’ve tried printing from the interrupt, and setting the led. When I touch pin 4 to ground, the board locks up (tilts don’t trigger the relays anymore).

I’ve tried

  pinMode(signalPin, INPUT);

and

  pinMode(signalPin, INPUT_PULLUP);

And I’ve tried

  attachInterrupt(signalPin, blink, FALLING);
  attachInterrupt(digitalPinToInterrupt(signalPin), blink, CHANGE);
  attachInterrupt(digitalPinToInterrupt(signalPin), blink, LOW);

Ok, learned a lot since I posted this. Shared the working code at the bottom.

Things I learned:

  • learned about the two versions (mbed, non-mbed) and how they relate to ble/imu usage
  • fixed up the isr to be clean and just trigger the debounce in main loop
  • fixed up the debounce to only try if the last signal was not within a few hundred msec
#include "Wire.h"

const int relayASetPin = 0;
const int relayAResetPin = 1;
const int relayBSetPin = 2;
const int relayBResetPin = 3;
const int signalPin = 4;

enum trainState {
  STOP_1,
  FORWARD,
  STOP_2,
  REVERSE
};

enum trainRelay {
  RELAY_A,
  RELAY_B
};

trainState tState = STOP_1;

bool intDetected = false;
int intCount=0;
int consecutiveSameRead = 0;
int debounceState;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.print(" \nTrain Relay Board V0.01\n\n");

  pinMode(LED_BUILTIN, OUTPUT);

  pinMode(relayASetPin, OUTPUT);
  pinMode(relayAResetPin, OUTPUT);
  pinMode(relayBSetPin, OUTPUT);
  pinMode(relayBResetPin, OUTPUT);
  pinMode(signalPin, INPUT);

  // Setup the default train relay stopped state here
  digitalWrite(relayASetPin, LOW);
  digitalWrite(relayAResetPin, LOW);
  digitalWrite(relayBSetPin, LOW);
  digitalWrite(relayBResetPin, LOW);

  changeRelay(false, RELAY_A);
  changeRelay(false, RELAY_B);

  pinMode(signalPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(signalPin), trainButtonInt, FALLING);
}

void loop() {

  if (intDetected) {
    consecutiveSameRead = 0;
    debounceState = digitalRead(signalPin);
    while (consecutiveSameRead < 4) {
      delay(30);
      if (digitalRead(signalPin) == debounceState) {
        consecutiveSameRead++;
      } else {
        consecutiveSameRead = 0;
        debounceState = digitalRead(signalPin);
      }
    }
    if (debounceState == LOW) {
      intCount++;
      Serial.print("intCount: ");
      Serial.println(intCount);

      switch (tState) {
        case STOP_1:
          tState = FORWARD;
          changeRelay(true, RELAY_A);
          break;
        case FORWARD:
          tState = STOP_2;
          changeRelay(true, RELAY_B);
          break;
        case STOP_2:
          tState = REVERSE;
          changeRelay(false, RELAY_A);
          break;
        case REVERSE:
          changeRelay(false, RELAY_B);
          tState = STOP_1;
          break;
        default:
          changeRelay(false, RELAY_A);
          changeRelay(false, RELAY_B);
          tState = STOP_1;
          break;
      }

      Serial.print("State: ");
      Serial.println(tState);
    }
    intDetected = false;
  }
  delay(50);
}

void changeRelay( bool set, trainRelay relay) {
  int pin = 0;
  if (set == true) {
    if (relay == RELAY_A) {
      pin = relayASetPin;
    } else {
      pin = relayBSetPin;
    }
  } else {
    if (relay == RELAY_A) {
      pin = relayAResetPin;
    } else {
      pin = relayBResetPin;
    }
  }

  digitalWrite(pin, HIGH);
  delay(20);
  digitalWrite(pin, LOW);
  delay(500);
}

void trainButtonInt () {
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();

  if (interrupt_time - last_interrupt_time > 200)
  {
    intDetected = true;
  }
  last_interrupt_time = interrupt_time;
}