Table of contents
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 vPortRaiseBASEPRI
to increase BASEPRI
the priority of the register to achieve the effect of the critical section.
In this code, a variable is first defined ulNewBASEPRI
whose value configMAX_SYSCALL_INTERRUPT_PRIORITY
is the maximum system call interrupt priority.
Then, use an assembly instruction msr
to ulNewBASEPRI
load the value of the value into BASEPRI
the register to set the new interrupt priority . Next, use the dsb
AND isb
instruction to ensure the order and synchronization of instruction execution.
In general, the function of this code is to BASEPRI
set 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 vPortClearBASEPRIFromISR
to clear the registers in the interrupt service routine (ISR) BASEPRI
and 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
#0
BASEPRI
BASEPRI
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.