Kernel interrupts priority - Cortex M4F port

Hello,

In my application there’s two high priority interrupts fired periodically by an AD conversion. Inside those interrupts subroutines some data are acquired and send to a task through a queue (xQueueSendFromISR). Using an IO pin to analize the execution time of those subroutines I detected that sometimes the period (that usually takes 20us to execute) jumps to something close to 200us.

The configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY flag is defined to 2 and the AD conversion interrupt priority is set to 4 (lower priority, matching the documentation requirements when using FreeRTOS calls inside interruptions).

I think that the reason why the ISR routine is taking longer time to execute is because some higher priority interrupt is taking the processor. But since all my interrupts are set to lower priority values, maybe is some kernel interrupt that is executing.

So my question is: is there any kernel interrupt with a priority higher than configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY?
If yes, is it normal to take so long to run (about 150us)?

Additional info:
Microcontroller - MK64F - Cortex M4f running at 120Mhz
FreeRTOS Kernel V10.3.0 - Port from NXP MCUXpresso

Thanks in advance!

No. In the official ports, the kernel interrupts occur only at one priority, set by configKERNEL_INTERRUPT_PRIORITY. You might want to double check the value of that symbol. It must be set to the lowest interrupt priority.

For perspective, there are two ongoing kernel interrupts - PendSV and Systick. A third interrupt, SVC, is used just once to start the the first task.

Thanks for your reply Jeff!

Here’s some defines related to interrupts:

#define configPRIO_BITS __NVIC_PRIO_BITS //Macro expands to 4 bits 
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1U << (configPRIO_BITS)) - 1)
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))

As I can understand (correct me if I’m wrong) the priority of the kernel interrupt is set to the lowest level (15), so I assume that’s not the problem.
I get a little confused about the fact that some macros are bit shifted and some aren’t. Shouldn’t all of them be bit shifted since the configuration bits are stored on the 4 most significant bits?

Another question, for what purpose are priority levels above configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY used?

Some of these symbols are shifted and some unshifted, by design. The unshifted ones are useful for the human reader, while the shifted ones are useful for the machine.

Priority levels above configMAX_SYSCALL_INTERRUPT_PRIORITY are useful for minimizing interrupt latency. In some cases you can even achieve near-perfect consistency in the interrupt latency. That’s because interrupts at those high priorities can also interrupt FreeRTOS critical sections. They can do so safely because they don’t interact with FreeRTOS.

Thanks for the explanation!

I understand that for the user interrupts these levels can be used to run critical code that don’t use any FreeRTOS API. These FreeRTOS critical sessions you mention run on high priority level interrupts, right? If yes, is it possible that they’re preempting my lower priority interrupts?

Yes, the critical sections can delay your ISRs. 150us+ sounds high to me, especially with a CPU clock at 120MHz. I think something else is going on.

They can DELAY, but not INTERRUPT. My understanding is that the OP has instrumented the ISR with basically raising a GPIO flag at the beginning and dropping it at the end.
That should only be possible by a Higher Priority Interrupt, or maybe some DMA transfer that blocks the CPU (but that time seems very high).

One other possibility is that the code has different paths through it or loops testing something that changes.

Good catch Richard, I think you’re right. In that case, the OP could start the ISR with __disable_irq() and end it with __enable_irq() as a temporary diagnostic.

If the problem goes away, then there is a higher priority interrupt in play.

If the problem remains, there is code occasionally taking longer than expected inside the ISR.

Thanks @jefftenney and @richard-damon for the tips. Sorry for the late reply, I put this problem aside for a while and couldn’t test your suggestions.

Right, I think that they are delaying my ISR by executing some other code elsewhere, but not really sure about it.

Yes, I’m rising a GPIO on the start of the ISR and dropping it at the end, so on most of executions it runs normally, taking just a few us. The code has one different path but since it runs periodically I’m able to identify it’s execution time on the scope, taking just a few us more than the normal path. The 150us delay on other hand seems to happen randomly. I think it’s code runs periodically but it’s randomly called inside my ISR.

Could this cause some RTOS instability since I’m using xQueueSendFromISR function inside the ISR?

Hi Yago,

could it be that your eco system implements ISRs bypassing the OS? If you had an ST MCU, my first question would be whether you use the HAL (which has the real bad habit of trying to set up an IRQ driven timer ISR for HAL timeouts). I don’t know if NXP does something similar, but maybe it’s worth investigating your IVT and NVIC registers to see if some part of your runtime system puts a high pri ISR above max syscall there. I wouldn’ t do this statically as some code may relocate the IVT to RAM and squeeze some entries in there at startup time.

Just a thought!

No, this experiment won’t impact FreeRTOS at all. The __disable_irq() and __enable_irq() calls manipulate PRIMASK, whereas FreeRTOS for M4F manipulates BASEPRI.