STM32 - Interrupt === ###### tags: `firmware_hardware` `electrical_system` `NTURT` #### Author: @andre-liang ![](https://i.imgur.com/P37qXYD.jpg) ### Preface ![](https://i.imgur.com/R3hgCCN.png) Above is the flowchart of the polling model, as you can see when CPU is waiting, for its peripheral to be ready, the cpu cannot do other tasks, which wastes both time and computation resource. By utitlizing interrupts, we can execute code at the exact moment when the event is triggered. In this tutorial, we will learn about external interrupts (a.k.a. EXTI), which trigger the interrupt by the voltage change of GPIO pins. ### Setup First, we need to sepcify witch pin to act as a interrupt trigger. Open `<project-name>.ioc` and toggle the pin to EXTI mode (we use PB1 as a example). ![](https://i.imgur.com/gG3UaeW.png) Also I recommand you to attach a label to the pin, it will be helpful later on. ![](https://i.imgur.com/vvqzvJi.png) **Then, remenber to enable EXTI line in the NVIC control panel.** ![](https://i.imgur.com/gn4CZAX.png) NVIC (Nested Vectored Interrupt Controller) is a device which the priority of different interrupts, in case multiple interrupts happens at the same time. Finally, save the `<project-name>.ioc` file and let the CubeIDE to auto-generate the code. ### Callback Function After setting up the EXTI, we also need to define the function to be excute when the interrupt was triggered. We can define the function in `Core/Src/main.c`, after the EXIT setup (generated by the IDE). ```cpp /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI1_IRQn); ``` The function must be `HAL_GPIO_EXTI_Callback(uint16_t)`, input argument is which EXTI pin was triggered. Here is one example: ```cpp /* USER CODE BEGIN 4 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == LED_PIN_Pin) { LED_value = (LED_value + 1) % 3; output_LED(LED_value); } } /* USER CODE END 4 */ ``` ### Example Let's say we want a LED to change color every 1 second. Also we want to have a button to change the color instantly, but the time interval is not affected. We can use EXTI to detect the button signal and delay in the mainloop, so that even the button is pressed during the `HAL_Delay(1000)`, we can still change the internal LED value. Here is the code implementation (in `Core/Src/main.c`): ```cpp /* USER CODE BEGIN 0 */ int LED_value = 0; void HAL_GPIO_EXTI_Callback(uint16_t); void output_LED(int inputValue) { HAL_GPIO_WritePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_RESET); if (inputValue == 0) { HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_SET); } else if (inputValue == 1) { HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET); } else if (inputValue == 2) { HAL_GPIO_WritePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin, GPIO_PIN_SET); } return; } /* USER CODE END 0 */ ``` ```cpp /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { LED_value = (LED_value + 1) % 3; output_LED(LED_value); HAL_Delay(1000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ ``` ```cpp /* USER CODE BEGIN 4 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == LED_PIN_Pin) { LED_value = (LED_value + 1) % 3; output_LED(LED_value); } } /* USER CODE END 4 */ ``` And the result looks like this: https://drive.google.com/file/d/1gGBn8bcynzQKBaHEqXWAxpqkl3uxHWKV/view?usp=sharing ### Conclusion In this tutorial, we only introduced the external interrupt, but there are also other kinds of interrupt for Timer, ADC, DMA... Interrupt is an essencial tool for the microcontroller to interact with the physical world, and you will see them alot afterward!