STM32 External Interrupt Example LAB

Previous Tutorial Previous Tutorial Tutorial 8 Next Tutorial Next Tutorial
STM32 External Interrupt Pins & Interrupt Latency
STM32 Course Home Page 🏠

 

 

In this LAB, we’ll see how to set up a GPIO pin to be an interrupt pin on the rising, falling, or both edges. And we’ll write the ISR handler for this interrupt, in which we’ll toggle an output pin (e.g. LED). Finally, we’ll check the interrupt response time and interrupt latency.


   Required Components For LABs   

 

All the example code/LABs/projects in the course are going to be done using those boards below.

QTY Component Name 🛒 Amazon.com 🛒 eBay.com
2 BreadBoard Amazon eBay
1 LEDs Kit Amazon Amazon eBay
1 Resistors Kit Amazon Amazon eBay
1 Capacitors Kit Amazon Amazon eBay & eBay
2 Jumper Wires Pack Amazon Amazon eBay & eBay
1 9v Battery or DC Power Supply Amazon Amazon Amazon eBay
1 Micro USB Cable Amazon eBay
1 Push Buttons Amazon Amazon eBay

★ Check The Full Course Complete Kit List

Some Extremely Useful Test Equipment For Troubleshooting:

Affiliate Disclosure: When you click on links in this section and make a purchase, this can result in this site earning a commission. Affiliate programs and affiliations include, but are not limited to, the eBay Partner Network (EPN) and Amazon.com.


   LAB Objectives   

 

LAB Number 3
LAB Title External Interrupt Pins
  • Configure GPIO Output Pin & Input Pin Within CubeMX Tool
  • Configure the input pin to be an interrupt source on the rising edge
  • Toggle the output pin when an interrupt is detected within the ISR handler
  • Measure the interrupt response time between event and output change

 


   STM32 CubeMX Configurations   

 

Step1: Open CubeMX & Create New Project

STM32 CubeMX Create New Project

Step2: Choose The Target MCU & Double-Click Its Name

STM32 CubeMX Choose The Part Step

Step3: Click On The Pin You Want To Configure As An Output & Select Output Option

Let it be A8 pin for example! (The LED Pin)

STM32 GPIO Pin Select In CubeMX

Step4: Click On The Pin You Want To Configure As An External Interrupt Input

Let it be A9 pin for example! It’s EXTI line 9 (We’ll connect a push button to it).

STM32 External Interrupt Example

Step5: Go To GPIO Config Tab, And Select The A9 Pin EXTI interrupt edge and pull mode

STM32 External Interrupt Example Code CubeMX

Step6: Open The NVIC Tab And Enable The EXTI line9 Interrupt

STM32 External Interrupt NVIC EXTI Enable

Step7: Open The NVIC Config Tab And Check if you want to change the priority of the EXTI line9 external interrupt or not (Optional Step)

STM32 External Interrupt Example NVIC Config CubeMX

Step8: Set The RCC External Clock Source

STM32 RCC External Clock Selection CubeMX

Step9: Go To The Clock Configuration

Step10: Set The System Clock To Be 72MHz Or Whatever You Want

STM32 Clock Tree Configuration CubeMX

Step11: Name & Generate The Project Initialization Code For CubeIDE or The IDE You’re Using

 

Then, open the project in the IDE you’re using. And head over to the main.c file. So we can start writing the application code and have a look at the initialization code generated by the STM32 CubeMX tool.

 


   The Application Code In CubeIDE   

 

Here is the generated initialization code in the main.c file

#include "main.h"

void SystemClock_Config(void);
static void MX_GPIO_Init(void);

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();

  while (1)
  {

  }
}

Let’s have a look at the MX_GPIO_Init() function, as I wanna point to something in it.
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA8 */
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PA9 */
  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

}

The last couple of lines in this function do the following: configure the EXTI line9 interrupt priority level, and enable its interrupt signal. The mode of the interrupt trigger is selected in the configuration of the input pin itself (on rising edge). And you can change it of course as per the application you’re currently developing.

The ISR that gets called and executed when this interrupt occurs can be found in the stm32f1xx_it.h file, so let’s head over to it now!

/******************************************************************************/
/*           Cortex-M3 Processor Interruption and Exception Handlers          */ 
/******************************************************************************/

void NMI_Handler(void)
{
  /* USER CODE BEGIN NonMaskableInt_IRQn 0 */

  /* USER CODE END NonMaskableInt_IRQn 0 */
  /* USER CODE BEGIN NonMaskableInt_IRQn 1 */

  /* USER CODE END NonMaskableInt_IRQn 1 */
}
// And all other internal exceptions/interrupts handlers
// ..
// ..
// ..
/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f1xx.s).                    */
/******************************************************************************/

void EXTI9_5_IRQHandler(void)   // <----- The ISR Function We're Looking For!
{
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
}

Point the mouse to the function HAL_GPIO_EXTI_IRQHandler() and right-click its name and then open the declaration for it. This will take you to the source file where it’s defined, which is this file stm32f1xx_hal_gpio.c

Here is the function implementation you’ll see in this file.

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); // Clears The Interrupt Flag
    HAL_GPIO_EXTI_Callback(GPIO_Pin);   // Calls The ISR Handler CallBack Function
  }
}

This function clears the interrupt source, then calls the ISR handler callback function. So now, we’ll write our implementation for this callback function in our application (main.c file)

We’ll check the interrupt pin source, then toggle the output GPIO pin in this ISR handler callback. And that’s it for this LAB!

Full LAB Code (main.c)

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();

  while (1)
  {
     // Stay IDLE .. Everything is done in the ISR Handler
  }
}

// EXTI Line9 External Interrupt ISR Handler CallBackFun
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == GPIO_PIN_9) // If The INT Source Is EXTI Line9 (A9 Pin)
    {
	HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8); // Toggle The Output (LED) Pin
    }
}

 


   Prototyping & Testing   

 

Step0: Refer To The Blue Pill Board Schematic & Pinout

Blue pill pinout

Step1: Connect The ST-Link To The USB Port & SWD Pins On Board

STM32 GPIO HAL Led Blinking

Step2: Click The Debug Button To Compile The Code & Flash It To The Board & Start A Debugging Session

Step3: You Can Stop The Debugging Session Or Keep It Going. But You Need To Restart The MCU Once To Run The New Application At The Booting Process.

Download External Interrupt LAB3 Project

The Results For This LAB

Test Video

Interrupt Response Time Measurement On My DSO

  • Blue Trace is the push button input signal
  • Yellow Trace is the LED output pin

They are identical in the normal view as you can see. You can’t see any delay, the response looks immediate and the traces are overlapping.

Interrupt Latency And Interrupt Response Time Measurement STM32 Interrupts

However, after zooming in time division, we can see a little bit of delay between the input button Rise to 1 and the LED state change. It’s measured to be nearly 1.6uSec.

Interrupt Latency And Interrupt Response Time Measurement STM32

This includes the interrupt latency, context switching overhead, and ISR callback procedure as well as the HAL_TogglePin function call. All in all, it’s great response time. You can improve this by directly writing to the GPIO output pin port without using the HAL_GPIO function. This will be a topic for a future tutorial!

 

 

Previous Tutorial Previous Tutorial Tutorial 8 Next Tutorial Next Tutorial

 

Share This Page With Your Network!

Khaled Magdy

I'm an embedded systems engineer doing both Software & Hardware. I'm an EE guy who studied Computer Engineering, But I'm also passionate about Computer Science. I love reading, writing, creating projects and Technical training. A reader by day a writer by night, it's my lifestyle. You can view my profile or follow me via contacts.

You may also like...

Leave a Reply

%d bloggers like this: