This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Are interrupts re-entrant on TMS320F2812?

I read the interrupt manual and searched this forum, but could not find the answer to the question: are interrupts re-entrant? My system has PWM interrupts (extremely high priority) and UART and timer interrupts (low priority). The behavior I would like, is for the PWM interrupt to be able to interrupt a UART or timer ISR, but I would like the PWM ISR to never be interrupted by anything ever.

That last bit I can achieve by disabling global interrupts while in the PWM ISR, but how about that first bit? Will the PWM interrupt jump to the PWM ISR even if I'm in the middle of one of the other ISRs?

I'm using one of the event manager modules for PWM interrupt, SCIB for RX/TX interrupts, and TIMER2 for timer interrupts.

TIA, -Jon

  • Hi,

    I'm not sure what you are desiring is interrupt reentrancy.  Reentrancy means that when you are in say, the T4CINT (I like to be specific about which interrupts I'm talking about) that if the conditions are again satisfied which cause T4CINT to execute, that you will enter the T4CINT ISR again.  Ie, the T4CINT will interrupt itself!  Yes, the F2812 can do this, but it is normally prevented by the fact that INTM is set when entering an ISR, and for PIE interrupts the PIEACK group bit is also set so even if you reenable interrupts by clearing INTM, the T4xINT PIE group couldn't run.

    Usually, reentrancy is bad, because if your code in the ISR reallows interrupts by clearing INTM, and acknowledges the PIEACK (for PIE multiplexed interrupts) then this reentrancy will likely occur uncontrollably, until the stack overflows.  Basically, ISR reentrancy is a type of recursion.  If your ISR is designed to deal with this correctly, I suppose it is possible to do it without problems.  But it is not typical of ISR codes.

    Rather, what you seem to desire is simply that a higher priority ISR execute when its conditions are satisfied, even though you  may be in another ISR which has caused INTM to be set.  This is not reentrancy, but merely allowing interrupts to preempt while in an ISR. 

    You needn't disable interrupts when your PWM interrupt executes, because interrupts are already disabled during the vector branch.  All you need to do is to clear INTM, ie. reenable interrupts, at the start of the lower priority interrupts, and then the PWM interrupts will always be able to preempt.

    So it's simple:  just reenable interrupts at the start of the low priority ISRs.  Also, understand that the interrupt priorities refered to in the docs are only the CPU core priorities, which determine which ISR executes when multiple interrupt flags are set at the exact same time in the CPU.  This has nothing to do with whether an interrupt which is of high priority according to your application can preempt other less significant ISRs.  You must control this type of priority and the possibility of preemptions in software.

    Note that quite fine grained control is possible.  Before reenabling interrupts in an ISR, you have free reign to tinker with interrupt enable bits, and PIEACK bits, to ensure any desired behavior.  You can also use assembly language to speed up when interrupts get re-enabled.  I do this for ex, in low priority interrupts.  I write an assembly pre-ISR which simply does "clrc INTM" or "eint" and then jumps to the real low-priority ISR.  That way I give the high priority ISR the ability to vector as quickly as possible, in case it occurs while the C preamble code for a lower priority ISR is running.  So this technique reduces interrupt latency for high-priority interrupts.

    It is necessary to do a great deal of tinkering and experimenting with the F2812 to get a handle on how all this works, because it is quite complex.  GPIO pins set up as diagnostic outputs and a scope are your friend.


    Have fun!

  • Wow, thanks for that long & detailed response! You're right, I meant "pre-emption," not "re-entrancy."

  • Crcarle said:

    [edit]

    Note that quite fine grained control is possible.  Before reenabling interrupts in an ISR, you have free reign to tinker with interrupt enable bits, and PIEACK bits, to ensure any desired behavior.  You can also use assembly language to speed up when interrupts get re-enabled.  I do this for ex, in low priority interrupts.  I write an assembly pre-ISR which simply does "clrc INTM" or "eint" and then jumps to the real low-priority ISR.  That way I give the high priority ISR the ability to vector as quickly as possible, in case it occurs while the C preamble code for a lower priority ISR is running.  So this technique reduces interrupt latency for high-priority interrupts.

    More precisely, it is interrupt latency jitter that is reduced by using an assembly pre-ISR.  The way this works is as follows:  Let's say you reenable interrupts in a low-priority ISR, then T4CINT gets flagged.  The T4CINT will now get vectored.  As long as T4CINT occurs after you have already re-enabled interrupts, there is no gain to using an assembly pre-ISR.  Also, the latency to vector T4CINT will be consistent (within the usual pipeline induced jitter bounds of about 4-7 cycles).

    Where things get wierd is when the T4CINT occurs after the low priority interrupt branch, but before you re-enabled interrupts.  Realize that the C compiler inserts "preamble" code in the assembly output that of course you don't know much about from just looking at the C code.  This is something you can look at by getting an assembler listing output and suffering the requisite mental pain of attempting to decipher it.  What you will find is that there is a sequence of instructions added before and after an ISR (and stuff added before and after regular functions as well).  Though, the sequence of stuff is slightly different for ISRs vs. functions (I think; it's been a while since I looked at this, so I could be in err).  The main point is that there are a considerable number of instructions that the compiler places in the code before your code to re-enable interrupts gets a chance to execute. 

    What this means is that you are not getting interrupts re-enabled as quickly as possible if you use a C statement to accomplish this.  Rather, it will happen about 10 instructions past when your low priority ISR is actually vectored, give or take a few.  Now the situation is actually more complicated than just a 10 instruction delay before reenabling interrupts that would be reduced to 1 if you wrote in assembly.  That is the fact that the T4CINT can occur at any time during the preamble code!  So if it occurs just a cycle after the low priority ISR vectors (thereby missing the chance to get scheduled first via the core priority mechanism), then you will experience the maximum wait of the entire preamble code execution time before you can get interrupts reenabled allowing the T4CINT to preempt.  Or, it could occur somewhere in the middle of the preamble code, or just before you reenable, or at the same time, or just after.

    What this leads to is a jitter in the apparent interrupt latency.  The real hardware interrupt latency doesn't actually change, which is the time from when interrupts are enabled and flagged to vector branch.  But there is this unavoidable contention due to other ISRs having preamble codes, which adds a software induced latency of variable and unpredictable length.  This causes your application to experience an effective interrupt latency jitter that is much greater than what would be the result of just the pipeline jitter in a world with no competing interrupts.

    The only way to minimize this added latency jitter is to use an assembly pre-ISR which executes before the C compiler's preamble code.  Here is an example of the simplest case of just re-enabling interrupts, as I use before a CPU Timer 2 ISR in some program:

     

        .ref _Tint2_Isr

    ***********************************************************************
    *
    * Function: _Tint2_Pre_ISR
    *
    ***********************************************************************
        .text

        .def    _Tint2_Pre_ISR
    _Tint2_Pre_ISR:                ; this happens before the main ISR for Timer2
                                ; so this is the Timer2 interrupt vector target
        eint                    ; enable interrupts to make this ISR preemptable
        lb        _Tint2_Isr      ; jump to the Timer2 ISR

    ;end text section

        .end                    ; end of file Timer2-preISR.asm

  • OK, I implemented it as you suggest. Thanks again!