Interrupt modes not working

Hello,

I'm currently working on code for a datalogging device (based on a Zero) that needs to put the sensor to sleep when waiting for data. The hardware is setup for an external interrupt to wake the MCU from a standby sleep mode (from the LowPower library).

The issue I'm having is that I can set the mode in attachInterrupt(digitalPinToInterrupt(pin), ISR, mode); to either LOW or HIGH and it works fine. However, it will not work with RISING, FALLING or CHANGE interrupt states.

Is this a known issue with the Zero?

I think I found an explanation in another post:

"One thing you should note is that the edge event interrupts require a specific clock and that clock is disabled in deep sleep mode. For your wake interrupts you should use HIGH or LOW which will work correctly in deep sleep mode."

I think I've almost got my sketch working, though I believe that I need to now figure out how to set the Zero's registers to turn all the clocks/functionality back on after putting the unit to sleep. If anyone has some tips on that it would be greatly appreciated.

Linked below is an example which configures the EIC to use GCLK1 which is configured to the XOSC32K (external 32kHz oscillator).

GitHub Link

It was written for a variant board (SAMD21J18 based), but it should be fully compatible with the Zero.

The main reconfiguration code is:

   // Set the XOSC32K to run in standby
   SYSCTRL->XOSC32K.bit.RUNSTDBY = 1;
   
   // Configure EIC to use GCLK1 which uses XOSC32K 
   // This has to be done after the first call to attachInterrupt()
   GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(GCM_EIC) | 
                       GCLK_CLKCTRL_GEN_GCLK1 | 
                       GCLK_CLKCTRL_CLKEN;

Note: You must first make at least one call to attachInterrupt() before running the above code. This is because the interrupt handling code in the Arduino core configures the EIC clocks during that first call.

1 Like

THAT DID IT! I've been fighting this for a while and had been setting a 48Mhz clock before attaching the interrupt so it was high power AND would constantly hang after a couple cycles!

How did you figure out what the structures were that you could use to set this up? I've looked through the datasheet and there are some registers I'd like to set. However, I've read through the lowpower.h/.cpp library that I am using and the samd_core.h files but I don't see these structures being defined or linked to the registers on the SAMD core.

The register definitions can be found in the CMSIS folder.

It is installed in ../Arduino15/packages/arduino/tools/CMSIS/4.0.0-atmel/Device\ATMEL/samd21/include/ you will find definitions headers in both the component and instance subdirectories.

On the Windows platform the above folder is located under C:/Users//AppData/Local/.

There is a certain pattern and naming scheme that is pretty consistent.

I got something similar working by attaching the EIC to the same clock setup for the RTC by the RTCZero library.

I did something like:

#include <RTCZero.h>
RTCZero rtc;
void setup() {
    pinMode(D3, INPUT_PULLDOWN);
    attachInterrupt(D3, d3Callback, CHANGE);
    EIC->CONFIG[1].bit.FILTEN1 = 1; // D3=eic9
    EIC->WAKEUP.vec.WAKEUPEN = (1<<9);
    rtc.begin();
    rtc.setTime(0, 0, 0);
    rtc.setDate(0, 0, 0);
    rtc.attachInterrupt(rtcCallback)
    rtc.setAlarmSeconds(0);
    rtc.enableAlarm(MATCH_SS);
    // The RTCZero library will setup generic clock 2 to XOSC32K/32
    // and we'll use that for the EIC.
    GCLK->CLKCTRL.reg = uint16_t(
        GCLK_CLKCTRL_CLKEN |
        GCLK_CLKCTRL_GEN_GCLK2 |
        GCLK_CLKCTRL_ID( GCLK_CLKCTRL_ID_EIC_Val )
    );
    while (GCLK->STATUS.bit.SYNCBUSY) {}
}

OK, that's essentially what GabrielNotman did too :slight_smile:

Dear All

I do not know if you still follow that topics but it look like it can help me to solve my similar problem.
I can not understand your explication may be because some missing knowledge.

I am actually puting in sleep mode my microcontroller with RTCZero library.
My module work as the following:
Each hour my Ardafruit Feather MO take the measure of 8 sensors. Whe it's done, it send the data and goes to sleep for about 59mn.

With RTCZero, my borad sleep 10 second, flash a led and sleep 10 second, flasha led and so on until the next measure.

There is a rain gauge which count the drops falling in the gauge. The microcontroller must be able to count even when it's in sleep mode.
For this reason, I setup an external interrupt (on A4) to wake up the microcontroller. The ISR function will incremen a variable. That variable will be use to know the number of drops within 1 hour.

The bunket of the rain gauge is LOW because of a pull down resistance. When the bunket move to the other side, it goes HIGH when is goes close to the magnetix sensor, and then the signal goes LOW when the bunket is in the other side (position).

Then A4 goes HIGH as long as the bunket is close to the magnetic sensor of the rain gauage.

Then, each time A4 is HIGH, the variable increment.

My system work very fine with RISING or CHANGE or FALLING but not with HIGH because the HIGH ststus can be HIGH fore some millis second. The the ISR is called 2-3 time.Then my variable is not incrementing of 1, but 3 or 4.

Regarding your topics, I have not understand if that solution allow RTCZero to wake up with RISING mode, instead of HIGH or LOW? That would be great but I did not understand how I could modify my code.

I also would like to try this solution but as it's not clear for me, I do not know how I can modify my code.

I configured my RTCZero library as the following:

const unsigned TX_INTERVAL = 60;      // 1mn

const int pin_arrosage = A4;

  #include <RTCZero.h>
  /* Create an rtc object */
  RTCZero sleep;
  
  const byte alarmSeconds = 10;
  const byte alarmMinutes = 0;
  const byte alarmHours = 0;

void setup(){
  sw.pinMode(wakeup_led, OUTPUT);
  sw.digitalWrite(wakeup_led,HIGH);

    pinMode(pin_arrosage, INPUT_PULLUP);
    //digitalWrite(pin_arrosage, LOW);
    //attachInterrupt(digitalPinToInterrupt(pin_arrosage), triggeredDropArrosage, CHANGE);
    attachInterrupt(digitalPinToInterrupt(pin_arrosage), triggeredDropArrosage, HIGH);

    sleep.begin();
    delay(100);
    rtczero_resetAlarm()
}


void loop(){
   // Take the measures
   // measures(); 
   // When the measures , it goes to sleep mode for 1mn (for the test, it sleep 1mn, but it will sleep for 59mn.)
   
   for (int i=0; i<int(TX_INTERVAL/10); i++) {
      sw.digitalWrite(wakeup_led,LOW);
      rtczero_resetAlarm();
      sleep.standbyMode(); // Sleep until next alarm match
      
      sw.digitalWrite(wakeup_led,HIGH);
      delay(100);
      sw.digitalWrite(wakeup_led,LOW);
    }

}

void rtczero_resetAlarm(){
    //https://github.com/ProjectsByJRP/M0_Sleep_Wake_on_RTC_int/blob/master/Sleep_wake_on_RTC_alarm.ino

    // Variable to set a reference in the time.
    byte seconds = 0;
    byte minutes = 0;
    byte hours = 0;
    byte day = 1;
    byte month = 1;
    byte year = 1;
    // Set time reference
    sleep.setTime(hours, minutes, seconds);
    sleep.setDate(day, month, year);

    // set alarm (wake up RTCZero)
    sleep.setAlarmTime(alarmHours, alarmMinutes, alarmSeconds); //  By default we set at 10 sec, 0 mn, 0 hours
    sleep.enableAlarm(sleep.MATCH_HHMMSS);
}

void triggeredDropArrosage()
{
  // Wait until  pin_arrosage is LOW
  do{
  }while(digitalRead(pin_arrosage)==HIGH);
  vcountDrops=vcountDrops+1;
  led_state = !led_state;

}

I am really confuse with this kind of code

EIC->CONFIG[1].bit.FILTEN1 = 1; // D3=eic9
    EIC->WAKEUP.vec.WAKEUPEN = (1<<9);

...
 GCLK->CLKCTRL.reg = uint16_t(
        GCLK_CLKCTRL_CLKEN |
        GCLK_CLKCTRL_GEN_GCLK2 |
        GCLK_CLKCTRL_ID( GCLK_CLKCTRL_ID_EIC_Val )
    );
    while (GCLK->STATUS.bit.SYNCBUSY) {}

because I absolutly do not understand it. As I underatnd, the first two line,change the behaviour of RTCZero?

Then how can I modify my code, to have my board sleep 10 second, flashing a led, sleeping 1o sec,flashing a led, until next the measures, and when it raining, it count the drop at any time, even during the sleep mode.

Many thank for your help

Hello All,

How do I get SERCOM interrupts working?

I've been trying to wake the Zero up from sleep through a Serial input.