I. Basic Concepts
The ARM Coetex-M3 kernel supports a total of 256 interrupts, including 16 internal interrupts, 240 external interrupts, and programmable 256 level interrupt priority settings. Currently, STM32 supports a total of 84 interruptions (16 internal and 68 external), as well as 16-level Programmable Interrupt priority settings. It only uses the high 4 bits of 8 bits for the interrupt priority setting.
STM32 supports 68 interrupt channels and has been allocated to the corresponding external devices. Each interrupt channel has its own interrupt priority control byte PRI_n (8 bits, however, only four bits are used in STM32, and the four bits are valid). The 8-bit interrupt priority control word of each four channels forms a 32-bit priority register. The priority control characters of the 68 channels must contain at least 17 32-bit priority registers.
The 4-bit interrupt priority can be divided into two groups. From a high point of view, the preemptible priority is defined, followed by the response priority. According to this grouping, 4 bits can be divided into 5 groups in total
Group 0th: All 4bit values are used to specify the response priority;
Group 1st: the maximum value of 1 is used to specify the preemptible priority, and the last three are used to specify the response priority;
Group 2nd: The maximum two bits are used to specify the preemptible priority, and the last two bits are used to specify the response priority;
Group 3rd: The maximum three bits are used to specify the preemptible priority, and the last one is used to specify the response priority;
Group 4th: all four bits are used to specify the preemptible priority.
The relationship between preemptible priorities and response priorities is that interruptions with a higher preemptible priority can be responded to during interrupt processing with a lower preemptible priority, namely, interruption nesting.
When the preemptible priorities of the two interrupt sources are the same, there is no nested relationship between the two interrupts. When one interrupt arrives, if another interrupt is being processed, the resulting interruption will not be processed until the previous interruption is completed. If the two interrupts arrive at the same time, the Interrupt Controller determines which one to process based on their response priority. If both their preemptible priority and response priority are equal, then, they decide which one to process first based on their ranking order in the interrupt table. Each interrupt source must have two priorities.
Note the following points:
1) if the specified preemptible priority level or response priority level exceeds the range specified by the selected priority group, unexpected results may be obtained;
2) There is no nested relationship between interrupt sources with the same preemptible priority level;
3) If an interrupt source is specified as a preemptible priority level, and no other interrupt source is in the same preemptible priority level, you can specify any effective response priority for the interrupt source.
Ii. GPIO external interruption
In STM32, each GPIO can trigger an External Interrupt. However, the interrupt of GPIO is in the unit of group bit, and only one external interrupt can be used for the same group at the same time. For example, PA0, PB0, PC0, PD0, PE0, PF0, and PG0 are in one group. If we use PA0 as the external interrupt source, we will not be able to use it any more, in this case, we intelligently use external interrupt sources with different end numbers, such as PB1 and PC2. Each group uses an EXTIx interrupt mark. EXTI0-EXTI4 these 5 external interrupts have their own separate interrupt response function, the EXTI5-9 shares an interrupt response function, and the EXTI10-15 shares an interrupt response function. For interrupt control, STM32 has a dedicated management organization: Objective C.
3. Program Implementation
In fact, the above basic concepts and knowledge only have a rough understanding of the STM32 Interrupt System. speaking with a program will further deepen how to use the interrupt. Follow these steps:
1. Set the corresponding clock;
2. Set the corresponding interrupt;
3. IO port initialization;
4. Set the corresponding IO port as the interrupt line (before setting the External Interrupt) and initialize it;
5. Interrupt the function in the response function of the selected interrupt channel.
Suppose there are three buttons, and the corresponding interruption is triggered by the buttons. K1/K2/K3 is connected to PC5/PC2/PC3, so I will use EXTI5/EXTI2/EXTI3 to interrupt the external connection. PB5, PD6, and PD3 are respectively connected with Three LED lights. The interrupt effect is to press the button and the corresponding LED light will be lit.
1. Set the corresponding clock
First, you need to enable GPIOB, GPIOC, and GPIOE (because the other end is connected to the PE port ). Then, to trigger the interrupt, you also need to enable the GPIO multiplexing clock. The corresponding functions are explained in detail in the GPIO study notes. The Code is as follows:
Void RCC_cfg ()
{
// Enable the PB port clock of the pe pd pc and enable the multiplexing clock.
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOB | enabled, ENABLE );
}
The RCC function required to set the corresponding clock is in stm32f10x_rcc.c, so add this file to the project.
2. Set the corresponding interrupt
Setting the corresponding interrupt is actually to set the interrupt C. There is a struct NVIC_InitTypeDef in the STM32 Firmware Library, which has the corresponding flag settings, and then uses the NVIC_Init () function for initialization. The Code is as follows:
Void NVIC_cfg ()
{
NVIC_InitTypeDef NVIC_InitStructure; // The first struct
NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2); // select interrupt Group 2
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQChannel; // select interrupt Channel 2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // The preemptible interrupt priority is set to 0.
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // The response interrupt priority is set to 0.
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // ENABLE interruption
NVIC_Init (& NVIC_InitStructure );
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQChannel; // select interrupt Channel 3
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // set the preemptible interrupt priority to 1.
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // set the response interruption priority to 1.
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // ENABLE interruption
NVIC_Init (& NVIC_InitStructure );
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; // select interrupt Channel 5
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // set the preemptible interrupt priority to 2.
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; // set the response interruption priority to 2.
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // ENABLE interruption
NVIC_Init (& NVIC_InitStructure );
}
Because there are three interruptions, we need three bits to specify the preemption priority according to the previous article. Therefore, we select the 2nd group. Because the EXTI5-9 shares an interrupt response function, the interrupt channel selected for EXTI5 is EXTI9_5_IRQChannel. The details can be found in the header file. The library functions related to Objective C used are in stm32f10x_nivc.c. You need to copy the file and add it to the project. You can view the GPIO notes for specific locations. There is no problem in compiling this code, but an error will be reported during the link. You need to add STM32F10xR. LIB to the project. The specific location is... KeilARMRV31LIBSTSTM32F10xR. LIB.
3. IO port Initialization
Void IO_cfg ()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // select pin 2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // The maximum output frequency is 50 MHz.
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // output with pulling resistance
GPIO_Init (GPIOE, & GPIO_InitStructure );
GPIO_ResetBits (GPIOE, GPIO_Pin_2); // set the PE.2 pin to a low-level output
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5; // select pin 2 3 5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // select the input mode as float input.
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // The maximum output frequency is 50 MHz.
GPIO_Init (GPIOC, & GPIO_InitStructure); // set PC.2/PC.3/PC.5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6; // select Pin 3 6
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // The maximum output frequency is 50 MHz.
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // output with pulling resistance
GPIO_Init (GPIOD, & GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // select pin 5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // The maximum output frequency is 50 MHz.
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // output with pulling resistance
GPIO_Init (GPIOB, & GPIO_InitStructure );
}
The Pin Connecting to the External Interrupt needs to be set to the input state, and The Pin Connecting to the LED needs to be set to the output state. The initialize PE.2 is to make the other end of the key output low level. The functions in GPIO are in stm32f10x_gpio.c.
4. Set the corresponding IO port as the interrupt line
GPIO is not a dedicated interrupt pin. Therefore, when using GPIO to trigger external interruptions, you need to set the corresponding GPIO pins to be connected to the neutral disconnection. The specific code is as follows:
Void EXTI_cfg ()
{
EXTI_InitTypeDef EXTI_InitStructure;
// Clear the interrupt mark
EXTI_ClearITPendingBit (EXTI_Line2 );
EXTI_ClearITPendingBit (EXTI_Line3 );
EXTI_ClearITPendingBit (EXTI_Line5 );
// Select the interrupt pin PC.2 PC.3 PC.5
GPIO_EXTILineConfig (GPIO_PortSourceGPIOC, GPIO_PinSource2 );
GPIO_EXTILineConfig (GPIO_PortSourceGPIOC, gpio_pinsoure3 );
GPIO_EXTILineConfig (GPIO_PortSourceGPIOC, GPIO_PinSource5 );
EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3 | EXTI_Line5; // select the disconnection line 2 3 5
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // set it to interrupt request, not an event request
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // ENABLE external interrupt
EXTI_Init (& EXTI_InitStructure );
}
All functions to be called in EXTI_cfg are in stm32f10x_exti.c.
5. Write the interrupt response function
Unlike the C51 microcontroller, STM32 can use the interrupt keyword to define the interrupt response function. The STM32 interrupt response function interface has an interrupt vector table, which is provided by the startup code. The default interrupt response function is in stm32f10x_it.c. Therefore, we need to add this file to the project.
In this file, we found that many functions only have one function name and no function body. We can find the EXTI2_IRQHandler () function, which is the function for EXTI2 to interrupt the response. My goal is to light up the LED light, so the function body is actually very simple:
Void EXTI2_IRQHandler (void)
{
// Light up LED lights
GPIO_SetBits (GPIOD, GPIO_Pin_6 );
// Clear the interrupt flag to prevent continuous interruption.
EXTI_ClearITPendingBit (EXTI_Line2 );
}
Void EXTI3_IRQHandler (void)
{
GPIO_SetBits (GPIOD, GPIO_Pin_3 );
EXTI_ClearITPendingBit (EXTI_Line3 );
}
Void EXTI9_5_IRQHandler (void)
{
GPIO_SetBits (GPIOB, GPIO_Pin_5 );
EXTI_ClearITPendingBit (EXTI_Line5 );
}
Since the EXTI5-9 is sharing an interrupt response function, all the response functions of EXTI5-EXTI9 are written in this.
6. Write the main function
# Include "stm32f10x_lib.h"
Void RCC_cfg ();
Void IO_cfg ();
Void EXTI_cfg ();
Void NVIC_cfg ();
Int main ()
{
RCC_cfg ();
IO_cfg ();
NVIC_cfg ();
EXTI_cfg ();
While (1 );
}