STM32CubeMX Tutorial Series: EXTI

From Waveshare Wiki
Jump to: navigation, search
Abstract: This chapter present the external interrupt operation flow of STM32.

The project presented in this chapter is modified based on the GPIO project described in the chapter above. Copy the GPIO project, and modify the folder name. Click the file STM32F746I.ioc to open the project file STM32cubeMX for reconfiguration. PA0 should be configure to GPIO_EXTI0 mode.

Stm32cubemx-tutorial-series-exti-1.pngStm32cubemx-tutorial-series-exti-2.png

Since the WAKEUP key has connected to an external resistor, the PA0 will output high level when pressing WAKEUP key. In the GPIO configuration, set PA0 as rising edge trigger. Select No pull-up and no pull-down in the option GPIO Pull-up/Pull-down. In the user label box, add the label WAKEUP.

Stm32cubemx-tutorial-series-exti-3.png

In NVIC, check the option EXTI Line0 interrupt to enable PA0 interrupt. And the two options on the right are used to set the preemption priority and sub-priority. Here, we remain the default settings.

Stm32cubemx-tutorial-series-exti-4.png

Here we will shortly introduce what is NVIC (Nested Vector Interrupt Controller). NVIC is used to control the interrupt response. There are three parameters involved, Enable checkbox, Preemption priority and Sub-priority (the highest the value, thelowest the priority).

Using the Enable checkbox, youcan check/uncheck to enable/disable the interrupt. In the case that the interrupt is enabled, the running program will jump to the interrupt service routine when the interrupt trigger conditions are met. Otherwise,the program will not respond the interrupt request.

The preemption prioritydefines theability of one interrupt to interrupt another.For example, A interrupt is triggered and the corresponding interrupt service routine are running, and then B interrupt is triggered as well. If the preemption priority level of B interrupt is higher than A interrupt, the program will break the A interrupt service routine andjump to run the B interrupt service routine. If the preemption priority level of B interrupt is lower than A interrupt, the program will keep running the A interrupt service routine and will not run the B interrupt service routine until the A interrupt service routine finished.

Sub-prioritydefines the interrupt prioritylevel.In case that the interrupts with the same preemption priority level are triggered simultaneously, the one with the higher sub-priority will run first.

How to judge the priority level among the interrupts? First, you should check the preemption priority. The one with the higher preemption priority has the higher interrupt priority. For the interrupts with the same preemption priority, the one with the higher sub-priority has the higher interrupt priority. In case of the interrupts with the same preemption priority and sub-priority, the interrupt vector table may help you to know which one has the higher priority level. Here is a part of the interrupt vector table. For more information, please refer to the table 43. STM32F75xxx and STM32F74xxx vector table in File:STM32F745-STM32F746-Datasheet.pdf.

Here we will illustrate the priority level group. STM32 has 4 bits to define the preempt priority level and the sub-priority level. The priority level group allocates the 4 bits in priority-level register for the priority level numbersofthe preempt priority level and the sub-priority level. For example, 3 bits are for the preempt priority level (There are 2^3=8 levels), and 1 bit is for sub-priority level. (There are 2^1=2 levels)

Stm32cubemx-tutorial-series-exti-5.png

Now, the project of the stm32CubeMX has been configured. You can regenerate a new report and a new code, then compile the program.

Open the file main.c, delete the chapter of lines above the while loop in the main() routine, and make sure the while loop is empty. Add the interrupt callback function in the middle of USER CODE BEGIN 4 and USER CODE END 4 after the file main.c.

/* USER CODE BEGIN 4 */
/**
  * @brief EXTI line detection callbacks
  * @param GPIO_Pin: Specifies the pins connected EXTI line
  * @retval None
  */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if(GPIO_Pin == GPIO_PIN_0)
  {
    /* Toggle LED1 */
    BSP_LED_Toggle(LED1);
  } 
}
/* USER CODE END 4 */

The interrupt function judges whether there is an EXTI line 0 interrupt; if yes, the state of LED1 will switch. The figure below can be found in the STM32F7 data sheet, in which PA0~PK0 are EXTI line 0 interrupt.

Stm32cubemx-tutorial-series-exti-6.png

Compile the program again, and download the compiled code to the Open746-C development board. If the program has no error, you can see the LED1 changes its state every time when pressing the key WAKEUP.

In the following section, we will present the flow of interrupt routine. The body of the main routine is in the while loop. When pressing the key (connected with PA0), the edge sense circuit can detect a rising edge, which triggers the interrupt and set the interrupt flag. And then, the NVIC will judge whether the EXTI0 interrupt has the highest priority level.If yes, execute the EXTI0 interrupt.

Stm32cubemx-tutorial-series-exti-7.png

Before running the interrupt service routine, Contex-M7 core will push the content of the registers and the breakpoint of the main routine in used into the stack (field protection).In the interrupt vector table, the routine will find out the address of EXTI0 interrupt (0x0000 0058) which stores the entrance address of EXTI0 interrupt service function. And then, jump to run the interrupt service function.

Stm32cubemx-tutorial-series-exti-8.png

In the boot file of startup_stm32f746xx.s, we can find the interrupt vector table.

Stm32cubemx-tutorial-series-exti-10.png

In the table above, we can see that the address 0x0000 000 stores stack top address. And the address 0x0000 0004 stores the reset interrupt service function address. The 22th interrupts is EXTI0 interrupt, its address is 22x4 (0x0000 0058). In the interrupt service function file stm32f7xx_it.c, we can find out the service function of EXTI0 interrupt.

/**
* @brief This function handles EXTI line0 interrupt.
*/
void EXTI0_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI0_IRQn 0 */
  
  /* USER CODE END EXTI0_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
  /* USER CODE BEGIN EXTI0_IRQn 1 */
  
  /* USER CODE END EXTI0_IRQn 1 */
}

In the interrupt service function,only the GPIO external interrupt handle function HAL_GPIO_EXTI_IRQHandler() is called, the parameter in used is GPIO_PIN_0 (EXTI0 interrupt). The GPIO external interrupt handle function can clear the interrupt flag, and call the interrupt to callback the function HAL_GPIO_EXTI_Callback(). We only need to refactor the interrupt callback function by adding the application code (In this routine, the application code is switch the LED1 state).

/**
  * @brief  This function handles EXTI interrupt request.
  * @param  GPIO_Pin: Specifies the pins connected EXTI line
  * @retval None
  */
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

After executing the interrupt service function, the core will remove the register data pushed in the stack to recover filed, pull out the main routine break point address and switch tothe break point address to run the main routine.

OK, here we finish the interrupt service. As you can see, when the interrupt is triggered, the hardware identify the interrupt flag, and the NVIC check the interrupt priority level and judge whether execute this interrupt.In case that the interrupt can be executed, the current state of the routine should be protected at first by pushing the relative data into the stack. After finished the interrupt service function, the data will be pulled out from the stack to recover the filed, and allow the routine jump back to the main routine. If there is an interrupt with higher priority level in the interrupt service function, the current running data will be save, so as to execute the interrupt service function with higher priority level, which we call interrupt nesting. When the higher level interrupt is finished, the filed will be recovered to continue to execute the interrupt with lower priority level.

Hope you can get more knowledge about how dose the interrupt routine run by reading this chapter.