JP7FKFの備忘録

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

STM32 HAL タイマ割り込みの基礎の基礎

おことわり・前提

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

本題

  • タイマ割り込みを使えるようにする.
    • CubeMXで利用したいタイマを有効にする.
    • プリスケーラ,カウンタを適切に計算してセット.
      • 基本的にtimer clock sourceはinternal clockならAPB系がつかわれるが,どの系でくるかはdatasheet要確認.
    • auto preloadをenableにしておくと楽.
      • overしたときのcnt resetを自動でやってくれる. f:id:jp7fkf:20200603210205p:plain
  • タイマ割り込みをenableにする.
    • 忘れるとハマる. f:id:jp7fkf:20200603210212p:plain
  • どこかでHAL_TIM_Base_Start_IT(&htimx); をcallしてtimer interruptをenableにする.

コードを見ていく

  • ./Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_tim.c
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
{
  uint32_t tmpsmcr;

  /* Check the parameters */
  assert_param(IS_TIM_INSTANCE(htim->Instance));

  /* Enable the TIM Update interrupt */
  __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);

  /* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
  tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
  if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
  {
    __HAL_TIM_ENABLE(htim);
  }

  /* Return function status */
  return HAL_OK;
}
  • 基本的にmain.cppstatic void MX_TIMx_Init(void)あたりの最後で呼び出せばいいと思う.
    • もちろんmain関数の頭らへん(MX_TIM3_Init() が呼ばれたあと)で呼んでももちろん動くはず.
    • ex.
/**
  * @brief TIM3 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 39999;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 199;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */
  HAL_TIM_Base_Start_IT(&htim3);
  /* USER CODE END TIM3_Init 2 */

}
  • main.cppにcallbackを書く
    • 複数あるときでも引数で渡される&htimxを見て比較して分岐する.
    • ./Core/Src/main.cpp
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
  if(htim == &htim3)
    HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_0);
  if(htim == &htim14)
    printf("htim14 callback!\r\n");
}
  • 大まかな流れと実装.
    • ./Core/Src/stm32f0xx_it.c
      • それぞれの割り込みハンドラがここにいる.
      • タイマの割り込みハンドラは共通のHAL_TIM_IRQHandler(&htimx) をcallする.
/**
  * @brief This function handles TIM3 global interrupt.
  */
void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_TIM_IRQHandler(&htim3);
  /* USER CODE BEGIN TIM3_IRQn 1 */

  /* USER CODE END TIM3_IRQn 1 */
}
  • ./Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_tim.c
    • HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)は共通のタイマハンドラ.
    • ここでタイマの各種イベントに応じてcallback先を選んでいる.
    • タイマの時間切れ(elasped)の場合update eventとなり,タイマ共通のHAL_TIM_PeriodElapsedCallback(htim)がcallされるが,htimはそれぞれのIRQHandlerで引数として渡したタイマのオブジェクト(address)が入っているのでhtimを見ることでどのタイマによって発生したイベントかを判断できる.
/**
  * @}
  */
/** @defgroup TIM_Exported_Functions_Group7 TIM IRQ handler management
  *  @brief    TIM IRQ handler management
  *
@verbatim
  ==============================================================================
                        ##### IRQ handler management #####
  ==============================================================================
  [..]
    This section provides Timer IRQ handler function.

@endverbatim
  * @{
  */
/**
  * @brief  This function handles TIM interrupts requests.
  * @param  htim TIM  handle
  * @retval None
  */
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
{
  ...(snip)...
  /* TIM Update event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
      htim->PeriodElapsedCallback(htim);
#else
      HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
    }
  }
  ...(snip)...
}