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.