Detaching interrupts

Hi everyone,

I've found a tricky application for which the Arduino platform may be appropriate, but before I proceed I'd like to ask a couple questions I couldn't seem to find clear answers for in my research.

Without going into many details, let's say I'm using some switches to activate interrupts and I want to make certain that my ISRs don't run twice or at inappropriate times. I can't incorporate debounce delays without compromising the tasks performed by my hardware. To solve this, I could detach the interrupt and then reattach it when I need to use it again. Is it possible to detach an interrupt within that same interrupt's ISR? If so, I'm confident I could accomplish what I hope to.

For further control, I'd also like the interrupt to receive its HIGH signal from a digital output pin with a physical switch in between. This would act as a software safety so that an accidental button press won't set off the ["rising"] interrupt unless the digital pin is set HIGH. I see no reason this can't be done, but to be clear I have my circuitry right, I'd wire the DO pin to the interrupt with a switch in between; and a 10k resistor between the interrupt and ground. Is that correct? Or should the resistor be between the DO pin and ground? The difference is whether the circuit is tied to ground before or after the physical switch. I'm not sure which works.

Thanks very much for the help.

I see no reason this can't be done, but to be clear I have my circuitry right, I'd wire the DO pin to the interrupt with a switch in between; and a 10k resistor between the interrupt and ground. Is that correct?

Yes, between the interrupt pin and ground, so as to prevent a 'floating' input condition when the switch is in the open position. Not sure about the detachinterrupt when inside a ISR, but I think it should work. The trick is when do you reattach it such that you won't miss a future interrupt when you need to?

Lefty

a simple flag can do the trick too, some concept code (doesn't run or so)
It doesn't disable IRQ's it just quit them much faster.

volatile boolean disableIRQ =false;

void IRQ()
{
  if (disableIRQ()) return;
  .. your code here

  if (condition) disableIRQ = true;
  ...
}

void loop()
{

   disableIRQ = true;

   disableIRQ = false;
}

Ah, that wiring makes sense. I appreciate the swift replies.

For safety's sake I think it would be best to detach the interrupt so there's no risk of running an ISR when I shouldn't. (robtillaart- would your example provide this kind of protection? I don't fully understand.) And reattaching shouldn't cause and trouble unless the process takes long, but even a few ms wouldn't hurt.

The code I presented allows interrupts to happen, but the first thing the IRQ does is check if the IRQ is allowed by checking the volatile booean disableIRQ. If this flag is set the IRQ will be finished (return statement) so no further code will be executed. It is volatile so the compiler will not optiimize it and every change of it will directly be visible in the IRQ.

When the disableIRQ flag will be set is up to you(r programs logic)

  • can be in the IRQ itself
  • can be in void loop()
  • can be in void setup()
  • can be in another function
  • can be in another IRQ routine.

"disabling" IRQ's this way has an advantage above detachInterrupt shown in code below. This sample IRQ updates counter2 if enabled, and updates counter1 if disabled. The advantage is that you can easily see how often the IRQ is called while disabled. The disadvantage is that the IRQ still will steal CPU cycles while disabled.

volatile unsigned long counter1 = 0;
volatile unsigned long counter2 = 0;
volatile boolean disableIRQ =false;

void IRQ()
{
  if (disableIRQ)
  {
    counter1++;
    return;
  }
  counter2++;
  // rest of the IRQ code
}

I understand it now! That should work just as well for me. Thank you very much.

Another question- I was told that sometimes with microcontrollers, tripping a disabled interrupt will result in the ISR being run as soon as that interrupt is re-enabled because the flag is set when the interrupt is tripped regardless of whether it is enabled. Will I need to clear the flag before re-enabling the interrupt or does the Arduino utility do this automatically?

Good question, Arduino has this problem too, think it will never harm to reset the flag.

Will I need to clear the flag before re-enabling the interrupt or does the Arduino utility do this automatically?

It's your choice really and is application dependent. The 'memory' of a pending interrupt happening while your were detatched can be useful to not miss that event while in the detached mode as it will be 'serviced' when you reattach. However that 'event' memory is only one event long and it doesn't mean you haven't missed multible events while detached. So again it's nice to have the option either way and use it to best fit your application requirements. Interrupts can be tricky and takes some study and experiance to learn all their traps. :wink:

Lefty

Ah, that's unfortunate. How can I reset the flag? I haven't been able to find what code to write.

For Interrupt 0 (pin 2) I found that you can enter this line: EIFR = 0x01. What changes for Interrupt 1?

When bit 0 is set in EIFR and and the I bit is set in SREG, you jump to the isr for external interrupt 0, you can clear this bit by writing a one to it, as you did in that code.

Bit 1 in EiFR has the same functionality for external interrupt 1, so to clear it,

EIFR = 2; or
EIFR = 0x2; hex is easier to convert to bytes, or
EIFR = 1<<1;

all those do the same thing, but you are better off with;

EIFR |= 1<<INTF1; clear external interrupt 1
EIFR |= 1<<INTF0; clear external interrupt 0

Leaves everything else in the register the same (only two bits used in this register anyway).
I think those should work for you, all in the datasheet.

Thanks so much for the help, guys. My project works perfectly now. It now "debounces" by detaching the interrupts, running the important code, clearing the interrupt flags, and then resetting them. I really appreciate it.

Glad it works.

BTW, not trying to be snide about the datasheet comment. Its just when you get to the level of programming these things where you are worried about say, resetting the external interrupt flag, the datasheet has the answers and I have never yet had to wait for it to get back to me. The trick was convincing myself that i could actually understand it, even if it is more than 500 pages long

When bit 0 is set in EIFR and and the I bit is set in SREG, you jump to the isr for external interrupt 0,...

What about EIMSK?

You might want to take a look at the Reference Diagrams for the ATmega External Interrupts at http://web.alfredstate.edu/weimandn. Scroll down to the 'Atmel ATmega Subsystem Diagrams' and click on the Reference Diagrams link.

Don

Well, certainly the correct bit must be set in EIMSK to get your externals firing at all, didn't think that was part of the problem here so I didn't mention it, he had that part going already.