using an isr to set a boolean vs. just looking at the flag ...

mykle

Well-known member
Hi,

In my code I've got a minimal ISR that sets a volatile boolean. Later in the main loop I test the boolean. Very simple, works great.
But this ISR gets called at 2000hz, and I'm hunting for more cycles, so I am wondering about optimizations.

As I understand it, the mcu is configured so a rising edge on a pin sets an interrupt flag, and then the MCU serves the
interrupt ASAP by calling my ISR, and then clearing the flag.

Is it possible to set up the mcu to raise the interrupt flag on the rising edge but not try to call any ISR?
And then let me test and reset that flag from my main loop?

After all, a flag and a boolean are basically the same thing, so this would avoid the memory access
and whatever overhead is involved in getting into/out of the ISR. I have no idea how many cycles
this would save, but it just seems kind of wasteful to have an ISR that only sets a bool to true.

Or is there some other more normal paradigm for how to detect an interrupt from the main loop?
I assume I can't just use digitalRead(), since the interrupt arrives as a strobe pulse.

Thanks for any tips!
-mykle-
 
When you say 'and then let me test and reset the flag from my code', you are describing the difference between 'interrupt operation' and 'polling operation'. Using the 'interrupt' paradigm, the ISR takes care of updating needed state information 'in the background' so that you can use the information whenever and wherever you need it. However, the cost, as you pointed out, is the need for an ISR. Because real-time modules usually take care to make ISR costs as low as possible, this is generally the right way to go.

OTOH, when using the 'polling' paradigm, the hardware (or in your case, the processor's interrupt flag) is only queried when/if the information is required. The cost of this mode of operation is that any time your program needs to know the hardware state, it has to go ask the processor, and each of these 'polls' may be relatively expensive when compared to a simple boolean compare. If you have enough polling operations, the total time requirements may be larger than the cost of the ISR. There is another huge 'gotcha' w/r/t polling operations though, and that is because you may wind up with polling queries in multiple places in your program, a recipe for problems later on when a part of your code associated with polling is modified in one place, but not all, leading to incorrect/intermittent hard-to-troubleshoot behavior

Hope this helps,

Frank
 
this ISR gets called at 2000hz, and I'm hunting for more cycles, so I am wondering about optimizations.

Frank's explanation is good. Depending on what platform you're using, and what you need to do on each interrupt, you may be able to go much higher than 2000 Hz with interrupts. One easy way to test is with IntervalTimer, so your testing involves only the software, and not an external signal to an I/O pin. You can set the interrupt rate to 2 kHz and go up from there and see what happens. IntervalTimer is a library included with TeensyDuino, and you will find examples to get you started.
 
Is it possible to set up the mcu to raise the interrupt flag on the rising edge but not try to call any ISR?
And then let me test and reset that flag from my main loop?

Yes, this is possible. But you will need to access hardware registers directly to do it, since no Arduino functions are defined for this purpose. The specific register names and details depend on which Teensy model you use, which I didn't see mentioned in your question.

For example, if you are using Teensy 4.0 or 4.1 or MicroMod, I believe you would access the GPIO ISR register, which is documented starting on page 969 in the IMXRT1060 reference manual (rev 3). As you can see on page 970, that same register is used to clear the condition by writing a 1 bit. You would also want to configure the IOMUX registers so GPIO controls that pin, though simply using pinMode(pin, INPUT) might be enough.
 
Yes, this is possible. But you will need to access hardware registers directly to do it, since no Arduino functions are defined for this purpose. The specific register names and details depend on which Teensy model you use, which I didn't see mentioned in your question.

Whoops, no I didn't. I'm using the 3.2 . =)
 
When you say 'and then let me test and reset the flag from my code', you are describing the difference between 'interrupt operation' and 'polling operation'.

I guess my point is: I want to use the polling paradigm. I assume it's cheaper, because I don't need to poll nearly as often as the signal goes high. I just need to know that it went high at least once since the last poll.
But in fact I cannot use polling here, because the PWM signal I'm trying to detect is only high for 5% of the cycle, so polling will only catch it 5% of the time. Whereas MCU interrupt hardware will catch it 100% of the time.
 
I guess my point is: I want to use the polling paradigm. I assume it's cheaper, because I don't need to poll nearly as often as the signal goes high. I just need to know that it went high at least once since the last poll.
But in fact I cannot use polling here, because the PWM signal I'm trying to detect is only high for 5% of the cycle, so polling will only catch it 5% of the time. Whereas MCU interrupt hardware will catch it 100% of the time.

Having a latched reminder to poll against sounds interesting.


Also interrupts can be quickly disabled and enabled. Have the _ISR set the flag and disable itself and exit.

When the code polls the flag it will know it fired and the interrupt is OFF. Then re-enable the interrupt as desired.

Did this once for T_3.6: Monitoring a Serial port from a GPS. Interrupt on the Rx pin changes when it leaves the STOP state bit HIGH>LOW. The _ISR fired, interrupt was disabled to ignore other incoming bit changes, and an incoming GPS message was timestamped and known to be inbound, The interrupt was disabled until the end of the GPS message was processed when it was re-enabled.
Code:
FASTRUN void GPS_serialrx_isr() {
    GPS_RX_time = tsGPS; // Start bit transition detected after 'idle' time
    detachInterrupt(digitalPinToInterrupt(GPS_SRX));
    GPS_newData=1;
}
 
I guess my point is: I want to use the polling paradigm. I assume it's cheaper, because I don't need to poll nearly as often as the signal goes high. I just need to know that it went high at least once since the last poll.
But in fact I cannot use polling here, because the PWM signal I'm trying to detect is only high for 5% of the cycle, so polling will only catch it 5% of the time. Whereas MCU interrupt hardware will catch it 100% of the time.

I'm just wondering what's wrong with the original idea of simply setting a flag in the ISR and polling it in loop? Setting a flag in an ISR that is called at only 2kHz won't make a T3.2 sweat. Defragster's solution is good and saves a few cycles but I guess that doesn't matter much.

You haven't explained what the rest of your application does, but I would not waste too much time on premature optimization.

Quick estimation: IIRC the ISR overhead is in the order of 20 cycles (?). At 96MHz this corresponds to about 200ns overhead. Calling the ISR at 2 kHz would generate about 200ns * 2000 = 400µs overhead per second, i.e., ~0.04% load, which is probably neglectable.
 
On the original question, for Teensy 3.2, I believe you would want the ISF bit in the "PORT" register for whatever pin you're using. Like the similar bit for Teensy 4.x, you write a 1 to clear the bit back to zero. See page 227 in the MK20DX256 reference manual for details.

I do agree 2000 interrupts per second is usually not a big problem. But if you're building a particularly demanding project that pushes the hardware near its limits, or you're creating a library which will be used by many people in a wide range of projects, or you just enjoy learning low-level hardware details or optimizing stuff, going to the trouble to access this hardware register should let you avoid interrupt overhead.
 
I do agree 2000 interrupts per second is usually not a big problem. But if you're building a particularly demanding project that pushes the hardware near its limits, or you're creating a library which will be used by many people in a wide range of projects, or you just enjoy learning low-level hardware details or optimizing stuff, going to the trouble to access this hardware register should let you avoid interrupt overhead.

Yeah, the last two things mostly. =)
I'll try it out and see if I can measure the difference. Thanks!
 
Back
Top