STM32 porting FreeRTOS series seven: FreeRTOS interrupt management

Table of contents

1. What is an interruption

2. Interrupt priority group setting

3. Interrupt related registers


1. What is an interruption

Punctual atom ppt

 STM32F1 FreeRTOS Development Manual

7.1.1 Introduction to Interrupts

Interrupts are a very common feature of microcontrollers. Interrupts are generated by hardware. When an interrupt is generated, the CPU will interrupt the current process and turn to handle the interrupt service . The MCU of the Cortex-M core provides a nested interface for interrupt management. Vectored Interrupt Controller (NVIC). The NVIC of Cotex-M3 supports up to 240 IRQs (interrupt requests), 1 non-maskable interrupt (NMI), 1 Systick (tick timer) timer interrupt and multiple system exceptions.

7.1.2 Introduction to Interrupt Management

The Cortex-M processor has several programmable registers for managing interrupts and exceptions, most of these registers are in the NVIC and the system control block (SCB), and CMSIS defines these registers as structures. Take STM32F103 as an example, open core_cm3.h, there are two structures, NVIC_Type and SCB_Type. It is important to note the three interrupt mask registers: PRIMASK , FAULTMASK , and BASEPRI .

2. Interrupt priority group setting

Punctual atom ppt, STM32F1 FreeRTOS development manual

When multiple interrupts come, which interrupt the processor should respond to is determined by the priority of the interrupt. High-priority interrupts (with small priority numbers) must be responded first, and high-priority interrupts can preempt low-level interrupts. Priority interrupts , this is interrupt nesting. Some interrupts of the Cortex-M processor have fixed priorities, such as reset, NMI, and HardFault. The priorities of these interrupts are all negative , and the priority is the highest.

The Cortex-M processor has three fixed priorities and 256(2^8) programmable priorities. Most of the chips will simplify the design, and STM32 only has 16 levels of priority . When designing the chip, several low-end significant bits that express the priority will be cut off to reduce the number of priorities. Use MSB alignment (MSB alignment (Most Significant Bit Alignment) refers to the method of aligning the most significant bit (Most Significant Bit) with a specific position during data storage or transmission).

The Cortex-M processor also divides 256 priorities into high and low segments: preemptive priority (group priority) and sub-priority (sub-priority)
. And reset control register (AIRCR) ", there is a bit field in the AIRCR register called "priority group", and the corresponding assignment of this bit field can divide the bit field of preemption priority and sub-priority.

Register bit segment division 

The impact on the interrupt priority after assigning a value to this bit field

#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
 4 bits for subpriority */
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
 3 bits for subpriority */
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
 2 bits for subpriority */
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
 1 bits for subpriority */
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
 0 bits for subpriority */

When transplanting FreeRTOS, we configured group 4. At this time, all 4 priorities are preemptive priorities.

here in main.c

 /**********************************************************************************************************\

3. Interrupt related registers

Four adjacent priority registers form a 32-bit register.

 The four registers 0xE000_ED20~0xE000_ED23 can be spliced ​​into a 32-bit register whose address is 0xE000_ED20 . this point is very important! Because FreeRTOS directly operates the address 0xE000_ED20 when setting the interrupt priority of PendSV and SysTick .

Three system interrupt priority configuration registers, namely SHPR1 , SHPR2 , SHPR3

SHPR1 Register Address: 0xE000ED18

SHPR2 Register Address: 0xE000ED1C

SHPR3 Register Address: 0xE000ED20

 The interrupt management used by FreeRTOS is to use the BASEPRI register

BASEPRI : Mask interrupts whose priority is lower than a certain threshold. For example: BASEPRI is set to 0x50 , which means that the interrupt priority within 5~15 is masked, and the interrupt priority of 0~4 is executed normally

So how to operate the BASEPRI register now

In the BASEPRI register, interrupts whose priority is lower than a certain threshold are masked. When the threshold is set to 0 , no interrupts are turned off . Writing 0 to BASEPRI will stop masking interrupts. For example, if we want to shield the interrupt whose priority is not higher than 0X60, we can use the following assembly programming:

MOV R0, #0X60 
MSR BASEPRI, R0

If you need to cancel BASEPRI's masking of interrupts, you can use the following code:

MOV R0, #0 
MSR BASEPRI, R0

Notice! The switch interrupt of FreeRTOS is realized by operating the BASEPRI register! It can turn off interrupts below a certain threshold, and interrupts above this threshold will not be turned off!

4. FreeRTOS switch interrupt

The FreeRTOS switch interrupt functions are portENABLE_INTERRUPTS () and portDISABLE_INTERRUPTS(). These two functions are actually macro definitions, which are defined in portmacro.h, as follows:

#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)

It can be seen that the switch interrupt is actually implemented through the functions vPortSetBASEPRI(0) and vPortRaiseBASEPRI(). These two functions are as follows:

Define the scope of FreeRTOS mask interrupt

#define __NVIC_PRIO_BITS          4 /*!< STM32 uses 4 Bits for the Priority Levels    */
#ifdef __NVIC_PRIO_BITS
	#define configPRIO_BITS       		__NVIC_PRIO_BITS
#else
	#define configPRIO_BITS       		4                  
#endif
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5                       //系统可管理的最高中断优先级
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

Here is actually the assignment of the upper four bits of the BASEPRI register to 5

static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

	__asm
	{
		/* Set BASEPRI to the max syscall priority to effect a critical
		section. */
		msr basepri, ulNewBASEPRI
		dsb
		isb
	}
}

This code implements a function vPortRaiseBASEPRIto increase BASEPRIthe priority of the register to achieve the effect of the critical section.

In this code, a variable is first defined ulNewBASEPRIwhose value                     configMAX_SYSCALL_INTERRUPT_PRIORITYis the maximum system call interrupt priority.

Then, use an assembly instruction msrto ulNewBASEPRIload the value of the value into BASEPRIthe register to set the new interrupt priority . Next, use the dsbAND isbinstruction to ensure the order and synchronization of instruction execution.

In general, the function of this code is to BASEPRIset the value of the register to the maximum system call interrupt priority, thereby prohibiting other interrupt requests with a priority lower than or equal to this value, forming a critical section, and ensuring the atomicity of key codes Execution, avoiding race conditions and uncertainty caused by concurrent execution.

enable all interrupts

static portFORCE_INLINE void vPortClearBASEPRIFromISR( void )
{
	__asm
	{
		/* Set BASEPRI to 0 so no interrupts are masked.  This function is only
		used to lower the mask in an interrupt, so memory barriers are not 
		used. */
		msr basepri, #0
	}
}

This code implements a function vPortClearBASEPRIFromISRto clear the registers in the interrupt service routine (ISR) BASEPRIand unmask the interrupt.

In this code, an immediate value is loaded into a register using an assembly instruction , setting the value of 0 to 0. This way, no interrupts are masked and interrupt requests of all priorities are allowed to process normally .msr#0BASEPRIBASEPRI

It should be noted that this function is used in the interrupt service routine (ISR), so no memory barrier (memory barrier) is used to ensure the order and synchronization of instruction execution. Usually, in the interrupt service routine, because it runs in a single context, there is no need for data synchronization and memory barrier operations.

Guess you like

Origin blog.csdn.net/qq_51519091/article/details/131541203