I am using an ISR, which is written to be as minimal as possible:
volatile bool interrupt1{};
void ISR1() {
interrupt1 = true;
}
The interrupt is handled by polling the interrupt1 variable in loop()
:
if (interrupt1 == true) {
// Do stuff
interrupt1 = false;
}
Even though the interrupt signal coming in on the gpio isn't polled, the method described above is instead polling the interrupt variable from loop()
.
As an alternative to the above, is it possible to use some kind of push logic on the software side whenever an interrupt occurs, instead of continuously polling the interrupt variable? I hesitate to handle the full task from the ISR, as it's performing a lot of things.
What are my options here?
2 Answers 2
If the task is pretty short and time sensitive, your best option is to put it in the interrupt handler.
If the task is big and not too urgent (like: it could well wait for a
millisecond or so), your approach of polling the flag within loop()
is
the best one, provided the main program is non-blocking.
If the task is both big and urgent... you may have a difficult problem. You could try both approaches and see which one works best. Or you may try to split the task into a top half (short and urgent) and a bottom half (long but not so urgent). The interrupt handler would then perform the top half and set a flag, whereas the main loop would poll the flag and perform the bottom half.
Edit: for a short discussion on the top half / bottom half approach, see the first paragraphs of this article on Linux kernel development.
-
1Thanks for your reply. Last portion is particularly interesting. I might be able to refactor the responsibilities for a better tradeoff between timing and heavy lifting, so to speak...Erik– Erik2023年11月27日 11:54:12 +00:00Commented Nov 27, 2023 at 11:54
-
2It can be tricky to think about what part of a task is "urgent". The ISR handler should take care of anything that will go wrong if you wait (like anything that's necessary to prepare the hardware for another event, if it arrives before you've finished with this one.)Glenn Willen– Glenn Willen2023年11月28日 04:16:55 +00:00Commented Nov 28, 2023 at 4:16
Since you tagged it Teensy: You could also reduce the priority of the interrupt, so that it can be interrupted by higher priority interrupts. Thus you can implement interrupts with longer durations without blocking important system functions.
Here is an example using the GPT1 and GPT2 timers running at different priorities:
#include "Arduino.h"
#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;
PeriodicTimer loPrioTimer(GPT1);
PeriodicTimer hiPrioTimer(GPT2);
void onLowPrioTimer() // some long task running from interrupt with low prio
{
Serial.printf(" Start low prio isr @t=%d ms\n", millis());
for (int i = 0; i < 10; i++)
{
Serial.printf(" lowPriority task %d\n",i);
delay(10);
}
Serial.println(" Stop low prio isr");
}
void onHiPrioTimer() // high prio, will interrupt the low prio isr
{
Serial.printf("high priority @t=%d ms\n", millis());
}
void setup()
{
while (!Serial) {}
loPrioTimer.begin(onLowPrioTimer, 500ms); // GPT1
hiPrioTimer.begin(onHiPrioTimer, 50ms); // GPT2
NVIC_SET_PRIORITY(IRQ_GPT1, 128); // lowest prio
NVIC_SET_PRIORITY(IRQ_GPT2, 16); // high prio
}
void loop()
{
}
which prints:
high priority @t=1057 ms
high priority @t=1107 ms
high priority @t=1157 ms
high priority @t=1207 ms
high priority @t=1257 ms
high priority @t=1307 ms
high priority @t=1357 ms
high priority @t=1407 ms
high priority @t=1457 ms
high priority @t=1507 ms
Start low prio isr @t=1507 ms
lowPriority task 0
lowPriority task 1
lowPriority task 2
lowPriority task 3
lowPriority task 4
high priority @t=1557 ms
lowPriority task 5
lowPriority task 6
lowPriority task 7
lowPriority task 8
lowPriority task 9
high priority @t=1607 ms
Stop low prio isr
high priority @t=1657 ms
high priority @t=1707 ms
high priority @t=1757 ms
high priority @t=1807 ms
high priority @t=1857 ms
high priority @t=1907 ms
high priority @t=1957 ms
high priority @t=2007 ms
Start low prio isr @t=2007 ms
lowPriority task 0
lowPriority task 1
lowPriority task 2
lowPriority task 3
lowPriority task 4
high priority @t=2057 ms
lowPriority task 5
lowPriority task 6
lowPriority task 7
lowPriority task 8
lowPriority task 9
high priority @t=2107 ms
Stop low prio isr
high priority @t=2157 ms
high priority @t=2207 ms
high priority @t=2257 ms
high priority @t=2307 ms
This shows that the high priority timer (running at 50 ms interval) intercepts the low priority ISR which runs every 500 ms for about 100 ms.
-
Thanks for your reply. I've never used interrupt priority. Wanna elaborate?Erik– Erik2023年11月27日 12:21:17 +00:00Commented Nov 27, 2023 at 12:21
-
1
-
What if an interrupt of the same kind occurs? For example, if it was counting something, wouldn't it miss a count increment (it presumably isn't a reentrant ISR)?Peter Mortensen– Peter Mortensen2023年11月27日 21:20:00 +00:00Commented Nov 27, 2023 at 21:20
-
What baud rate was used for 'Serial'?Peter Mortensen– Peter Mortensen2023年11月27日 21:22:04 +00:00Commented Nov 27, 2023 at 21:22
-
If an interrupt of the same kind occurs while the first one is serviced it will set the interrupt flag again and the isr will be called again (unless you delete the flag at the end of the ISR). However, this can not handle more than one interrupt request while an isr runs. Here some information about the ARM Nested Interrupt System: microcontrollerslab.com/…luni64– luni642023年11月28日 09:17:35 +00:00Commented Nov 28, 2023 at 9:17
if (interrupt1 == true)
thetrue
is redundant ... useif (interrupt1)
insteadvolatile bool interrupt1{};
- what are the braces for?