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
で指定している TIM1
や TIM6
といった定数は 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) {}
void timer1_cb() {}
本家 Arduino_Core_STM32 の HardwareTimer.h の 2020年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 更新
これも参考にどうぞ。https://t.co/0nvM930hfs
— matsujirushi (@matsujirushi12) May 9, 2020
ということでブログに更新情報が載っていました orz
EoT