The concept of priority in STM32 (Cortex-M3)
There are two concepts of priority in STM32 (Cortex-M3) - preemptive priority and response priority. Some people call response priority 'sub-priority' or 'sub-priority'. Each interrupt source needs to be assigned these two priorities.
An interrupt with a high preemptive priority can be responded to during the interrupt processing with a low preemptive priority, that is, interrupt nesting, or an interrupt with a high preemptive priority can nest an interrupt with a low preemptive priority.
When the preemptive priority of two interrupt sources is the same, there will be no nesting relationship between the two interrupts. When one interrupt arrives, if another interrupt is being processed, the later interrupt will have to wait until the previous interrupt is processed. If the two interrupts arrive at the same time, the interrupt controller decides which one to process first based on their response priority; if their preemptive priority and response priority are equal, the order of their ranking in the interrupt table determines which one to process first.
Since each interrupt source needs to be assigned these two priorities, there needs to be a corresponding register bit to record the priority of each interrupt; in Cortex-M3, 8 bits are defined to set the priority of the interrupt source. These 8 bits can be allocated in 8 ways, as follows:
All 8 bits are used to specify the response priority
The highest 1 bit is used to specify the preemptive priority, and the lowest 7 bits are used to specify the response priority
The highest 2 bits are used to specify the preemptive priority, and the lowest 6 bits are used to specify the response priority
The highest 3 bits are used to specify the preemptive priority, and the lowest 5 bits are used to specify the response priority
The highest 4 bits are used to specify the preemptive priority, and the lowest 4 bits are used to specify the response priority
The highest 5 bits are used to specify the preemptive priority, and the lowest 3 bits are used to specify the response priority
The highest 6 bits are used to specify the preemptive priority, and the lowest 2 bits are used to specify the response priority
The highest 7 bits are used to specify the preemptive priority, and the lowest 1 bit is used to specify the response priority
This is the concept of priority grouping.
--------------------------------------------------------------------------------
Cortex-M3 allows fewer interrupt sources to use fewer register bits to specify the priority of the interrupt source, so the STM32 reduces the register bits for specifying interrupt priority to 4 bits. These 4 register bits are grouped as follows:
Group 0: All 4 bits are used to specify the response priority
Group 1: The highest 1 bit is used to specify the preemptive priority, and the lowest 3 bits are used to specify the response priority
Group 2: The highest 2 bits are used to specify the preemptive priority, and the lowest 2 bits are used to specify the response priority
Group 3: The highest 3 bits are used to specify the preemptive priority, and the lowest 1 bit is used to specify the response priority
Group 4: All 4 bits are used to specify the preemptive priority
You can choose which priority grouping method to use by calling the function NVIC_PriorityGroupConfig() in the STM32 firmware library. This function has the following five parameters:
NVIC_PriorityGroup_0 => Select Group 0
NVIC_PriorityGroup_1 => Select Group 1
NVIC_PriorityGroup_2 => Select Group 2
NVIC_PriorityGroup_3 => Select Group 3
NVIC_PriorityGroup_4 => Select Group 4
The next step is to specify the priority of the interrupt source. The following is a simple example to illustrate how to specify the preemptive priority and response priority of the interrupt source:
// Select to use priority group 1
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// Enable EXTI0 interrupt
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPrio
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // Specify response priority level 0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// Enable EXTI9_5 interrupt
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPrio
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // Specify response priority level 1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
A few points to note are:
1) If the specified preemptive priority or response priority exceeds the range defined by the selected priority group, unexpected results may occur;
2) There is no nesting relationship between interrupt sources with the same preemptive priority level;
3) If an interrupt source is assigned a preemptive priority level and there is no other interrupt source at the same preemptive priority level, any valid response priority level can be assigned to this interrupt source.
Second, the switch is always interrupted:
In STM32/Cortex-M3, interrupts are enabled or disabled by changing the current CPU priority.
PRIMASK bit: Only NMI and hard fault exceptions are allowed, and all other interrupts/exceptions are masked (current CPU priority = 0).
FAULTMASK bit: Only NMI is allowed, and all other interrupts/exceptions are masked (current CPU priority = -1).
In the STM32 firmware library (stm32f10x_nvic.c and stm32f10x_nvic.h), four functions are defined to operate the PRIMASK bit and the FAULTMASK bit to change the current priority level of the CPU, thereby achieving the purpose of controlling all interrupts.
The following two functions are equivalent to turning off the general interrupt:
void NVIC_SETPRIMASK(void);
void NVIC_SETFAULTMASK(void);
The following two functions are equivalent to opening the global interrupt:
void NVIC_RESETPRIMASK(void);
void NVIC_RESETFAULTMASK(void);
The above two groups of functions should be used in pairs and cannot be used interchangeably.
For example:
The first method:
NVIC_SETPRIMASK();
NVIC_RESETPRIMASK(); //Enable the general interrupt
The second method:
NVIC_SETFAULTMASK();
NVIC_RESETFAULTMASK(); //Enable the general interrupt
Frequently used
NVIC_SETPRIMASK();
NVIC_RESETPRIMASK();
As a habit of mine, when learning something about a certain platform, I always have to understand the interrupt processing flow first, of course, from the file code level process analysis.
Let's talk about the interrupt process of stm32. We know that there are many drivers written in the stm32 library, which can be said to include all. At the same time, many data processing methods are also provided, such as serial port reading and writing, and users can choose polling, interruption, DMA and other 3 methods to process.
Regarding interrupts, the stm32 library has a good framework, and users only need to fill in the implementation of several functions. As the Internet says, this is fool-proof development.
To understand interrupts, you must first know the file stm32f10x_it.c, which is generally in the same directory as the main file. Open this file, we can see the implementation of the xyz_IRQHandler function. Although it is an implementation, it is almost empty. By the way, these functions are interrupt processing functions that users need to fill in. If you use which interrupt to do the corresponding processing, you have to fill in the corresponding interrupt processing function. You need to fill it out according to the actual situation of each peripheral, but generally there will be interrupts turned off and on. There are many system-related interrupt handling functions in this file, such as the system clock SysTickHandler. For specific implementations, please refer to the examples under stm32fwlibFWLibexamples.
So far, we have only seen the interrupt handling functions, but how are these handling functions called by hardware interrupts? Well, here we have to mention the file stm32f10x_vector.c. The content is as follows:
typedef void( *intfunc )( void );
typedef union { intfunc __fun; void * __ptr; } intvec_elem;
// Some extensions made by IAR to the used language (here is C), that is, the extended functions can be used here
#pragma language=extended #pragma segment="CSTACK"
void __iar_program_start( void );
#pragma location = ".intvec"
const intvec_elem __vector_table[] =
{
At this point, there is another question, where is this vector table placed? From the above explanation of .intvec, we can see that it is placed at an address by the linker (here is 0x08000000, NVIC_VectTab_FLASH). But how does stm32 know this address? Maybe there is a default value, or is it just a fixed value? ). We found the following function in the stm32f10x_nvic.c file:
void NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)
{
}
At the same time, there is an example of vectortable_relocation in the example directory: This example describes how to use the NVIC firmware library to set the CortexM3 vector table in a specific address other than default.
In this example, the above function is called directly, and it seems that the meaning is obvious. But how does SCB->ExceptionTableOffset work?
To explain this problem in detail, let's first look at a set of definitions: [stm32f10x_map.b]
#define SCS_BASE
#define SysTick_BASE (
#define NVIC_BASE (SCS_BASE + 0x0100)
#define SCB_BASE (SCS_BASE + 0x0D00)
#ifdef _SCB
#define SCB ((SCB_TypeDef *) SCB_BASE)
#endif
typedef struct
{ vu32 CPUID; vu32 IRQControlState; vu32 ExceptionTableOffset; vu32 AIRC; vu32 SysCtrl; vu32 ConfigCtrl; vu32 SystemPriority[3]; vu32 SysHandlerCtrl; vu32 ConfigFaultStatus; vu32 HardFaultStatus; vu32 DebugFaultStatus; vu32 MemoryManageFaultAddr; vu32 BusFaultAddr;
} SCB_TypeDef;
Actually, the main thing here is to figure out what this SCB means, because this structure is mapped to a physical address. Like other control registers, this is the same way. Could it be that this is also some kind of controller? After a google search, I found that the system control register group [mentioned in the previous article] is defined in the STM32 firmware library as follows:
typedef struct
{ vuc32 CPUID; vu32 ICSR; vu32 VTOR; vu32 AIRCR; vu32 SCR ; vu32 CCR; vu32 SHPR[3]; vu32 SHCSR; vu32 CFSR; vu32 HFSR; vu32 DFSR; vu32 MMFAR; vu32 BFAR ; vu32 AFSR;
} SCB_TypeDef;
Their corresponding names in the ARM manual are
CPUID = CPUID Base Register
ICSR = Interrupt Control State Register
VTOR = Vector Table Offset Register
AIRCR = Application Interrupt/Reset Control Register
SCR = System Control Register
CCR = Configuration Control Register
SHPR = System Handlers Priority Register
SHCSR = System Handler Control and State Register
CFSR = Configurable Fault Status Registers
HFSR = Hard Fault Status Register
DFSR = Debug Fault Status Register
MMFAR = Mem Manage Address Register
BFAR = Bus Fault Address Register
AFSR = Auxiliary Fault Status Register
At this point, we finally know that the address of this interrupt vector table will eventually be written to a controller. So, the above 0x08000000 can be a different value, as long as it is ensured that this address cannot be accessed by other programs.
Previous article:About stm32 microcontroller, using id encryption, plain code security analysis
Next article:Create an STM32 project based on the V3.4.0 firmware library in Keil4
Recommended ReadingLatest update time:2024-11-16 17:44
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Switch OUT?! Nintendo's latest recruitment may be aimed at the next generation console
- 【ST NUCLEO-H743ZI Review】+ 3. Key input
- Today's Live Broadcast | Outlook for DLP Technology in AR HUD and In-Vehicle Display Applications
- Award-winning live broadcast: Focus on "TI FPD-Link III automotive chipset" Ideal solution for automotive video transmission
- Playing with Zynq Serial 1——Zynq Linux boot process
- 【AT-START-F425 Review】Overclocking Performance of AT32F425
- I can't access GitHub anymore, what should I do? I can't access it at all
- [Mill MYB-YT507 development board trial experience] opencv face detection
- TouchGFX application development based on STM32CubeMX on STM32H7A3 processor - HelloWorld!
- How large a fifo capacity can ep4ce6 achieve?