1

Background

I was wondering if using ticker interrupts could interfere with hardware interrupts triggered by a button press.

Example

Imagine I would like to use these two types of interrupts:

  1. a ticker timer to update a progress bar on a small display every n second
  2. a hardware interrupt that starts/stops the process whose progress is displayed if the user presses a button

Important: Both interrupts set shared global volatile flags.

Main question

Would it be possible for the ticker interrupt to occur during a button induced interrupt and as a result for the program to end up in a state where the global flags are set contradictorily?

More specific questions

Does a hardware and a software interrupt have the same 'rank'?

If they occured at the same time, would the interrupt request occurring slightly later (but still overlapping with the first one) be ignored, or just put into a queue and execute straight after the first interrupt has finished? In this case, the flags would be set in an unexpected manner.

Can I disable one type of the interrupts inside the other type's ISR - i.e. ignore it?

I hope the problem statement is clear enough even without a code example.

pfabri
  • 885
  • 1
  • 9
  • 25

1 Answers1

1

I'mm assuming you are using an AVR.

When an interrupt fires, other interrupts are disabled while the interrupt routine is running. So any interrupts that occur in this time simply get flagged. When the interrupt routine returns, the global interrupt flag is re-enabled and any polled interrupts can then fire one at a time.

You can manually enable the global interrupts inside the routine for critical things that must run, but are disabled by default.

EDIT:

Is there a way to disable this flag setting? I don't want the ticker timer to perform an interrupt once the button has been pressed. This is why I asked about ranks and the ability to disable on type of interrupt, if there is such a thing

You can clear the pending interrupt, however you'll have to read the datasheet for your Arduino's AVR. You need to find the register for the external interrupt.

For example, on an atmega328p, external interrupt 0 can be cleared by setting its flag bit to 1:

EIFR |= (1 << INTF2);

EIFR = External Interrupt Flag Register
INTF2 = Bit 0 – INTF0: External Interrupt Flag 0

However, it may be far simpler to poll the button in your loop() function. Or at best, simply set a flag for you to act upon back in the loop() function. There you would be able to decide if you want to react or ignore to the interrupt

There is the issue of having your interrupts far too large. If you use timing, or require accuracy, this could be affected by a large amount over time. As the interrupt queue length is only 1 deep some interrupts could be lost. And the interrupt which powers millis() & micros() runs multiple times per millisecond, so a bulky interrupt could end up slowing down time.

Also do you have any debouncing code or hardware?

If not, the interrupt handling the button could be run multiple times on a single press.

Chris A
  • 1,475
  • 3
  • 18
  • 22
  • Thank you for your answer. Is there a way to disable this flag setting? I don't want the `ticker` timer to perform an interrupt once the button has been pressed. This is why I asked about ranks and the ability to disable on type of interrupt, if there is such a thing... – pfabri Dec 28 '16 at 12:16
  • @pfabri I have edited my answer to look at your question above. – Chris A Dec 28 '16 at 13:03
  • Yes, I do a (tested) software debounce on the button. I understand your suggestion, but even if the button interrupt does nothing else than setting a global flag, if the timer requests an interrupt concurrently, than as soon as the button interrupt exits, the timer interrupt will be pulled from the IR queue and executed, which will in turn rewrite the global flag set by the button interrupt. As a result, `loop()` will think that the interrupt came from the timer. Can't I just use `noInterrupts()` to have timer IRs _ignored_ inside the button interrupt? That's all I'd need. – pfabri Dec 28 '16 at 15:09
  • @pfabri "*As a result, loop() will think that the interrupt came from the timer*" -- I'm talking about a simple `bool` value, this does not need to be touched by the timer ISR. And no, `noInterrupts` will do nothing in the ISR as the global interrupts are already disabled, the interrupts are still flagged as waiting, and will continue after the current ISR returns. "*have timer IRs ignored inside the button interrupt?*" You can use a `volatile bool`, then in button ISR, set true on entry, false on return. Then in the timer ISR, if the bool is true, return and do nothing. – Chris A Dec 28 '16 at 15:20
  • _"You can use a volatile bool, then in button ISR, set true on entry, false on return. Then in the timer ISR, if the bool is true, return and do nothing."_ But doesn't this contradict what you said earlier? If the timer IR waits in a queue until the button IR finishes AND if the the button IR exits by setting the flag _"false on return"_, then by the time the timer IR fires, this flag will always be false. Or am I misunderstanding something completely? Only asking, because this is exactly what I tried earlier, but apparently, the two IRs still interfere this way. – pfabri Dec 28 '16 at 15:41
  • @pfabri Sorry, yes, I was working on the trail of thought that the timer interrupt could be enabled inside the button ISR. The same logic could be applied to my earlier suggestion: Use the button ISR to flag the loop, then in the loop code, you could disable interrupts while checking the button, and enable afterwards. Then the timer ISR will either run before or after the button code, but never in the middle of it. – Chris A Dec 28 '16 at 15:53
  • Sorry to be a pain, but what if I must use an ISR for the button press? Is that a no-go unless I can access the IRS register and reset it? – pfabri Dec 28 '16 at 16:03
  • You can use whichever method you like, as per my suggestion in my last comment, you would be using the ISR to detect the button press, and acting on it elsewhere. I think this is an X/Y problem though. Rather than trying to stop the button ISR from queuing in the timer ISR, change the button code to only do something if it is expected. Is there a difference between the button ISR being queued and run after the timer, compared to the button being pushed after the timer ISR. Either way both scenarios happen after the timer ISR. – Chris A Dec 28 '16 at 16:14