Interrupt prioritization

From SEGGER Wiki
Revision as of 14:23, 27 August 2019 by Martin (talk | contribs)
Jump to: navigation, search

Most CPUs support interrupts with different priorities. Utilizing these, developers may determine the order of execution when two or more interrupts occur simultaneously. The number of available interrupt priority levels depends on the CPU and/or the implemented interrupt controller.

With embOS, different levels of interrupts are grouped into one of two categories, i.e. high priority and low priority interrupts:

  • High priority interrupts are called zero-latency interrupts within the embOS documentation.
  • Low priority interrupts are called embOS interrupts within the embOS documentation.

Generally, the differences between embOS interrupts and zero-latency interrupts are as follows:

embOS interrupts Zero-latency interrupts
May call any embOS API function that is legal for ISRs Must not call any embOS API function
Must call OS_INT_Enter() or OS_INT_EnterNestable() as first embOS API function in the ISR Must not call OS_INT_Enter() or OS_INT_EnterNestable()
Must call OS_INT_Leave() or OS_INT_LeaveNestable() as last embOS API function in the ISR Must not call OS_INT_Leave() or OS_INT_LeaveNestable()
Can temporarily be disabled by embOS and thus may be affected by additional latency Are never disabled by embOS and thus are not affected by additional latency
Typically include the lower half of all available priorities Typcially include the upper half of all available priorities

This means that zero latency interrupts can interrupt the operating system at any time, even in critical sections such as the modification of RTOS-maintained linked lists.

Note: Debug builds of embOS will check the priority of interrupts and call OS_Error() with the error code 166 (OS_ERR_CPU_STATE_ISR_ILLEGAL) in case an embOS API call was made from a zero-latency interrupt.

Interrupt priority levels with ARMv7-M

With its architectural specification, ARMv7-M supports up to 256 interrupt priorities, i.e. the values 0 to 255 (where 0 indicates the highest and 255 the lowest possible priority).
The threshold between embOS interrupts and zero-latency interrupts by default is configured at 128 (where 0 to 127 are considered zero-latency, while 128 to 255 are considered embOS interrupts).

Most ARMv7-M devices, however, do not implement all 256 priority levels, but for example 16 or 32 priority levels only. This is done by omitting the least significant bits of the respective priority register. Consequently, with given examples, the remaining most sugnificant bits may hold priority values of 0 to 15, or 0 to 31, respectively.
With those implementations, the threshold between embOS interrupts and zero-latency interrupts is at 8 or 16, respectively.

Note: Since at reset all priorities are initialized with 0, applications need to explicitly configure the priority of interrupts that should be used as embOS interrupts.

With embOS, there's two different options to configure the priority of interrupts:

  • embOS API functions
  • CMSIS API functions

When using CMSIS API (i.e. NVIC_SetPriority()) the supported priority values may be used as-is, for these functions account for the actual number of implemented interrupt levels for the chosen device and shift the desired value into the appropriate position inside the priority register.

Contrary, when using embOS API (i.e. OS_ARM_ISRSetPrio()) the numbers 0 to 255 must be used in all cases, since these functions are agnostic of the actual number of implemented interrupt levels. This means that these functions will write to the least significant bits of the priority register, but since writes to any un-implemented bits are ignored, this approach gives the exact same results as when using the CMSIS API.

For illustration, the following table holds examples for calls to OS_ARM_ISRSetPrio() and NVIC_SetPriority() with different numbers of priority levels:

highest priority for a zero-latency interrupt lowest priority for a zero-latency interrupt highest priority for an embOS interrupt lowest priority for an embOS interrupt
8 implemented levels with embOS API OS_ARM_ISRSetPrio(<ID>, 0); OS_ARM_ISRSetPrio(<ID>, 127); OS_ARM_ISRSetPrio(<ID>, 128); OS_ARM_ISRSetPrio(<ID>, 255);
with CMSIS API NVIC_SetPriority(<ID>, 0); NVIC_SetPriority(<ID>, 3); NVIC_SetPriority(<ID>, 4); NVIC_SetPriority(<ID>, 7);
32 implemented levels with embOS API OS_ARM_ISRSetPrio(<ID>, 0); OS_ARM_ISRSetPrio(<ID>, 127); OS_ARM_ISRSetPrio(<ID>, 128); OS_ARM_ISRSetPrio(<ID>, 255);
with CMSIS API NVIC_SetPriority(<ID>, 0); NVIC_SetPriority(<ID>, 15); NVIC_SetPriority(<ID>, 16); NVIC_SetPriority(<ID>, 31);
128 implemented levels with embOS API OS_ARM_ISRSetPrio(<ID>, 0); OS_ARM_ISRSetPrio(<ID>, 127); OS_ARM_ISRSetPrio(<ID>, 128); OS_ARM_ISRSetPrio(<ID>, 255);
with CMSIS API NVIC_SetPriority(<ID>, 0); NVIC_SetPriority(<ID>, 63); NVIC_SetPriority(<ID>, 64); NVIC_SetPriority(<ID>, 127);
256 implemented levels with embOS API OS_ARM_ISRSetPrio(<ID>, 0); OS_ARM_ISRSetPrio(<ID>, 127); OS_ARM_ISRSetPrio(<ID>, 128); OS_ARM_ISRSetPrio(<ID>, 255);
with CMSIS API NVIC_SetPriority(<ID>, 0); NVIC_SetPriority(<ID>, 127); NVIC_SetPriority(<ID>, 128); NVIC_SetPriority(<ID>, 255);