cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4R9 GPIO13, 14, 15 EXTI interrupt problem

Du1
Senior

I think I've caused some problem in the way I'm coding this interrupt. For a second I thought it was a pipeline re-entry problem like Clive-Two-Zero described in a different thread, but adding a volatile variable and incrementing it, didn't seem to work.

Does anyone see anything obviously wrong with the code?

This is a project generated from TouchGFX and I'm using GCC to compile. I was unsuccessfull in porting the project to System Workbench or Atollic to take advantage of the in circuit debugger to see exactly what is happening and where it's hanging.

Left and Right comes from a different microcontroller that is handling a quadrature encoder dial. So I know the signal are nice and clean of bouncing (checked with scope). What made me sure it was the interrupt is when I move the left and right output from the microcontroller handling the quadrature encoder to the joystick left and right input of the discovery kit (STM32L4R9I-DISCO), the behavior goes away and I get nice and responsive graphics motions. While if I used the GPIO defined in the code below, the graphics is interrupted and I get lag and premature end of animations.

Thanks for your help!

/**
 * @brief Rotate left received from BLE Dial Board
 */
#define LEFT_PIN                       GPIO_PIN_15   /* PB.15 */
#define LEFT_GPIO_PORT                 GPIOB
#define LEFT_GPIO_CLK_ENABLE()         __HAL_RCC_GPIOB_CLK_ENABLE()
#define LEFT_GPIO_CLK_DISABLE()        __HAL_RCC_GPIOB_CLK_DISABLE()
#define LEFT_EXTI_IRQn                 EXTI15_10_IRQn
/**
 * @brief  Rotate right received from BLE Dial Board
 */
#define RIGHT_PIN                       GPIO_PIN_14   /* PB.14 */
#define RIGHT_GPIO_PORT                 GPIOB
#define RIGHT_GPIO_CLK_ENABLE()         __HAL_RCC_GPIOB_CLK_ENABLE()
#define RIGHT_GPIO_CLK_DISABLE()        __HAL_RCC_GPIOB_CLK_DISABLE()
#define RIGHT_EXTI_IRQn                 EXTI15_10_IRQn
 
uint8_t BSP_JOY_Init(JOYMode_TypeDef Joy_Mode)
{
  uint8_t Status = HAL_OK;
  GPIO_InitTypeDef GPIO_InitStruct;
 
  /* Initialized BSP IO */
  BSP_IO_Init();
  /* Common configuration for GPIO used for joystick SEL */
  SEL_JOY_GPIO_CLK_ENABLE();
  LEFT_GPIO_CLK_ENABLE();
  RIGHT_GPIO_CLK_ENABLE();
//  DEMO1_GPIO_CLK_ENABLE();
//  DEMO2_GPIO_CLK_ENABLE();
  GPIO_InitStruct.Pin   = SEL_JOY_PIN;
  GPIO_InitStruct.Pull  = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
 
  if(Joy_Mode == JOY_MODE_GPIO)
  {
    /* Configure GPIO used for joystick SEL as input */
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(SEL_JOY_GPIO_PORT, &GPIO_InitStruct);
 
    /* Configure other joystick pins */
    BSP_IO_ConfigPin((RIGHT_JOY_PIN | LEFT_JOY_PIN | UP_JOY_PIN | DOWN_JOY_PIN), IO_MODE_INPUT_PU);
  }
  else if(Joy_Mode == JOY_MODE_EXTI)
  {
    /* Configure GPIO used for joystick SEL as input with External interrupt */
    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
    HAL_GPIO_Init(SEL_JOY_GPIO_PORT, &GPIO_InitStruct);
    /* Enable and set corresponding EXTI Interrupt to the lowest priority */
    HAL_NVIC_SetPriority((IRQn_Type)(SEL_JOY_EXTI_IRQn), 0x0F, 0x00);
    HAL_NVIC_EnableIRQ((IRQn_Type)(SEL_JOY_EXTI_IRQn));
 
    /* Configure GPIO used for LEFT as input with External interrupt */
    GPIO_InitStruct.Pin   = LEFT_PIN;
    HAL_GPIO_Init(LEFT_GPIO_PORT, &GPIO_InitStruct);
    /* Enable and set corresponding EXTI Interrupt to the lowest priority */
    HAL_NVIC_SetPriority((IRQn_Type)(LEFT_EXTI_IRQn), 0x0F, 0x00);
    HAL_NVIC_EnableIRQ((IRQn_Type)(LEFT_EXTI_IRQn));
 
    /* Configure GPIO used for RIGHT as input with External interrupt */
    GPIO_InitStruct.Pin   = RIGHT_PIN;
    HAL_GPIO_Init(RIGHT_GPIO_PORT, &GPIO_InitStruct);
    /* Enable and set corresponding EXTI Interrupt to the lowest priority */
    HAL_NVIC_SetPriority((IRQn_Type)(RIGHT_EXTI_IRQn), 0x0F, 0x00);
    HAL_NVIC_EnableIRQ((IRQn_Type)(RIGHT_EXTI_IRQn));
 
    /* Configure other joystick pins */
    BSP_IO_ConfigPin((RIGHT_JOY_PIN | LEFT_JOY_PIN | UP_JOY_PIN | DOWN_JOY_PIN), IO_MODE_IT_HIGH_LEVEL_PD);
    /* Configure IO Expander interrupt */
    MFX_IO_ITConfig();
  }
  else
  {
    Status = HAL_ERROR;
  }
  return Status;
}
 
/**
  * @brief  This function handles External line 10 to 15 interrupt request.
  * @param  None
  * @retval None
  */
volatile int bug; //added this for the pipeline re-entry bug
void EXTI15_10_IRQHandler(void)
{
  if(HAL_GPIO_ReadPin(SEL_JOY_GPIO_PORT, SEL_JOY_PIN)){
    HAL_GPIO_EXTI_IRQHandler(SEL_JOY_PIN);
  }else if(HAL_GPIO_ReadPin(LEFT_GPIO_PORT, LEFT_PIN)){
    HAL_GPIO_EXTI_IRQHandler(LEFT_PIN);
  }else if(HAL_GPIO_ReadPin(RIGHT_GPIO_PORT, RIGHT_PIN)){
    HAL_GPIO_EXTI_IRQHandler(RIGHT_PIN);
  }
  bug++;
}
 
/**
 * @brief  EXTI line detection callback.
 * @param  uint16_t GPIO_Pin Specifies the pins connected EXTI line
 * @retval None
 */
volatile uint32_t selk = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
//  char UserTxPlayBuffer[10] = {0x7E, 0xFF, 0x06, 0x0F, 0x00, 0x01, 0x01, 0xFE, 0xEA, 0xEF};
  switch(GPIO_Pin)
  {
    case MFX_INT_PIN:
      MfxDetectInt();
      break;
      
    case SEL_JOY_PIN:
      joystick_press = JOY_SEL;
//      HAL_UART_Transmit(&UartHandle, (uint8_t*)UserTxPlayBuffer, sizeof(UserTxPlayBuffer), HAL_MAX_DELAY);
      break;
 
    case LEFT_PIN:
      joystick_press = JOY_LEFT;
      mp3_play_track_folder(1,1);
//      HAL_UART_Transmit(&UartHandle, (uint8_t*)UserTxPlayBuffer, sizeof(UserTxPlayBuffer), HAL_MAX_DELAY);
      break;
 
    case RIGHT_PIN:
      joystick_press = JOY_RIGHT;
      mp3_play_track_folder(1,1);
//      HAL_UART_Transmit(&UartHandle, (uint8_t*)UserTxPlayBuffer, sizeof(UserTxPlayBuffer), HAL_MAX_DELAY);
      break;
 
    // case DEMO1_PIN:
    //   joystick_press = JOY_DEMO1;
    //   break;
 
    // case DEMO2_PIN:
    //   joystick_press = JOY_DEMO2;
    //   break;
 
    default:
      break;
  }
 
  return;
}
 
unsigned int Buttons::sample()
{
    int result = joystick_press;
 
    // if (joystick_press == JOY_SEL)
    // {
    //     joystick_press = JOY_NONE;
    // }
    joystick_press = JOY_NONE;
    xQueueReceive(JoyStickEventQueue, &result, (TickType_t)0);
 
    return result;
}

1 ACCEPTED SOLUTION

Accepted Solutions
S.Ma
Principal

In case of non TouchFGX and HAL layer EXTI management, the pending bit is handled by the HAL interrupt so it does not show up easily like this (EXTI on SPI NSS line for slave, and SCK for SPI line activtity):

/**
  * @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)      )       // this is NSS interrupt in slave mode
 
    SPIP_InterruptBasedStateMachine(0);
    return;
  }
 
 while(1);
}
 
 
void SPIP_EnableNSS_EXTI(SPIP_t* pSPIP) {
// PD0 = NSS
  __HAL_GPIO_EXTI_CLEAR_IT(pSPIP->pNSS_Slave->Init.Pin);
  __HAL_GPIO_EXTI_CLEAR_FLAG(pSPIP->pNSS_Slave->Init.Pin);
  HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
 
void SPIP_DisableNSS_EXTI(SPIP_t* pSPIP) {
  HAL_NVIC_DisableIRQ(EXTI0_IRQn);  
}
 
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 */
}

As of the graphics, maybe the interrupt priority/level requires proper level ...

View solution in original post

4 REPLIES 4
S.Ma
Principal

In the ISR don't rely on GPIO level, signals could be glitchy (debouncing).

The ISR is no longer pending IF the EXTI corresponding PR bits sources are all cleared.

Add PR test and clear, then confirm by using GPIO level reading to see if this makes some improvements.

Thanks for the quick reply @S.Ma​ !

while searching for an answer I found code snippets like these:

if(EXTI_GetITStatus(EXTI_Line3)!=RESET)//Judge whether a line break
{
 
Interrupt logic…
 
EXTI_ClearITPendingBit(EXTI_Line3);   //Remove LINE interrupt flag bit
 
}     

However, the project files generated from TouchGFX did not include the header file for finding EXTI_ClearITPendingBit or EXTI_Line3, 4, 5, etc..

An internet search for this header file for the STM32L4R9AI didn't seem to yield anything.

How would you handle figuring out what EXTI_Line caused the interrupt?

Thanks!

S.Ma
Principal

In case of non TouchFGX and HAL layer EXTI management, the pending bit is handled by the HAL interrupt so it does not show up easily like this (EXTI on SPI NSS line for slave, and SCK for SPI line activtity):

/**
  * @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)      )       // this is NSS interrupt in slave mode
 
    SPIP_InterruptBasedStateMachine(0);
    return;
  }
 
 while(1);
}
 
 
void SPIP_EnableNSS_EXTI(SPIP_t* pSPIP) {
// PD0 = NSS
  __HAL_GPIO_EXTI_CLEAR_IT(pSPIP->pNSS_Slave->Init.Pin);
  __HAL_GPIO_EXTI_CLEAR_FLAG(pSPIP->pNSS_Slave->Init.Pin);
  HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
 
void SPIP_DisableNSS_EXTI(SPIP_t* pSPIP) {
  HAL_NVIC_DisableIRQ(EXTI0_IRQn);  
}
 
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 */
}

As of the graphics, maybe the interrupt priority/level requires proper level ...

Thanks for the super fast and detailed explanation! I'm understanding it a bit more now.