JP7FKFの備忘録

ヒトは,忘れる生き物だから.

STM32 HAL 外部割り込みの基礎の基礎

おことわり・前提

  • STM32CubeIDEを使った話をします.
  • あくまで自分用のメモという目的が主.
  • 逐次updateしたり追記したりがあるかもしれません.

本題

  • 外部割り込みをするには
    • GPIOをEXTI Interrupt modeにする. f:id:jp7fkf:20200603210148p:plain
    • NVICで該当のEXTI Interruptをenableにする. f:id:jp7fkf:20200603210153p:plain
      • これを忘れるとEXTIされないので注意.ハマりがち.
      • 外部割り込みに限らずなんだけれども,割り込みの優先順位は適切につける.
        • 例えば外部割り込みの中でHAL_Delay()を呼んだりしたいときはTime base: System tick timerより外部割り込みの優先順位を下げないと処理が戻ってこなかったりする.

実際のコードをみて割り込みの流れをみる

  • ./Core/Src/stm32f0xx_it.c
/******************************************************************************/
/* STM32F0xx 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_stm32f0xx.s).                    */
/******************************************************************************/

/**
  * @brief This function handles EXTI line 0 and 1 interrupts.
  */
void EXTI0_1_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI0_1_IRQn 0 */

  /* USER CODE END EXTI0_1_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
  /* USER CODE BEGIN EXTI0_1_IRQn 1 */

  /* USER CODE END EXTI0_1_IRQn 1 */
}
  • 複数のEXTIピンを定義した場合でも同じHAL_GPIO_EXTI_IRQHandler()がcallされる.
/******************************************************************************/
/* STM32F0xx 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_stm32f0xx.s).                    */
/******************************************************************************/

/**
  * @brief This function handles EXTI line 0 and 1 interrupts.
  */
void EXTI0_1_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI0_1_IRQn 0 */

  /* USER CODE END EXTI0_1_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
  /* USER CODE BEGIN EXTI0_1_IRQn 1 */

  /* USER CODE END EXTI0_1_IRQn 1 */
}

/**
  * @brief This function handles EXTI line 2 and 3 interrupts.
  */
void EXTI2_3_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI2_3_IRQn 0 */

  /* USER CODE END EXTI2_3_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
  /* USER CODE BEGIN EXTI2_3_IRQn 1 */

  /* USER CODE END EXTI2_3_IRQn 1 */
}
  • HAL_GPIO_EXTI_IRQHandler()がcallされると割り込みビットの処理が実行され,HAL_GPIO_EXTI_Callback()がcallされる.
    • これがユーザが実際に定義することを想定しているcallback functionである.
    • stm32f0xx_hal_gpio.cですでに__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)という形で定義されているが,__weak指定子がついているので,ユーザがvoid HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)を別で定義した場合それが優先される.
  • ./Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_gpio.c
/**
  * @brief  Handle EXTI interrupt request.
  * @param  GPIO_Pin Specifies the port pin connected to corresponding 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) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

/**
  * @brief  EXTI line detection callback.
  * @param  GPIO_Pin Specifies the port pin connected to corresponding EXTI line.
  * @retval None
  */
__weak void HAL_GPIO_EXTI_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_Callback could be implemented in the user file
   */
}
  • ユーザは実際にvoid HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)を定義して利用することができる.
    • 引数としてGPIO_PINが渡されるので,これを見てどのピンのEXTI割り込みかを判断する.
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
  HAL_Delay(1);
  printf("EXTI callback called!\r\n");
  if (GPIO_Pin == GPIO_PIN_3)
    printf("gpio3 pushed!\r\n");
  if (GPIO_Pin == GPIO_PIN_1)
    printf("gpio1 released!\r\n");
}
  • STM32 external interrupt and tick timer - Programmer Soughte
    • EXTI内部でHAL_Delay()を叩くとすべての処理が停止することがあった.
    • これは割り込み優先度がすべて0となっていたため.
    • HAL_Delay()systickを利用するためこの割り込みの優先度をあげ,EXTI割り込みの優先度を下げる必要がある.
    • これにより無限ループによる処理停止が引き起こされない.