FreeRTOS interrupt priority, critical section configuration (especially important)

a background

There are many configuration materials about FreeRTOS interrupt priority on the Internet, but individual configuration items have changed in v10.0. This article introduces the entire priority management configuration scheme in detail.
The priority of the ARM chip is 0~255. Different chip manufacturers use different priorities, not all of them. Here, the ARM Cortex-M3 series is used as an example. The priority grouping of the CM3 cores is as follows:


write picture description here

In order to manage the interrupt priority more conveniently, ST officially recommends and uses the fifth group by default: NVIC_PriorityGroup_4, whose priority register is an 8-bit register, CM3 only uses the upper 4 bits, forming a total of 16 priorities from 0 to 15, as shown below:


write picture description here

In the stm32f2xx.h file, the CM3 kernel priority is defined by __NVIC_PRIO_BITS to use the upper four bits, with the following code:

/**
 * @brief Configuration of the Cortex-M3 Processor and Core Peripherals 
 */
#define __CM3_REV                 0x0200  /*!< Core Revision r2p0                            */
#define __MPU_PRESENT             1       /*!< STM32F2XX provides an MPU                     */
#define __NVIC_PRIO_BITS          4       /*!< STM32F2XX uses 4 Bits for the Priority Levels */
#define __Vendor_SysTickConfig    0       /*!< Set to 1 if different SysTick Config is used  */

Two FreeRTOS priority configuration (important)

There are three configuration items in FreeRTOSConfig.h, responsible for priority management:

  1. #define configKERNEL_INTERRUPT_PRIORITY 255 //配置内核使用的中断优先级,这里是8 bit,默认最低优先级
  2. #define configMAX_SYSCALL_INTERRUPT_PRIORITY 95 /**配置系统所能调用管理的最高优先级,95转为十六进制是0x5F,最高优先级是5,优先级0-4不归系统管理**/
  3. #define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 /*配置系统内核优先级,这里使用的是4bit优先级,所以最低为15,跟1 中的配置相同*/

The specific interpretation of the above configuration in the ARM-CM3 kernel is: The FreeRTOS operating system kernel uses the lowest priority, and the highest priority that the operating system can call and manage is level 5~15.
I gave two examples to explain the meaning of this configuration in detail. Figure 1 is the example given by the official in the manual. Here, priority 1 is the lowest and priority 7 is the highest. If you configure configMAX_SYSCALL_INTERRUPT_PRIORITY=3 and configKERNEL_INTERRUPT_PRIORITY=1 respectively, the interrupts with priority levels 1~3 are affected and managed by the operating system kernel, and can be masked in the critical section; interrupts with priority levels 4~7 are not affected by the operating system Affects, but system API functions must never be used in interrupts (using operating system functions at priorities not managed by the system may cause timing confusion, exceptions, etc.).
Figure 2 shows the ARM-CM3 core, such as STM32F2xx and STM32F1 series microcontrollers, the core uses 4bit priority, priority 0 is the highest, and priority 15 is the lowest. If you set configMAX_SYSCALL_INTERRUPT_PRIORITY=111 (0x6F) and configKERNEL_INTERRUPT_PRIORITY=255 (0xFF), the priority of 0-5 is not managed by the system, and the system API function cannot be called at the same time; the interrupt of priority 6-15 is subject to the system's Management, you can use API functions (functions with FromISR at the end), and may be affected by the kernel delay, because the critical section of the operating system can temporarily shield the global interrupt, resulting in an interrupt that cannot be responded in time, and you need to wait until you exit the critical section can be executed later.


FreeRTOS official example
Figure 1 FreeRTOS official example


ARM priority of CM core
Figure 2 ARM priority of CM core

Three FreeRTOS task priorities

The task priority configuration of FreeRTOS is system-specific and has nothing to do with hardware. It is only responsible for the scheduling order among multiple tasks in the operating system. The number of task priorities is determined by FreeRTOSConfig.h, with #define configMAX_PRIORITIES ( 16 )task priority 0 being the lowest and 16 being the highest. To briefly mention here, because the assembly (CLZ) instruction for finding leading zeros used in the task scheduling of the operating system is highly efficient, it is recommended to set the maximum number of task priorities not to exceed 32.

  1. Configuration #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1, turn on the leading zero method, provided that the kernel supports the CLZ instruction, Baidu.
  2. configuration #define configMAX_PRIORITIES ( 16 ), using 16 priority numbers. The kernel defaults to using level 0, the lowest priority, idle task.
  3. Configuration #define configIDLE_SHOULD_YIELD 0, only affects idle priority tasks, so that tasks at idle priority (level 0) get the same CPU time.

Summary of the four questions

critical section problem

task name task A task B
priority 1 2
critical section Yes, it takes 2s without
blocking time 10ms 20ms
operation result keep running execute once

Reason analysis: Since vTaskDelay() is used for blocking, in the critical section, the function is in a shielded state and is not counted in the blocking period, so when the blocking time of task A is half of that of task B, the blocking time for task A to execute twice is only Task B can be made ready to switch to task B with higher priority when task A exits the critical section.

task name task A task B
priority 1 2
critical section without without
blocking time 10ms 20ms
operation result keep running keep running

When the critical section is closed, high-priority tasks can normally preempt low-priority task A.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324495689&siteId=291194637