Teensy 4.1 IntervalTimer Interrupt

Status
Not open for further replies.

Neal

Well-known member
My question: Once an interrupt is setup using the IntervalTimer class in the teensy core, when does the actual interrupt get reenabled. In my application it looks like the interrupt routine isn't reenabled until after the previous ISR completes. But when I look at the IntervalTimer class code, it looks to me like it should be reenabled as soon as the ISR is called.

I put together a simple example to test this:

#include <Arduino.h>
#include <IntervalTimer.h>

IntervalTimer updateTimer;

void myisr()
{
digitalWriteFast(6, HIGH);
digitalWriteFast(6, LOW);

delayMicroseconds(2000);
}

void setup()
{
pinMode(6, OUTPUT);
updateTimer.begin(myisr, 1000);
}

void loop()
{
}

I expected this to crash because I thought the the 2000 usec delay would cause myisr to be recalled every 1000 usec. Instead myisr executed once every 2000 usec.

Here is the part of the IntervallTimer class code where the actual timer isr code resides:

static void pit_isr()
{
IMXRT_PIT_CHANNEL_t *channel= IMXRT_PIT_CHANNELS;
if (funct_table[0] != nullptr && channel->TFLG) {channel->TFLG = 1;funct_table[0]();}
channel++;
if (funct_table[1] != nullptr && channel->TFLG) {channel->TFLG = 1;funct_table[1]();}
channel++;
if (funct_table[2] != nullptr && channel->TFLG) {channel->TFLG = 1;funct_table[2]();}
channel++;
if (funct_table[3] != nullptr && channel->TFLG) {channel->TFLG = 1;funct_table[3]();}
}

Because the TFLG flag is set to 1 before the call to the funct_table[0]() (this is myisr()), I thought the isr should be recalled before the 2000 usec delay is complete. Instead the pin high/low displayed on my scope shows that myisr is held off until the 2000 usec is passed.

So back to my original question-When does the actual isr get reenabled?
 
The interrupt for the timer is turned off until the ISR returns. The delay stops the ISR from returning.
An ISR should always be written to be as fast as reasonably possible. Putting a delay in an ISR is not reasonable.

Pete
 
Also good to know:

Interrupts can have the same or different priority levels on the ARM Teensy's. In groups of 16 between 0 and 255, with 0-15 being the highest level - and most defaulting to 128 (IIRC T_LC has fewer levels?).

Interrupts of the same or lower priority will not interrupt a current interrupt, but will be queued until the current one exits - and loop() basically runs at level 256 (IIRC a Paul post) - so any active interrupt halts the execution of loop().

A higher level interrupt will execute by interrupting a lower level interrupt.

So as Pete notes - all time spent in an interrupt should be minimized as it halts execution of any code at the same or lower priority level.

@luni - is there a note to this effect in Teensy Wiki?
 
Thanks for the responses. I realize that the interrupt code in a real application should be as short as possible. My example was constructed to help understand the timer interrupt process.

Also, I understand that a same/lower priority interrupt will be queued if a same/higher priority interrupt is being serviced. But I thought that setting TFLG = 1 (like is done in the IntervalTimer code snippet I included above) tells the uP enables another interrupt. Otherwise how would the uP know that the isr is finished?
 
tells the uP enables another interrupt.

That only affects the flag within the peripheral. It has no effect on the ARM processor. It only changes the signal the peripheral is able to send to the processor.


Otherwise how would the uP know that the isr is finished?

When the ARM processor runs your interrupt, it pushes several 32 bit words onto the stack in RAM. Most of them store the contents of registers. Two of those words are the program counter and a special code to indicate the end of an interrupt. For ARM chips, interrupt functions are written the same as normal C (and C++ static) functions. When that special number is restored, the ARM processor "knows" you are returning from an interrupt rather than just a normal function return. It restores the registers it has pushed onto the stack and updated the interrupt controller's state, taking interrupt priority into account. The hardware also does a nifty "tail chaining" optimization where it detects if another (same or lower) priority interrupt is about to run, where it just leaves most the prior stuff on the stack (rather than restore it only to have to save it all over again) and jumps directly to the next interrupt function.

The way it knows is that special code which gets pushed onto the stack and restored to the program counter when your interrupt function returns.
 
I see. Also neat the way tail chaining minimizes the pushing/popping time. Nice stuff.

Is there a document that describes the interrupt in more detail than the Document Number: IMXRT1060RM Rev. 2, 12/2019?
 
Status
Not open for further replies.
Back
Top