理系的な戯れ

理工学系とくにロボットやドローンに関する計算・プログラミング等の話題を扱って、そのようなことに興味がある人たちのお役に立てればと思っております。

STM32でインターバルタイマ割込み

はじめに

こんにちは、こうへいです。

今回は周期的にモータの回転速度を計測するために、タイマで周期的な割込みを発生して 決めておいた関数を実行できるようになりたいと思います。

以前にも書きましたが、エンコーダはあくまで最初の角度が0の相対的な角度情報しか得られないので 速度を出すためには、パルスを数えて時間経過後の増減量か、パルス間の時間を用いるかによって速度を求めます。

そのため、時間を計測することができなければなりませんので、タイマの使い方とタイマによる周期割り込みを 実現したいと思います。

クロックについて

カウンタをアップカウントするのはマイコンに入力されているクロックですが STM32については外からマイコンに接続された発信器の他に内部のCR発信器が内蔵されていて、使えます。

そして、外部、内部どちらからのクロックもPLLの分周器、逓倍器を通してマイコンのコアやメモリ、ペリフェラル(周辺回路)にクロックが伝わります。 4MHzの水晶が接続されているからと言ってマイコンが4MHzで動いているわけではないわけです。

STM32のクロック周りをブロックで表したものがマニュアルにあるので下図に紹介します。

f:id:kouhei_ito:20200112095547p:plain
STM32クロック周りの回路

これを、STM32CubeMXでは下図の様に設定することができる様です。

f:id:kouhei_ito:20200112102700p:plain
STM32CubeMXクロック関係の設定

クロックの区別
  • 内部
    • 高速 HSI
    • 低速 LSI
  • 外部
    • 高速 HSE
    • 低速 LSE
タイマ(TIM)に入るクロック

クロックのブロック線図をみてもTIMに入るクロックはAPB1かAPB2であろうことはわかるのですが そのどちらであるのかがマニュアル上で見つけられず苦労しましたが、以下の様になる様です

  • APB1 TIM2, 3, 4, 5, 6, 7, 12, 13, 14
  • APB2 TIM1, 8, 9, 10, 11

これらは、RCC_APB1ENRとRCC_APB2ENRと言うレジスタでどのTIMにクロックを供給するかしないかを設定できる様で そこに書いてありわかりました。

NUCLEO-F446REボードのクロック

さて、だいぶクロックのことが判ってきました。

僕が使っているNUCLEO-F446REボードでの実際はどうなのかなと言ったことになりますが。

結論は

8MhzがHSEとして加えられています。

NUCLEO-F446REボードは書き込みデバグ用にST-LINK/V2がくっついていますが、そちらにもう一個STM32F1が乗っかっています。 そのSTM32F1に加えられているクロック8MHzがSTM32F446にも加えられている構成となっています。

クロックの設定

ST-LINKのクロックを外部クロックとしてもらうためにはSTM32CubeMXで以下の様に、RCCの設定でBYPASS Clock Sourceを選択する必要がありそうです。

f:id:kouhei_ito:20200112111106p:plain
RCCの設定

つづいて、以下の様にSTM32CubeMXのクロックの設定で、HSEを選ぶ様にするのと、分周期、逓倍器の設定値を適切にします。 クロックは複雑な経路を通ってコアやペリフェラルに到達するのですが、各関所で出し得る周波数の上限があるらしく、違反するとSTM32CubeMXが色で警告してくれなす。

以下の図の様にSTM32CubeMXでAPB1は84MHzのに設定しました。

f:id:kouhei_ito:20200112111614p:plain
クロック設定

タイマ(TIM)の設定

アップカウンタで周期的に割り込みをかけるだけがしたいので、BasicTimerのTIM6を使いたいと思います。

分周期(プリスケーラ)の設定

84MHzでカウンタが大きくなるので、分周期(プリスケーラ)で小さくします。 8400で割ると84e6/84e2=1e4=10000なので 10KHzでカウントアップしてくれます。

Counter Periodの設定

カウンタがCounter Periodの値と位置すると割り込み等のトリガをかけることができる様です。 例えば1秒間隔にしようと思うと、10kHzでカウントアップしている場合は10000-1です。0から数えるので一つ減らします。

以上の設定をSTM32CubeMXですると

f:id:kouhei_ito:20200112120056p:plain
TIM6の設定

割り込みの有効化

TIM6の設定のNVIC Settingタブを開いてEnableをチェックする。

f:id:kouhei_ito:20200112120913p:plain
割り込みの有効化

タイマ割り込みのコーディング

ここまで来るのに結構時間がかかりました。 しかし、STM32CubeMXがなければ、こんなもんでは済まないでしょう。

いよいよ、コーディングですがここまでしてしまうとHALライブラリで激しく簡単です。

タイマをスタートするには

HAL_TIM_Base_Start_IT(&htim6);

割り込みがかかった時に処理される関数である割り込みハンドラはLEDを トグルするLチカだと、以下の様になります。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static short Led = 1;

    if (htim == &htim6){
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, Led);
        Led = 1 - Led;
    }
}

割り込みハンドラは main.cの中に書いて良いようです。 別のファイルにも同じ名前の関数があるのですがweak修飾子というものがついているそうです。 で、同じ関数が2箇所に存在した場合はweek修飾子がついた方は優先順位が低くなるので ユーザが書いた割り込みハンドラが実行されるみたいです。

タイマ割り込みLチカ

では、コンパイルして書き込んで実行してみました。


タイマ割り込みLチカ

(当初、縦長動画のせいなのか、動画が小さくなりましたが、iMovieで横長に保存→他のソフトで縦長にして保存→youtubeにアップ。という手順でOK)

最初、タイマスタート忘れていて、動かなかったんですが、すぐに気づいて修正したら、うまく行きました。

1秒毎に緑のLEDが点滅しています。

今回のブログの作成とコーディングとビデオ撮影は近くのスタバで実施しました。

おわりに

タイマ割り込みもクリアできました。

今回のタイマ割り込みが、調べて確認しなければならない事がが多く一番時間がかかりました。

その甲斐もあって、モータ実験もすぐにできるところまで来ました。 次回はモータ実験結果を紹介できるかなと思います。

モータのシミュレーションと実際を比較するために、STM32でモータ速度を取得する準備をしてきたわけですが、 ここまででマイクロマウスを走らせるのに絶対的に必要な要素はほとんどやり終えた感があります。

残りは

  • PWM出力
  • ADコンバータの使用
  • スイッチ等の入力処理

だけになりました。

記事の中で、「の様です。」という感じで断定してないところがありますが、これは調べながら、コーディングをしながら記事を書いているためで その時点で、うまく走るか判っていないためです。

今回の記事に関しては、全て間違いなく機能しました。

もう少し頑張ります。