cancel
Showing results for 
Search instead for 
Did you mean: 

EXTI Interrupt Not Triggering on STM32-G0B1RE (Hardware and Software Triggers Fail, SysTick Works)

auuais
Associate

Body:

Hello STM32 Community,

I’m facing an issue with EXTI interrupts on my Nucleo-G0B1RE board (STM32G0B1RE). The EXTI interrupt doesn’t trigger, even though the configuration appears correct, and I’ve tested both hardware and software triggers. I’ve tried multiple pins (PA0, PA1, PA8, PC13) and created a fresh STM32CubeMX project, but the issue persists. The SysTick interrupt works fine, indicating that the interrupt system is partially functional. I’d appreciate any insights or suggestions to resolve this issue.

Problem Description

I’m trying to set up an EXTI interrupt on PA0 to trigger on a rising edge. PA0 is configured with a pull-down resistor, and I toggle it by connecting it to VDD (3.3V) to generate a rising edge. The GPIO input works (PA0 detects voltage changes), but the EXTI interrupt never triggers. I’ve also tried forcing a software EXTI interrupt using EXTI->SWIER1, but that doesn’t work either. However, the SysTick interrupt works perfectly, so the issue seems specific to EXTI.

Hardware and Software Setup

  • Board: Nucleo-G0B1RE (STM32G0B1RE)
  • IDE: STM32CubeIDE (latest version as of March 2025)
  • Project: Generated a fresh project using STM32CubeMX
  • Pin Configuration:
    • PA0: EXTI interrupt, rising edge, pull-down resistor
    • Green LED (PA5): Output to toggle on interrupt
    • USART2 (PA2/PA3): For debug output at 115200 baud
  • Previous Tests: I’ve tested EXTI on PA0, PA1, PA8, and PC13 (user button), but none of them trigger the interrupt.

    Steps Taken and Results

    EXTI Interrupt Test on PA0

    I configured PA0 as an EXTI interrupt pin with a rising edge trigger and a pull-down resistor. I toggle PA0 by connecting it to VDD (3.3V) to generate a rising edge. The code includes debug output to confirm the EXTI configuration and PA0’s state.

    Code:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <string.h>
#include <stdio.h>

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* EXTI interrupt callback for PA0 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == GPIO_PIN_0) {
        // Toggle the green LED to indicate interrupt
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);  // Green LED on PA5 for Nucleo-G0B1RE
        // Print a message over UART
        char msg[50];
        strcpy(msg, "EXTI interrupt triggered on PA0!\r\n");
        HAL_UART_Transmit(&huart2, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
    }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_USART2_UART_Init();
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */

  /* Explicitly enable global interrupts */
  __enable_irq();

  /* Print a startup message */
  char msg[50];
  strcpy(msg, "Starting EXTI interrupt test on PA0...\r\n");
  HAL_UART_Transmit(&huart2, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);

  /* Debug: Check if global interrupts are enabled */
  if (__get_PRIMASK() == 0) {
      strcpy(msg, "Global interrupts are enabled\r\n");
  } else {
      strcpy(msg, "Global interrupts are DISABLED!\r\n");
  }
  HAL_UART_Transmit(&huart2, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* Print PA0 state for reference */
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
        strcpy(msg, "PA0 is HIGH\r\n");
    } else {
        strcpy(msg, "PA0 is LOW\r\n");
    }
    HAL_UART_Transmit(&huart2, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
    HAL_Delay(500);  // Check every 500 ms
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
  RCC_OscInitStruct.PLL.PLLN = 8;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART2 Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief GPIO Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  /* USER CODE BEGIN MX_GPIO_Init_1 */
  /* Debug: Confirm we entered MX_GPIO_Init */
  char msg[50];
  strcpy(msg, "Entered MX_GPIO_Init\r\n");
  HAL_UART_Transmit(&huart2, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
  /* USER CODE END MX_GPIO_Init_1 */

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

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);  // Green LED on PA5

  /*Configure GPIO pin : B1_Pin (PC13) */
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;  // Trigger on rising edge
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;        // Pull-down to ensure a known state
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PA5 (Green LED) */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

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

  /* Debug: Confirm EXTI is enabled */
  if (NVIC_GetEnableIRQ(EXTI0_1_IRQn)) {
      strcpy(msg, "EXTI0_1_IRQn is enabled\r\n");
  } else {
      strcpy(msg, "EXTI0_1_IRQn is NOT enabled!\r\n");
  }
  HAL_UART_Transmit(&huart2, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);

  /* Debug: Confirm EXTI line is configured */
  if (EXTI->IMR1 & EXTI_IMR1_IM0) {
      strcpy(msg, "EXTI line 0 interrupt is unmasked\r\n");
  } else {
      strcpy(msg, "EXTI line 0 interrupt is masked!\r\n");
  }
  HAL_UART_Transmit(&huart2, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);

  /* Debug: Check EXTI rising edge trigger */
  if (EXTI->RTSR1 & EXTI_RTSR1_RT0) {
      strcpy(msg, "EXTI line 0 rising edge trigger is enabled\r\n");
  } else {
      strcpy(msg, "EXTI line 0 rising edge trigger is NOT enabled!\r\n");
  }
  HAL_UART_Transmit(&huart2, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);

  /* USER CODE BEGIN MX_GPIO_Init_2 */
  /* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* EXTI interrupt handler for lines 0 and 1 */
void EXTI0_1_IRQHandler(void) {
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @PAram  file: pointer to the source file name
  * @PAram  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
Output:

Entered MX_GPIO_Init
EXTI0_1_IRQn is enabled
EXTI line 0 interrupt is unmasked
EXTI line 0 rising edge trigger is enabled
Starting EXTI interrupt test on PA0...
Global interrupts are enabled
PA0 is LOW
...
PA0 is HIGH
PA0 is HIGH
PA0 is LOW​

 

Observation:

  • PA0 detects voltage changes (LOW to HIGH transitions), confirming the GPIO input works.
  • The EXTI configuration is correct (NVIC enabled, EXTI line unmasked, rising edge trigger enabled).
  • However, the EXTI interrupt doesn’t trigger (no EXTI interrupt triggered on PA0! message, and the green LED doesn’t toggle).
1 ACCEPTED SOLUTION

Accepted Solutions
Karl Yamashita
Principal

The HAL_GPIO_EXTI_IRQHandler doesn't have a call to HAL_GPIO_EXTI_Callback, which you are using.

Instead, it calls either HAL_GPIO_EXTI_Rising_Callback or HAL_GPIO_EXTI_Falling_Callback

 

 

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if (__HAL_GPIO_EXTI_GET_RISING_IT(GPIO_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_RISING_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Rising_Callback(GPIO_Pin);
  }

  if (__HAL_GPIO_EXTI_GET_FALLING_IT(GPIO_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_FALLING_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Falling_Callback(GPIO_Pin);
  }
}


__weak void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);

  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Rising_Callback could be implemented in the user file
   */
}

/**
  * @brief  EXTI line detection callback.
  * @PAram  GPIO_Pin Specifies the port pin connected to corresponding EXTI line.
  * @retval None
  */
__weak void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);

  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Falling_Callback could be implemented in the user file
   */
}

 

Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.

View solution in original post

3 REPLIES 3
Sarra.S
ST Employee

Hello @auuais, thank you for the detailed explanation! 

Before diving deep into the behavior you're observing, could you try and run this example to make sure it is functional on your side: 

STM32CubeG0/Projects/NUCLEO-G0B1RE/Examples/GPIO/GPIO_EXTI at master · STMicroelectronics/STM32CubeG0 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Karl Yamashita
Principal

The HAL_GPIO_EXTI_IRQHandler doesn't have a call to HAL_GPIO_EXTI_Callback, which you are using.

Instead, it calls either HAL_GPIO_EXTI_Rising_Callback or HAL_GPIO_EXTI_Falling_Callback

 

 

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if (__HAL_GPIO_EXTI_GET_RISING_IT(GPIO_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_RISING_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Rising_Callback(GPIO_Pin);
  }

  if (__HAL_GPIO_EXTI_GET_FALLING_IT(GPIO_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_FALLING_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Falling_Callback(GPIO_Pin);
  }
}


__weak void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);

  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Rising_Callback could be implemented in the user file
   */
}

/**
  * @brief  EXTI line detection callback.
  * @PAram  GPIO_Pin Specifies the port pin connected to corresponding EXTI line.
  * @retval None
  */
__weak void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);

  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Falling_Callback could be implemented in the user file
   */
}

 

Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.

Thank you!
That actually was the problem and replacing with the right call, it solved.