STM32 タイマー割り込みをLLで構築する

  • 2021.06.25
  • LL
STM32 タイマー割り込みをLLで構築する

皆さま こんにちは。

今回は LL を使ってタイマー割り込みでLチカしてみます。

LLってな~に?という方は HALとLL の記事をご覧ください。

投稿時の開発環境を記しておきます。

PC:Windows10 OS
IDE: STM32CubeIDE Version1.6.0
Configurator: STM32CubeMX Version6.2.1
Board: STM32Nucleo-F401RE

タイマー割り込みとは?

定期的に行いたい仕事がある場合にタイマー割り込みを使います。
例えばHALの時間管理では1msecのカウンタを使っています。
このカウンタの計数を行うために1msec毎の割り込み処理が行われています。

プロジェクトを作成する

IDEを起動し、File- New – STM32 Project を選択し、Target Selection ウィンドウが出たら Board Selector タブを選択し Boards List から NUCLEO-F401RE を選択し Next ボタンを押します。

Project 名に F401TimerLL と入力し、Finishボタンを押します。
Initialize all peripherals with their default Mode ? と聞いてくるので Yesを押します。

タイマー動作の仕様を決める

タイマー2(TIM2)を使って1秒毎にLEDを点滅することにします。

TIM2をLLで使う準備をする

Project Managerタブを選択し Advanced Settings を見ると TIM の項目がありません。

そこでまず Pinout & Configuration でTIM2を有効にしてみます。

Pinout & Configuration – Categories – Timers – TIM2 を選択し、Mode – Clock Source で Internal Clock を選択します。

そのままProject Managerタブを選択し Advanced Settings を見ると TIM の項目が追加されています。

TIM の右側のHALの部分をクリックするとコンボボックスのリストが表示されるので、LLを選択します。

この状態で、一度ビルドしておきます。

パラメーターを設定する

まずTIM2の割り込みを有効にします。
Pinout & Configuration – Categories – Timers – TIM2 を選択し Mode の Clock Source が Internal Clock になっていることを確認します。
(先ほど設定した内容です)

次に、その下の Configuration の NVIC Settingsタブの TIM2 gloval interrupt の Enabled にチェックを入れます。

次に Parameter Settings タブを選択し Counter Settingsのパラメータを以下の通りに設定します。

Prescaler : 83
Counter Mode : Up
Coutner Period : 999999
Internal Clock Division : No Division
auto-reload preload : Enable

設定した画像を貼っておきます。

設定した値について説明しておきます。

STM32F401のリファレンスマニュアル(RM0368)よりTIM2は32ビットのカウンタを持っています。
TIMによっては16ビットのカウンタの場合もあるので注意してください。

タイマーの周期 T [秒]は以下の式で求めることができます。
f はタイマーに供給されるクロック[Hz]です。

T = プリスケーラ * カウンタピリオド * 1/f [秒]

STM32の場合、プリスケーラとカウンタピリオドはカウント始まりが0なので、設定する値は -1 する必要があります。

fは84MHzですから周期は以下の式から求めることができます。

T = 84 * 1000000 * 1/84M = 1[秒]

クロックを確認する

隣の Clock Configurationタブを選択するとクロックの系統図を見ることができます。

データシートを確認するとわかりますがTIM2はAPB1バスに接続されています。

系統図よりクロックは 84MHz であることが確認できました。

コーディングする

これまでの設定で生成されるコードだけでは割り込みハンドラに飛んできてくれないのでmain.cのMX_TIM2_Init()の最後に以下の2行を追加します。
USER CODE BEGIN と END の間に記述します。

/* USER CODE BEGIN TIM2_Init 2 */
LL_TIM_EnableCounter(TIM2);
LL_TIM_EnableIT_UPDATE(TIM2);
/* USER CODE END TIM2_Init 2 */

デバッグしながら初期設定を終えた後のレジスタの値を、リファレンスマニュアルのレジスタ設定と比較して何が足りないのか確認していきます。

私の場合レジスタの設定は Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_timh や \Src\stm32f4xx_ll_timc を眺めながら、どのAPIを使えば良いか探しています。

まず LL_TIM_EnableCounter(TIM2) でカウンタを有効にしています。
これは CR1レジスタのビット0をセットする関数です。

次に LL_TIM_EnableIT_UPDATE(TIM2) で更新割り込みを有効にしています。
これは DIERレジスタのビット0をセットする関数です。

続いてCore\Src\stm32f4xx_it.cのTIM2_IRQHandler()に以下のコーディングを行います。

void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */

  /* USER CODE END TIM2_IRQn 0 */
  /* USER CODE BEGIN TIM2_IRQn 1 */
  if (LL_TIM_IsActiveFlag_UPDATE(TIM2))
  {
    LL_TIM_ClearFlag_UPDATE(TIM2);
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
  }
  /* USER CODE END TIM2_IRQn 1 */
}

これはステータスレジスタの更新割り込みフラグをチェックして、フラグが立っていたらクリアしてからLEDへの出力ポートを反転します。

ビルドして実行する

それではビルドしてエラーがないことを確認して動かしてみましょう。

こちらでは、めでたくLチカが確認できました。

皆さまは いかがでしたか?

同じ作業を HAL でも試してみました。
ビルドアナライザーで確認したRAMとFlashの消費量(単位[KB])は以下のとおりです。
さほど大きな差はないので、どちらを使っても良さそうですね。

ライブラリ RAM Flash
HAL 1.68 9.62
LL 1.61 8.26

お疲れさまでした。

LLカテゴリの最新記事