Important Considerations for Using FreeRTOS with Cortex-M

This article is from CSDN Blog on FreeRTOS Basics, and it mainly shares important considerations for using FreeRTOS with Cortex-M.

Original link:

https://blog.csdn.net/zhzht19861011/article/details/50135449

Before reading this article, you must understand the meanings of two macros defined in FreeRTOSConfig.h. The article “FreeRTOS Kernel Configuration Description” explains these two macros:

●configKERNEL_INTERRUPT_PRIORITY

●configMAX_SYSCALL_INTERRUPT_PRIORITY

FreeRTOS is a perfect match for the Cortex-M core, making the porting and use of FreeRTOS much simpler. According to official feedback from FreeRTOS, most issues encountered when using FreeRTOS on Cortex-M cores are caused by incorrect priority settings. This issue is expected because, although the interrupt mode of the Cortex-M core is very powerful, it can be a bit cumbersome (or rather complicated) for engineers who are used to traditional interrupt priority architectures, and it is counterintuitive (mainly because in Cortex-M, a higher numerical value for interrupt priority represents a lower priority). This chapter intends to describe the interrupt priority mechanism of Cortex-M and how to use it in conjunction with the RTOS kernel.

Note: Although the priority scheme of the Cortex-M core may seem complex, every officially released FreeRTOS interface package (usually found in FreeRTOSV7.2.0\FreeRTOS\Source\portable folder, typically port.c) will have correctly configured demonstration routines that can serve as a reference.

1 Effective Priority

1.1 Detailed Description of Cortex-M Hardware

First, it is important to understand the total number of effective priorities, which depends on how the microcontroller manufacturer utilizes the Cortex core. Therefore, not all Cortex-M core microcontrollers have the same interrupt priority levels.

The Cortex-M architecture itself allows up to 256 programmable priority levels (the priority configuration register is up to 8 bits, so the priority range is from 0x00 to 0xFF), but most microcontroller manufacturers only use a portion of those priorities. For example, TI Stellaris Cortex-M3 and Cortex-M4 microcontrollers use 3 bits of the priority configuration register, providing 8 priority levels. Similarly, NXP LPC17xx Cortex-M3 microcontrollers use 5 bits of the priority configuration register, providing 32 priority levels.

1.2 Application to RTOS

The RTOS interrupt nesting scheme divides effective interrupt priorities into two groups: one group can be masked by the RTOS critical section, and the other group is unaffected by the RTOS and is always enabled. The macro configMAX_SYSCALL_INTERRUPT_PRIORITY in FreeRTOSConfig.h defines the boundary between the two groups of interrupt priorities. Interrupts with a logical priority higher than this value are unaffected by the RTOS. The optimal value depends on the number of bits used in the priority configuration register of the microcontroller.

2 Priority Values and Logical Priority Settings

2.1 Detailed Description of Cortex-M Hardware

It is necessary to explain the priority values and logical priorities: in the Cortex-M core, if there are 8 priority levels, we say the priority values range from 0 to 7, but the highest priority value of 7 actually represents the lowest logical priority. Many engineers accustomed to traditional interrupt priority architectures may find this counterintuitive. It is important to carefully distinguish whether the priority mentioned below refers to the priority value or the logical priority.

Next, it is necessary to understand that in the Cortex-M core, the lower the priority value of an interrupt, the higher the logical priority. For example, an interrupt with a priority of 2 can preempt an interrupt with a priority of 5, but not vice versa. In other words, interrupt priority 2 is higher than interrupt priority 5.

This is the most common mistake made with the Cortex-M core, as most non-Cortex-M core microcontrollers express interrupt priorities in the opposite way.

2.2 Application to RTOS

FreeRTOS functions that end with “FromISR” are protected for interrupt calls (executing these functions enters a critical section), but even these functions cannot be called by interrupt service functions with logical priorities higher than configMAX_SYSCALL_INTERRUPT_PRIORITY (the macro configMAX_SYSCALL_INTERRUPT_PRIORITY is defined in the header file FreeRTOSConfig.h). Therefore, any interrupt service routine using RTOS API functions must have an interrupt priority value greater than or equal to the value of the configMAX_SYSCALL_INTERRUPT_PRIORITY macro. This ensures that the logical priority of the interrupt is equal to or lower than configMAX_SYSCALL_INTERRUPT_PRIORITY.

By default, Cortex interrupts have a priority value of 0. In most cases, 0 represents the highest priority. Therefore, RTOS API functions must never be called in interrupt service routines with a priority of 0.

3 Overview of Cortex-M Internal Priorities

3.1 Detailed Description of Cortex-M Hardware

The interrupt priority register of the Cortex-M core is aligned to the Most Significant Bit (MSB). For example, if 3 bits are used to express priority, these 3 bits are located at bits 5, 6, and 7 of the interrupt priority register. The remaining bits 0 to 4 can be set to any value, but for compatibility, it is best to set them to 1.

The Cortex-M priority register has up to 8 bits. If a microcontroller only uses 3 of them, those 3 bits are aligned to the MSB, as shown in the following figure:

Important Considerations for Using FreeRTOS with Cortex-M

Figure 1

A certain microcontroller only uses 3 bits in the priority register. The following figure shows how the priority value 5 (binary 101B) is stored in the priority register. If the unused position in the priority register is 1, the figure also shows why the value 5 (binary 0000 0101B) can be seen as the value 191 (binary 1011 1111).

Important Considerations for Using FreeRTOS with Cortex-M

Figure 2

A certain microcontroller only uses 4 bits in the priority register. The following figure shows how the priority value 5 (binary 101B) is stored in the priority register. If the unused position in the priority register is 1, the figure also shows why the value 5 (binary 0000 0101B) can be seen as the value 95 (binary 0101 1111).

Important Considerations for Using FreeRTOS with Cortex-M

Figure 3

3.2 Application to RTOS

As described above, the logical priority of interrupts that call RTOS API functions in interrupt service routines must be less than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY (lower logical priority means higher priority value).

CMSIS and different microcontroller vendors provide library functions that can set a certain interrupt priority. Some library function parameters are aligned to the least significant bit, while others may be aligned to the most significant bit, so it is essential to refer to the library function application manual for correct settings.

The values of macros configMAX_SYSCALL_INTERRUPT_PRIORITY and configKERNEL_INTERRUPT_PRIORITY can be set in FreeRTOSConfig.h. These two macros need to be set according to the specific situation of the Cortex-M core, aligned to the most significant bit. For example, if a certain microcontroller uses 3 bits in the interrupt priority register, setting the value of configKERNEL_INTERRUPT_PRIORITY to 5 would look like this:

#define     configKERNEL_INTERRUPT_PRIORITY  (5<<(8-3))

The macro configKERNEL_INTERRUPT_PRIORITY specifies the interrupt priority used by the RTOS kernel, as the RTOS kernel cannot preempt user tasks, this macro is generally set to the minimum priority supported by the hardware. For Cortex-M hardware, the RTOS uses the PendSV and SysTick hardware interrupts, and in the function xPortStartScheduler() (this function is called by the scheduler start function vTaskStartScheduler()), the priority register for the PendSV and SysTick hardware interrupts is set to the value specified by the macro configKERNEL_INTERRUPT_PRIORITY.

The relevant code is as follows (located in port.c):

/*PendSV priority setting register address is 0xe000ed22 SysTick priority setting register address is 0xe000ed23*/#define portNVIC_SYSPRI2_REG     ( * ( ( volatile uint32_t * ) 0xe000ed20 )) #define portNVIC_PENDSV_PRI ( ( (uint32_t)configKERNEL_INTERRUPT_PRIORITY ) << 16UL )#define portNVIC_SYSTICK_PRI ( ( (uint32_t)configKERNEL_INTERRUPT_PRIORITY ) << 24UL )/* …. *//*Ensure PendSV and SysTick are the lowest priority interrupts */portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;portNVIC_SYSPRI2_REG |=portNVIC_SYSTICK_PRI;

4 Critical Section

4.1 Detailed Description of Cortex-M Hardware

The RTOS kernel uses the BASEPRI register of the Cortex-M core to implement critical sections (Note: BASEPRI is the priority masking register, any interrupt with a priority value greater than or equal to this register will be masked; the higher the priority value, the lower the logical priority, but when zero, no interrupts are masked). This allows the RTOS kernel to mask only a portion of interrupts, thus providing a flexible interrupt nesting model.

For those API functions that need to be protected during interrupt calls, FreeRTOS uses the BASEPRI register to implement interrupt protected critical sections. When entering a critical section, the value of the BASEPRI register is set to configMAX_SYSCALL_INTERRUPT_PRIORITY, and when exiting the critical section, the value of the BASEPRI register is set to 0. Many bug reports mention that when exiting a critical section, the register should not be set to 0 but should restore its previous state (the previous state is not necessarily 0). However, the Cortex-M NVIC will never allow a lower priority interrupt to preempt a currently executing higher priority interrupt, regardless of the value in the BASEPRI register. Compared to the method of saving the BASEPRI value before entering the critical section and restoring it upon exiting, setting the BASEPRI register to 0 upon exiting the critical section allows for faster execution speed.

4.2 Application to RTOS Kernel

The RTOS kernel creates critical sections by writing the value of configMAX_SYSCALL_INTERRUPT_PRIORITY to the BASEPRI register. Interrupt priority 0 (with the highest logical priority) cannot be masked by the BASEPRI register, so configMAX_SYSCALL_INTERRUPT_PRIORITY must never be set to 0.

Source | Arm Education

Copyright belongs to the original author, if there is any infringement, please contact to delete

END

About Arm Education

Arm Education is an innovative education platform focusing on AIoT (Artificial Intelligence + Internet of Things), providing a comprehensive AIoT education solution from primary and secondary schools to higher education institutions. Arm Education, relying on Arm technology, has developed the ASC (Arm Smart Connectivity) curriculum and talent training system. It has been widely applied in university-industry cooperation and K-12 STEM education, dedicated to cultivating talents in the field of intelligent connectivity that meet the needs of the times.

Leave a Comment