AttachInterrupt and disable on a SAMD21 not possible

Hi,

I would like to use a light barrier to trigger a camera. It should trigger the camera as long as the light beam is broken (HIGH-signal) and it should be possible to shot additional images after the last trigger signal from the light barrier.

The whole system needs to sleep if nothing happes and I'm using the LowPower.h-library.

#define TRIGGER_A_PIN 1     // PA10, 15 an IC

volatile boolean trigger_a_int = false;

//My idea was to do in setup()
void setup()
{
Serial.begin(9600);
pinMode(TRIGGER_A_PIN, INPUT); //pulled low by resistor
attachInterrupt(TRIGGER_A_PIN, trigger_a_int_func, HIGH);
}

void loop() {
trigger_funct();  //calls the function to later be able to shoot additional images
}

//interrupt routine:
void trigger_a_int_func()  {
detachInterrupt(TRIGGER_A_PIN);
trigger_a_int = true;
trigger_funct(); // call the camera function immediatly for taking a picture
}

//trigger the camera:
void trigger_funct() {
if (trigger_a_int)  {
//Trigger the camera program
Serial.println("Trigger");
trigger_a_int = false;
attachInterrupt(TRIGGER_A_PIN, trigger_a_int_func, HIGH);
}
}

Why isn't this working? It fires the interrupt only once

Your interrupt service routine unnecessarily detaches from the interrupt and never attaches again.

By the way, it is a bad idea to post code snippets here. Read some of the locked topics at the top of this forum to learn the proper way to post.

In many cases, the compiler is free to change the order of execution. If you do not want that to happen, there are ways to deal with it.

Variables that are accessed from the main program and from an interrupt service routine should be declared volatile. Is yours?

HI, why is it unnecessarily? When not detaching it fires constantly and didnt execute the rest. Yes there volatile. It wasn't supposed to be code snippes. I just stripped everything als in my current test program to figure out how to deal with attaching and re-attaching the interrupt.

How would you solve that if you says that's unnecessarily to detach the ISR?

timtailors:
I just stripped everything als in my current test program to figure out how to deal with attaching and re-attaching the interrupt.

For most effect help, always post a complete program that actually compiles, not just snippets where you think the problem is. After all, if you really knew what the problem was, you wouldn’t need to post a question. You’d just fix it.

When not detaching it fires constantly and didnt execute the rest.

This:

attachInterrupt(TRIGGER_A_PIN, trigger_a_int_func, HIGH);

I suspect that the interrupt is doing exactly what you are telling it to do. It’s firing as long as the pin is HIGH. Perhaps you want to consider using RISING, FALLING, or CHANGE.

HI, I edited my current test program which I'm using right now.

"I suspect that the interrupt is doing exactly what you are telling it to do"

Yes exactly, that's why I detached it after the first execution. I first tried RISING but learned that it's not possible with a SAMD21 chip

timtailors:
I first tried RISING but learned that it’s not possible with a SAMD21 chip

Baloney, right from the data sheet:

Oh you're right! That's working. I really tried it, was the first idea I had but then it didnt work and I read that it's not possible with the SAMD21

Ok, It didn't work as expected with the "LowPower.h" library. With that in use only HIGH wakes the chip up. With RISING nothing happens

You haven't posted any code that includes use of the LowPower.h library.

Now that you mention it, I think I recall that edge triggering requires certain clock(s) to be enabled. You can set them to be enabled during sleep. See the SMAD21 datasheet.

Post full code of your attempts (BOTH edge and level triggering) that include the LowPower.h library.

That was my attempt including the LowPower lib

Ok but will the power consumption increase when enabling additional clocks? If so then it would be maybe better so solve the first attemp with HIGH and getting the interrupt attached again?

RISING:

#include "LowPower.h"

#define TRIGGER_A_PIN 1     // PA10, 15 an IC

volatile boolean trigger_a_int = false;


void setup()
{
  Serial.begin(9600);
  pinMode(TRIGGER_A_PIN, INPUT); //pulled low by resistor
  attachInterrupt(TRIGGER_A_PIN, trigger_a_int_func, RISING);
}

void loop() {
  trigger_funct();
}


void trigger_a_int_func()  {
  trigger_a_int = true;
  trigger_funct();
}

//trigger the camera:
void trigger_funct() {
  if (trigger_a_int)  {
    //Trigger the camera program
    Serial.println("Trigger");
    trigger_a_int = false;
    LowPower.standby();
  }
}

HIGH:

#include "LowPower.h"

#define TRIGGER_A_PIN 1     // PA10, 15 an IC

volatile boolean trigger_a_int = false;


void setup()
{
  Serial.begin(9600);
  pinMode(TRIGGER_A_PIN, INPUT); //pulled low by resistor
  attachInterrupt(TRIGGER_A_PIN, trigger_a_int_func, HIGH);
}

void loop() {
  trigger_funct();
}


void trigger_a_int_func()  {
  trigger_a_int = true;
  trigger_funct();
}

//trigger the camera:
void trigger_funct() {
  if (trigger_a_int)  {
    //Trigger the camera program
    Serial.println("Trigger");
    trigger_a_int = false;
    LowPower.standby();
  }
}

There seems to be multiple Low Power libraries out there, all conveniently using the header file "LowPower.h". Which one are you using? BTW, This One is specifically for SAMD boards.

I’m using this one GitHub - rocketscream/Low-Power: Low Power Library for Arduino

I also tried to one which you mentioned. Also got confused first but the one is called
LowPower.h and the other “ArduinoLowPower.h”

I’m using also the latest SAMD core as this is also mentioned in the first lib’s description.

So, I couldn’t come up with a bullet-proof way of combining level-sensitive interrupts and sleep mode. I needed to disable the interrupt in the ISR to prevent the processor from being slammed as the input continued to cause continuous interrupts. But, then re-enabling the interrupt before sleeping is tricky because an interrupt right before sleeping would disable further ones again and the processor would never wake up.

So, I went with edge-triggered interrupts and the ArduinoLowPower library. Check out the ExternalWakeup example that comes with that library as a good starting point. I ended up modifying that example because contact bounce was causing spurious interrupts and incrementing of the ‘repetitions’ variable… Code below was tested on an Adafruit Feather M0 – the only SAMD21 board I have.

#include "Arduino.h"
#include "ArduinoLowPower.h"

void repetitionsIncrease();

uint32_t repetitions = 1;
const uint8_t pin = 5;

void setup() {
 pinMode(LED_BUILTIN, OUTPUT);
 pinMode(pin, INPUT);
 LowPower.attachInterruptWakeup(pin, repetitionsIncrease, FALLING);
}

void loop() {
 for (uint32_t i = 0; i < repetitions; i++) {
 digitalWrite(LED_BUILTIN, HIGH);
 delay(500);
 digitalWrite(LED_BUILTIN, LOW);
 delay(500);
 }
 LowPower.sleep();
 repetitions++;
}

void repetitionsIncrease() {
}

If you're going to use sleep, you MUST use a level-sensitive interrupt to wake up. Once awake, you can then switch to edge-sensitive interrupts to do whatever it is you need to do when awake. When you then go back to sleep, switch back to level-sensitive interrupts. Edge-sensing REQUIRES a clock which WILL increase power consumption.

Regards, Ray L.

The ArduinoLowPower library in fact enables the clock necessary to allow edge-triggered interrupts during sleep. It uses the 32KHz clock for this purpose. You'd need that clock active anyway if you want to do a wake-on-RTC type sleep. So, yes it will increase power dissipation. But, I think the 32KHz clock is fairly low power.

In the end it's an engineering tradeoff. You can use other techniques, but to assert that you "MUST" use level-triggered interrupts is a fallacy.