Understanding priority levels of ISR and FreeRTOS APIs

As per:

That means an interrupt cannot itself be interrupted by another interrupt that has a logical priority below the maximum syscall interrupt priority - and can therefore access whatever is being protected by the critical section.

Yes.

The priority registers is only 8-bits and will only implement a few bits of the 8-bit register, so presumably when the value gets shifted you are not ending up with any bits set in any of the bits implemented by the hardware, so the value will appear to the hardware as 0. However you have the code there so you can determine exactly what it is doing.

When FreeRTOS is manipulation its internal structures, like a ready list, it needs to make sure that no one else is going to also try to manipulate the structure. It does this by disabling the interrupts at and below configMAX_SYSCALL_INTERRUPT_PRIORITY. If an interrupt has a higher priority (lower value) than this and does call a FreeRTOS function (and the assert is present to catch it), and that function manipulates the same structure, that can result in a corrupted data structure, things like a task being lost from the ready queue is a very real possibility.

1 Like

It does this by disabling the interrupts at and below configMAX_SYSCALL_INTERRUPT_PRIORITY

If an interrupt has a higher priority (lower value) than this

i’m getting confused by these two lines. ISRs with interrupt priority <= configMAX_SYSCALL_INTERRUPT_PRIORITY mean they’re of a higher priority. If the kernel disables “high” priority interrupts, then why would the interrupt occur?

In essence, we want to prevent any ISR of priority >= configMAX_SYSCALL_INTERRUPT_PRIORITY from triggering while critical section is being executed, yeah?

Kind of. configMAX_SYSCALL_INTERRUPT_PRIORITY sets the maximum LOGICAL priority from which FreeRTOS API calls can be made, so we want to block interrupts with a priority greater than configMAX_SYSCALL_INTERRUPT_PRIORITY, not greater than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY.

that’s fine. I’m trying to distinguish the priority levels of ISRs from that of FreeRTOS’.
So when we say we want to block the interrupts of a priority > configMAX_SYSCALL_INTERRUPT_PRIORITY, we actually mean high or low priorities cause the higher numbers represent lower priorities?

Yes, FreeRTOS sets a mask register that controls what interrupt priorities can trigger to configMAX_SYSCALL_INTERRUPT_PRIORITY, which means interrupts of that priority or greater-value lower-priority are blocked, and lesser-value higher-priority can still happen. The ordering of interrupt priorities is the reverse of the value, so higher priority is lesser value. (and I try to always use higher or lower, never greater or lesser (as well as the mathematical symbols) as those tend to refer to the NUMBERS (as in priority value), not the priority order of the interrupts

So it disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY, but leaves higher priority interrupts enabled.

I feel in your previous message, you probably mistyped. The interrupts < configMAX_SYSCALL_INTERRUPT_PRIORITY are of higher priority so if it’s disabling interrupts upto that, it’s disabling high priority interrupts and leaving low priority (>= configMAX_SYSCALL_INTERRUPT_PRIORITY) enabled, no?

Also, if the high priority interrupts are disabled while critical section is being executed, why the fear of them triggering and corrupting the critical section?

Sorry if I’m being a nuisance right now.

Be VERY careful how you interpret things, by “disable interrupts up to configMAX_SYSCALL_IN TERRUPT_PRIORITY”, it is meant to disable any interrupt with a priority value >= configMAX_SYSCALL_INTERRUPT_PRIORITY. I try to use very distinct here, ‘higher’ and ‘lower’ are logical priorities, higher priority interrupts have numerically smaller values.

The interrupt hardware doesn’t have an option to turn off just higher priority interrupts, and leave lower priorities enabled, largely because it doesn’t make sense. The hardware has a register for the current mask level, and interrupt of that level and lower (bigger values) are masked off and won’t generate an interrupt still the mask is removed of set to a lower priority (higher value) than the interrupt in question.

Yes I believe I’m interpreting the right way: disabling interrupts of a higher priority upto configMAX_SYSCALL_INTERRUPT_PRIORITY - in other words, if configMAX_SYSCALL_INTERRUPT_PRIORITY == 4, priority values of 1,2,3,4 are disabled, yes?

Also from the doc:

ISR’s running above the maximum syscall priority are never masked out by the RTOS kernel itself

I reckon they’re referring to the numerical interrupts and not logical.

Then what do we mean by disabling interrupts if it isn’t for “disabling interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY” i.e disabling only high priorities?

Just think in LOGICAL priorities where higher is above lower and lower is below [edit!] higher - because you are turning everything in knots. Ignore the actual numerical values - as I said originally - ARM MCUs use low NUMERICAL values to represent high LOGICAL priorities - but nearly every other MCU (and FreeRTOS runs on 40+ architectures) do it the other way around. Therefore the website cannot make an assumption as to which way around a particular MCU happens to number interrupt priorities - but no matter logically higher interrupt priroities are always higher in priority than logically lower interrupt priorities - that is why they are called priorities. If you mask up to a logical priority level then only interrupts that have a logically higher priority can execute.

Therefore configMAX_SYSCALL_INTERRUPT_PRIORITY is the maximum LOGICAL priority from which a FreeRTOS API function can be called.

When the MCU masks interrupts up to a specified LOGICALLY priority value, all interrupt priorities LOGICALLY lower than it (the ones that the MCU sees as having lower priority, doesn’t matter what its actual number is) are masked and interrupt priorities LOGICALLY higher than it (the ones that can still interrupt because they are not masked) can still execute.

1 Like

NO!, it means priorities 4,5,6,… get disabled. ‘up to’ is talking about the LOGICAL priority order not numerical. As I said, the hardware doesn’t have a mechanism to disable high priority (small numerical value) interrupts but leave lower priority (larger numerical value) still enabled

Again, you have it backwards, it says that interrupts with a higher priority, i.e a SMALLER value, than configMAX_SYSCALL_INTERRUPT_PRIORITY are never disabled by FreeRTOS.

If you are ever thinking that you have a case where an interrupt of priority value 1 is disabled, but an interrupt of priority 6 is still enabled, you have it wrong. The only way to do something like that it go to the specific interrupt (by number, not interrupt priority) and disable it.

The FreeRTOS documentation will almost always be referring to the Logical interrupt priority (lower meaning higher value and higher being lower values, on the Cortex M series) because it is describing in a hardware independent way what is happening, and on other machines, priority 0 may be the lowest priority. One in the chapter specifically for the Cortex M processors will it talk specifically about interrupt priority values (Thats the page Richard Barry pointed out near the beginning of the topic).

A pictorial representation, if that helps:


            Logical      Numerical
           Priorities    Priorities
           +--------+    +-------+             ^
           |        |    |       |             |
           |        |    |       |             |
           |        |    |       |             | Not masked by FreeRTOS kernel
           | Higher |    | Lower |             | ( FreeRTOS APIs can not be
           |        |    |       |             |    called from these ISRs. )
           |        |    |       |             |
           |        |    |       |             v
           +--------+    +-------+ <---------------- configMAX_SYSCALL_INTERRUPT_PRIORITY
           |        |    |       |             ^
           |        |    |       |             |
           |        |    |       |             |
           |        |    |       |             |
           |        |    |       |             |
           |        |    |       |             |
           |        |    |       |             |
           | Lower  |    |Higher |             | Masked by FreeRTOS Kernel
           |        |    |       |             | ( FreeRTOS APIs can be
           |        |    |       |             |    called from these ISRs. ) 
           |        |    |       |             |
           |        |    |       |             |
           |        |    |       |             |
           |        |    |       |             |
           |        |    |       |             |
           |        |    |       |             |
           +--------+    +-------+             v

So in terms of NUMERICAL PRIORITIES, if configMAX_SYSCALL_INTERRUPT_PRIORITY == 4, then 4, 5, 6 and above are masked during critical sections.

Thanks.

4 Likes

Right. So the kernel disables the low priority interrupts to prevent any other low priority interrupts using fromISR APIs from accessing the critical region while it’s being accessed by another ISR already and prevents any high priority interrupt from fiddling with the critical section by asserting out hence not suggested to not fromISR in high priority ISRs.

To clarify: a lower priority interrupt has acquired a lock, and a high priority interrupt occurs. The higher priority interrupt will rightaway be executed but what happens to the lock? technically if the lock remains intact then we shouldn’t worry about higher priority interrupt fiddling with a critical section but that’s what I’m trying to clarify.

Yep, thanks for it. But what causes the confusion is in some examples, they have referred higher numerical priority to a higher priority.

Refer to the table captioned Example interrupt priority configuration

When I low priority interrupt enters a critical section, the interrupt mask level is temporarily bumped to configMAX_SYSCALL_INTERRUPT_PRIORITY, so the higher level interrupt will be masked off for the duration of the critical section. Interrupts with higher priority (lower value on Cortex M) than configMAX_SYSCALL_INTERRUPT_PRIORITY, which aren’t allowed interact with FreeRTOS, can still occur, but they won’t mess with the data protected by the critical section.

You are misunderstanding that page. The ONLY spot it actually refers to a numeric physical priority (as opposed to a logical number where 0 is lowest priority) is in the section title “Special Note for ARM Cortex-M3 and Cortex-M4 users”. Everywhere else, you should be reading the “number” used as a priority NOT as the value loaded into the priority register, but as a logical priority value where lower number is lower priority. Except for that note, the whole page is designed to talk about a generic architecture, and assumes the “Low Priority” means it is a Low Priority (which turns out on the Cortex-M to be a big number).

1 Like

As clarified by Richard Damon, that page is not Cortex-M specific and therefore, you should read those numbers as logical priorities (lesser the number, lower the priority).

As mentioned before too, this pages talks about Cortex-M priorities in detail: https://www.freertos.org/RTOS-Cortex-M3-M4.html

Getting the priority configuration right on Cortex-M is not straight forward - therefore, there are many asserts to catch incorrect configurations.

Thanks.

so the higher level interrupt will be masked off for the duration of the critical section

do you mean higher priority interrupts are masked off while the lower priority interrupt is executing critical section?

Yes, to give a concrete example, on a Cortex-M with the MAX_SYSCALL of 5 and 4 bits (priorities 0-Highest to 15-Lowest).
If a Priority level 14 ISR enters a critical section, the Interrupt Mask Level gets set to 5, so if a Interrupt level 8 interrupt get raised, it will be held off. When the critical section end, and the mask level restored, the interrupt will occur then.

On the other hand, if a priority level 2 interrupt comes, it will interrupt immediately.

Priority 2 will preempt immediately cause it’s got a higher priority and is not masked, but i’m not sure if this relates to your previous point about high priority interrupts getting disabled while lower priority interrupt is executing critical section.

And by high priority, I mean the ones that are not masked by the kernel (higher priority than configMAX_SYSCALL_INTERRUPT_PRIORITY