SAMD21 External Interrupts problem

I am trying to setup an external interrupt in SAMD21 board. Ultimately I want to wake up the MCU from deep sleep with this interrupt. But for starters I want to get this IRQ handled and I am already having troubles with that. I am using the datasheet as reference and some posts on avrfreaks and this forum. I even checked my code with the original source code to be sure if it I am missing anything.

I have the SAMD21 onboard the Arduino Nano 33 IoT and I am using PA20 connected to a button I drive low with a press.

My steps so far are:

  • Setup the IO pin in PORT register group
  • Setup GCLK for EIC
  • Enable NVIC IRQs from EIC
  • Setup EIC EXTINT4

I am not sure what I am doing wrong in this case, I am also quite confused by the PMUX register and its addressing (tried several combinations already).

// at startup

    // setup the pin as input
    PORT->Group[PORTA].DIRCLR.reg |= PORT_PA20; // input
    PORT->Group[PORTA].OUTSET.reg |= PORT_PA20; // enable the internal pullup
    PORT->Group[PORTA].PINCFG[20].reg = PORT_PINCFG_INEN | // enable input
                                       PORT_PINCFG_PMUXEN | // enable port muxing
                                       PORT_PINCFG_PULLEN;
    PORT->Group[PORTA].PMUX[10].reg |= PORT_PMUX_PMUXE_A;

    // setup a clock generator for EIC
    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |
                        GCLK_CLKCTRL_ID_EIC |
                        GCLK_CLKCTRL_GEN_GCLK0;
    while (GCLK->STATUS.bit.SYNCBUSY);

    // set up NVIC
    NVIC_DisableIRQ(EIC_IRQn);
    NVIC_ClearPendingIRQ(EIC_IRQn);

    NVIC_SetPriority(EIC_IRQn, 0);
    NVIC_EnableIRQ(EIC_IRQn);

    // set up EXTINT
    // Pin Digital 9 = PA20 - connected to EXTINT4
    //EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO10;
    EIC->INTENSET.reg |= EIC_INTENSET_EXTINT4;


    EIC->CONFIG[0].reg |= //EIC_CONFIG_FILTEN0 | // not sure if filtering is needed
                          EIC_CONFIG_SENSE2_LOW_Val;
    EIC->WAKEUP.reg |= EIC_WAKEUP_WAKEUPEN4;

    EIC->CTRL.reg |= EIC_CTRL_ENABLE;
    while (EIC->STATUS.bit.SYNCBUSY);

// static 
volatile bool turnedOff = false;

void EIC_Handler()
{
  Serial.println("got it");
  turnedOff = true;
}

// checking the bool in the main loop

Welcome to the forum.

You could use the functions for configuring pin interrupts provided by Arduino. Here is an example.

/*
  This example shows how to wake up the SAMD21 from sleep with an external interrupt.
  This sketch will break the USB during normal operation.
  Double click the button to enable bootloader mode for a new sketch.

  The circuit:
  - Arduino Nano 33 IoT.

  This example code is in the public domain.
*/

#include "Arduino.h"

#define LED_PIN               LED_BUILTIN
#define WAKE_UP_PIN           (9)


void setup()
{
  pinMode( LED_PIN, OUTPUT );
  pinMode( WAKE_UP_PIN, INPUT_PULLUP );
  attachInterrupt( digitalPinToInterrupt( WAKE_UP_PIN ), wakeUpHandler, LOW );
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
}

void loop()
{
  ledTask();
  sleepTask();
}


void ledTask()
{
#define BLINK_INTERVAL 200

  static uint32_t previousMillis = 0;
  static bool ledState = LOW;

  uint32_t currentMillis = millis();
  if ( currentMillis - previousMillis >= BLINK_INTERVAL )
  {
    previousMillis = currentMillis;
    ledState = !ledState;
    digitalWrite( LED_PIN, ledState );
  }
}


void sleepTask()
{
#define SLEEP_INTERVAL 5000

  static uint32_t previousMillis = 0;

  uint32_t currentMillis = millis();
  if ( currentMillis - previousMillis < SLEEP_INTERVAL )
  {
    return;
  }
	__DSB();
	__WFI();
  previousMillis = millis();
}


void wakeUpHandler()
{

}

The sketch will blink an LED for 5 seconds and then sleep until wake up. For the wake up the level at the pin needs to get LOW and then released again. While LOW is applied to the pin the wakeUpHandler will be called continuously.

1 Like

I tried and this indeed works!

I wonder what is wrong in my approach though? I think I understood the datasheet properly and setup all the registers properly.

For now trying to build my solution around the Arduino wrapper functions with a deepsleep with RTC 32-bit counter.