8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Wio LTE JP Version(STM32F405RG)で HardwareTimer のタイマー割り込みを行う

Last updated at Posted at 2020-05-09

LTE Cat.1 モデム搭載のマイコンボード "Wio LTE JP Version" は STM32F405RG を搭載しています。

この MCU はハードウェアタイマーを計14個持っており、タイマー割り込み元として利用可能です。ここではハードウェアタイマーによる割り込みを利用する方法を記しておきます。

5/9 更新: TIM_TypeDef 等を指定しなくてもできることが分かったので、その方法に更新しました。詳しくはあとがきで。

2022/1/8 更新: SeeedJP/Arduino_Core_STM32 1.8.0 で、コールバック関数が set::bind() に対応しました。コールバック引数の書き方が変更となっています。

論よりコード

1 秒毎に timer1_cb() が実行される最小コードです。

#include <WioLTEforArduino.h>
WioLTE Wio;

HardwareTimer Timer1(TIM1);

void timer1_cb() {
  SerialUSB.println("=> timer1_cb!");
}

void setup() {
  SerialUSB.begin(115200);
  delay(500);
  SerialUSB.println("START ----");
  Wio.Init();

  Timer1.pause();
  Timer1.setOverflow(1000 * 1000, MICROSEC_FORMAT); // = per 1000 ms
  Timer1.refresh();
  Timer1.attachInterrupt(timer1_cb);
  
  Timer1.resume(); // START
}

void loop() {
}

このように動作します。

解説

setOverflow() で割り込み間隔を設定、 attachInterrupt() でコールバック関数を設定、 resume() でタイマー開始です。
その他のメソッドは HardwareTimer.h を見てください。

調査したこと

setOverflow() の第2引数で割り込み間隔の指定方法を変更

例では MICROSEC_FORMAT を使いましたが HERTZ_FORMAT も利用可能です。名前の通り Hz で指定します。 (定義は ここ)
以下は同じことです。お好きな指定方法をお使いください。

  Timer1.setOverflow(100 * 1000, MICROSEC_FORMAT); // = per 100 ms
  Timer1.setOverflow(10, HERTZ_FORMAT); // = per 100 ms

TICK_FORMAT は結局プリスケーラ―(Prescaler)やクロックから算出するソースとなります。使いたければどうぞ。

複数のハードウェアタイマーを同時に利用

インスタンスを複数作り、それぞれのインスタンスで setOverflow()attachInterrupt() を指定していきます。

#include <WioLTEforArduino.h>
WioLTE Wio;

HardwareTimer Timer1(TIM1);

void timer1_cb() {
  SerialUSB.println("=> timer1_cb!");
}

HardwareTimer Timer6(TIM6);

void timer6_cb() {
  SerialUSB.println("===> timer6_cb!");
}

void setup() {
  SerialUSB.begin(115200);
  delay(500);
  SerialUSB.println("START ----");
  Wio.Init();
  delay(500);
  
  Timer1.pause();
  Timer1.setOverflow(1000 * 1000, MICROSEC_FORMAT); // = per 1 sec
  Timer1.refresh();
  Timer1.attachInterrupt(timer1_cb);
  Timer1.resume();
  
  Timer6.pause();
  Timer6.setOverflow(1200 * 1000, MICROSEC_FORMAT); // = per 1.2 sec
  Timer6.refresh();
  Timer6.attachInterrupt(timer6_cb);
  Timer6.resume();
}

void loop() {
}

計 14 個のタイマーが利用できる

HardwareTimer で指定している TIM1TIM6 といった定数は TIM1 から TIM14 の計 14 個が利用できます。すなわち、同時に14個のハードウェアタイマーを利用できるという事です。

定数は以下のように利用できる機能が異なるようです。

定数 機能名
TIM1, TIM8 Advanced-control timers
TIM3, TIM4, TIM9 ~ TIM14 General-purpose timers
TIM2, TIM5 General-purpose timers (32-bit)
TIM6, TIM7 Basic timers

それぞれ試してみましたが、「~秒に1回割り込む」程度の利用であればすべて同様に利用できました。
機能として何があるのかは STM32F4xx の仕様書 を参照ください。

コールバック関数の引数について

SeeedJP/Arduino_Core_STM32 1.8.0 にて、コールバック関数の引数指定方法が変わりました。

void timer1_cb(HardwareTimer *HT) {}
1.8.0以降
void timer1_cb() {}

本家 Arduino_Core_STM32 の HardwareTimer.h2020年3月の修正 が取り込まれたためです。 (当該コミット)

これにて std::bind()コールバック関数に引数を指定ができるようになっています。

例) resume と pause を二つのタイマーでやり取りする

これまでの内容を踏まえて、二つのタイマーを使ったサンプルです。
二つのタイマーを用意し、片方が5回カウントしたら自分自身を止めつつもう片方のタイマーを動かすのを繰り返します。

#include <WioLTEforArduino.h>
WioLTE Wio;

HardwareTimer Timer1(TIM1);
volatile int t1;

HardwareTimer Timer3(TIM3);
volatile int t3;

void timer1_cb() {
  t1++;
  SerialUSB.print("timer1_cb: "); SerialUSB.println(t1);
  if (t1 > 4) {
    SerialUSB.println("timer1 stopping and timer3 will start");
    Timer1.pause();
    t3 = 0;
    Timer3.resume();
  }
}

void timer3_cb() {
  t3++;
  SerialUSB.print("timer3_cb: "); SerialUSB.println(t3);
  if (t3 > 4) {
    SerialUSB.println("timer3 stopping and timer1 will start");
    Timer3.pause();
    t1 = 0;
    Timer1.resume();
  }
}

void setup() {
  SerialUSB.begin(115200);
  delay(500);
  SerialUSB.println("START ----");
  Wio.Init();
  delay(500);

  Timer1.pause();
  Timer1.setOverflow(500 * 1000, MICROSEC_FORMAT); // = per 500 ms
  Timer1.refresh();
  Timer1.attachInterrupt(timer1_cb);

  Timer3.pause();
  Timer3.setOverflow(1000 * 1000, MICROSEC_FORMAT); // = per 1 sec
  Timer3.refresh();
  Timer3.attachInterrupt(timer3_cb);

  Timer1.resume();
}

void loop() {
}

動作の様子

あとがき

結構いろいろ調べました。

5/9 更新

ということでブログに更新情報が載っていました orz

EoT

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?