STM32 HAL タイマ割り込みの基礎の基礎
おことわり・前提
- STM32CubeIDEを使った話をします.
- あくまで自分用のメモという目的が主.
- 逐次updateしたり追記したりがあるかもしれません.
本題
- タイマ割り込みを使えるようにする.
- CubeMXで利用したいタイマを有効にする.
- プリスケーラ,カウンタを適切に計算してセット.
- 基本的にtimer clock sourceはinternal clockならAPB系がつかわれるが,どの系でくるかはdatasheet要確認.
- auto preloadをenableにしておくと楽.
- overしたときのcnt resetを自動でやってくれる.
- タイマ割り込みをenableにする.
- 忘れるとハマる.
- どこかで
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.cpp
のstatic void MX_TIMx_Init(void)
あたりの最後で呼び出せばいいと思う.- もちろんmain関数の頭らへん(
MX_TIM3_Init()
が呼ばれたあと)で呼んでももちろん動くはず. - ex.
- もちろんmain関数の頭らへん(
/** * @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)... }