What is config KERNEL INTERRUPT PRIORITY?

The explanation on freeRTOS web is:
“configKERNEL_INTERRUPT_PRIORITY sets the interrupt priority used by the RTOS kernel itself. Interrupts that call API functions must also execute at this priority. Interrupts that do not call API functions can execute at higher priorities and therefore never have their execution delayed by the RTOS kernel activity (within the limits of the hardware itself)”

I don’t understand what is meant by “interrupt priority used by the RTOS kernel”. Does kernel use or generate any interrupt?

The Kernel often will use a software generated interrupt to do the task switch operation (This code will be in port specific section of code. It also uses a Timer Interrupt to provide basic timing services.

Dear Richard-Damon,

Thanks for reply

  1. AFAIK, the software interrupt which is used to trigger context switching, should be of the lowest priority. This is because task should only run when there is no other ISR running, and it is not good to perform context switching while another ISR is still running
    Is this correct?

  2. If configKERNEL_INTERRUPT_PRIORITY is set to, for example, 0, does that mean all kernel interrupts which you mentioned (software interrupt, timer interrupt) will be at 0?

  3. If the answer to 2. is yes, then next question is: If 0 is the lowest priority, setting software interrupt to priority 0 makes sense (as my understanding in 1.). But making Timer Interrupt (Tick Interrupt) at priority 0 seems not logically to me; because the counter of the time base has to increment by 1 when it needs to - any delay will render the timer tick inaccurate
    Is this correct?

Which port are you using? My answers assume a Cortex-M, but the answers will be different if that is not the case.

Where did this text come from as I think it is subtly wrong for the general case, which may be because it is out of date or it may be because you are not using a Cortex-M but something like a PIC24. In the Cortex-M case interrupts that cause a context switch have to run at or below configMAX_SYSCALL_INTERRUPT priority, nothing to do with configKERNEL_INTERRUPT_PRIORITY.

Tasks can only run when there is no ISR running - that is a hardware thing, FreeRTOS, as software, can’t change that.

Again, specific to the Cortex-M, configKERNEL_INTERRUPT_PRIORITY should be the lowest priority because it sets the priority of the interrupt that performs the context switch. In a system in which interrupts nest you want the entire nesting of interrupts to unwind before performing a context switch - rather than allowing each interrupt in the potentially nested stack of interrupts perform context switches.

In the Cortex-M there are only two interrupts used by the kernel - SysTick and PendSV - and both are set to configKERNEL_INTERRUPT_PRIORITY. However, again you answer makes me suspicious you are not using a Cortex-M as if you were 0 would be the highest priority, not the lowest, and you cannot set configKERNEL_INTERRUPT_PRIORITY to 0.

It is not such a strict requirement to make the tick interrupt the lowest priority, but it is best to do so so the tick count changing doesn’t change the logic path half way through an ISR, and to ensure interrupts that may be higher priority are not delayed (the RTOS doesn’t know what the application is doing, so application interrupts may be more important). It would only start to become an issue with timing if interrupts were disabled for more than one entire tick period - so two ticks were missed as the processor can only hold one pending. If interrupts are disabled for that length of time then I suspect there will other issues in the application design anyway.

Dear Richard,

Which port are you using?

I am using RX600 port. Interrupt priority 0 is of lowest priority

Where did this text come from as I think it is subtly wrong for the general case, which may be because it is out of date or it may be because you are not using a Cortex-M but something like a PIC24.

I apologise for taking information out of context. The complete explanation on freertos.org is:
"For ports that only implement configKERNEL_INTERRUPT_PRIORITY
configKERNEL_INTERRUPT_PRIORITY sets the interrupt priority used by the RTOS kernel itself. Interrupts that call API functions must also execute at this priority. Interrupts that do not call API functions can execute at higher priorities and therefore never have their execution delayed by the RTOS kernel activity (within the limits of the hardware itself).

For ports that implement both configKERNEL_INTERRUPT_PRIORITY and configMAX_SYSCALL_INTERRUPT_PRIORITY:
configKERNEL_INTERRUPT_PRIORITY sets the interrupt priority used by the RTOS kernel itself. configMAX_SYSCALL_INTERRUPT_PRIORITY sets the highest interrupt priority from which interrupt safe FreeRTOS API functions can be called."

And I understand your explanation. Thank you

Still a bit unclear about the statement below in italic. I understand that:
i) If a port implements only configKERNEL_INTERRUPT_PRIORITY, then in a critical section, all interrupts will be blocked
ii) If a port implements both configMAX_SYSCALL_INTERRUPT_PRIORITY and configKERNEL_INTERRUPT_PRIORITY, then in a critical section, only interrupts which has the priority in between these two priorities, will be blocked

But in:
"For ports that only implement configKERNEL_INTERRUPT_PRIORITY
configKERNEL_INTERRUPT_PRIORITY sets the interrupt priority used by the RTOS kernel itself. Interrupts that call API functions must also execute at this priority. Interrupts that do not call API functions can execute at higher priorities and therefore never have their execution delayed by the RTOS kernel activity (within the limits of the hardware itself)."

  • Why is it that “Interrupts that call API functions must also execute at this priority”? Is there an example? What is the treatment different between interrupts which call, and don’t call
    , API functions?

I think this is because ports that only implement one of those constants tend to be on much simpler processors that don’t have many priority levels. It is not relevant to the RX port you are using though.

Why is it that “Interrupts that call API functions must also execute at this priority”? Is there an example? What is the treatment different between interrupts which call, and don’t call, API functions?

For the discussion below, lets make the following assumptions:

  1. Numerically higher priority interrupts have logically higher priority (i.e. priority 2 interrupt can preempt priority 1 interrupt handler).
  2. The port implements configKERNEL_INTERRUPT_PRIORITY and configMAX_SYSCALL_INTERRUPT_PRIORITY.

FreeRTOS critical sections disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. Critical sections are the sections of code which manipulate FreeRTOS internal data structures and therefore, any other FreeRTOS API must not be called when the code is in a critical section (otherwise FreeRTOS internal data structures may get corrupted).

Lets say you have 5 interrupts and configMAX_SYSCALL_INTERRUPT_PRIORITY is 3.

                                         ^ +------------+
                                         | |  IRQ1      |
                                         | |            |
                                         | +------------+
        Blocked during critical section  | |  IRQ2      |
                                         | |            |
                                         | +------------+
                                         | |  IRQ3      |<------- configMAX_SYSCALL_INTERRUPT_PRIORITY
                                         v |            |
                                        ---+------------+
                                         ^ |  IRQ4      |
                                         | |            |
    Not blocked during critical section  | +------------+
                                         | |  IRQ5      |
                                         | |            |
                                         v +------------+

When FreeRTOS kernel is in a critical section, IRQ1, IRQ2 and IRQ3 are blocked but IRQ4 and IRQ5 are not. So when the code is in a critical section:

  • If IRQ1, IRQ2 or IRQ3 happens, the corresponding ISR will not be executed until the code exits the critical section.
  • If IRQ4, or IRQ5 happens, the corresponding ISR will be executed immediately and the critical section will be interrupted.
           Critical                    Critical
            Section           IRQ3      Section  ISR3
             Starts         active         Ends  starts
                  ^              ^            ^ ^
                  |              |            | |
                  |              |            | |
                  |              |            | |
          --------+--------------+------------+-+----------------------
                            ---- Increasing time ---->


                            IRQ4  ISR4    ISR4
                           active starts  ends
                                ^ ^       ^
           Critical             | |       |  Critical
            Section             | |       |  Section
             Starts             | |       |  Resumes
                  ^             | |       | ^
                  |             | |       | |
                  |             | |       | |
                  |             | |       | |
          --------+-------------+-+-------+-+-----------------------
                            ---- Increasing time ---->

If ISR for IRQ1, IRQ2 or IRQ3 calls a FreeRTOS API, it will be okay as it will not interrupt a critical section. But if ISR for IRQ4 or IRQ5 calls a FreeRTOS API, that API may be called at a time when the code is in a critical section which will lead to data corruption.

Hope it helps.

Thanks.

2 Likes

Dear Gaurav,

FreeRTOS critical sections disable interrupts up to configKERNEL_INTERRUPT_PRIORITY
I thought if only configKERNEL_INTERRUPT_PRIORITY is used, then in critical section, all interrupts are disabled? And when configMAX_SYSCALL_INTERRUPT_PRIORITY is used, then critical sections disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY itself?

Critical sections are the sections of code which manipulate FreeRTOS internal data structures…
I thought in taskEnterCritical(), the only thing happening in there is that the interrupts got disabled? I cannot find anywhere in taskEnterCritical() that manipulates FreeRTOS internal data structure

Please correct me if I am wrong: I think it should be like below:

                                         ^ +------------+
                                         | |  IRQ1      |
                                         | |            |
                                         | +------------+
        Blocked during critical section  | |  IRQ2      |
                                         | |            |
                                         | +------------+
                                         | |  IRQ3      |<------- **configMAX_SYSCALL_INTERRUPT_PRIORITY**
                                         v |            |
                                        ---+------------+
                                         ^ |  IRQ4      |
                                         | |            |
    Not blocked during critical section  | +------------+
                                         | |  IRQ5      |
                                         | |            |
                                         v +------------+

I thought in taskEnterCritical(), the only thing happening in there is that the interrupts got disabled? I cannot find anywhere in taskEnterCritical() that manipulates FreeRTOS internal data structure

Critical section is the code that executes after a call to taskEnterCritical() and before a call to taskExitCritical(). It is that code which manipulates FreeRTOS data structures. An example is this function which updates FreeRTOS tasks ready list after calling taskEnterCritical() (i.e. after entering critical section): https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/tasks.c#L1068

And yes, you are right and I updated my answer (for others reference).

Thanks.

1 Like

Hi Gaurav/Richard,

I think I understand now. Let me summarize, and correct me if I am wrong:

  1. While Kernel is running, it should not be interrupted by interrupt which calls FreeRTOS API function. It can be, however, be interrupted by interrupt which does not call API functions. This is because Kernel has critical sections, and interrupting Kernel’s critical sections with an interrupt which calls FreeRTOS API will potentially cause data corruption

  2. In a port which implements both configKERNEL _INTERRUPT_PRIORITY and configMAX_SYSCALL_INTERRUPT_PRIORITY: when Kernel is running, IPL (in case of RX port) is set (by the Kernel code) to configMAX_SYSCALL_INTERRUPT_PRIORITY, such that only interrupts having priority high than this, are able to interrupt the Kernel

  3. Therefore, when assigning priority level to a interrupt, user should check whether it calls API function or not. If it does not, then it can be assigned priority higher than configMAX_SYSCALL_INTERRUPT_PRIORITY. If the interrupt does call API function, than its assigned priority cannot be higher than configMAX_SYSCALL_INTERRUPT_PRIORITY; because if otherwise, this interrupt (which calls API function) is able to interrupt the Kernel (which violates 1. above)

Question:
Application can also have critical sections. Is it safe to interrupt application’s critical section with an interrupt which calls FreeRTOS API function?

That is correct.

If critical sections in the application mask interrupts up to the priority set by configMAX_INTERRUPT_PRIORITY, and interrupts that use API functions can only run at priorities configMAX_INTERRUPT_PRIORITY and below, then an interrupt calling an API function cannot interrupt a critical section in the application because it would be masked. That is the whole point.

1 Like