
スチームパンク風LEDゴーグル⑤(M5Stamp Picoでタイマー割り込み)
スチームパンク風ゴーグルにLEDマトリクスを仕込んで、ライブの小道具として使おうという計画。前回までに、ゴーグル本体と制御基板が完成して、あとはプログラムを書けば使える、というところまでたどり着いた…。
…たどり着いた…のだけれど、プログラムの作成が少し難航している。
作りたいのは:
表情切り替え(平静/笑い/泣き/怒り)
イルミネーションエフェクト
まばたきアニメーション(一定時間ごと/表情の切り替え時)
外部からWi-Fiで制御
といったごく単純なもので、アニメーション画像の更新には当然のようにタイマー割り込みを使っているのだが、M5Stamp Picoでは、いつも使っているタイマー割り込みのライブラリ(MsTimer2)が使えないので、これらの機能を統合しきれていないのだ。
MsTimer2ライブラリの使えるマイコン(Teensy)では動いているんだけどねえ…。
調べたら、MsTimer2はAVR系のマイコンでしか動かないらしい。M5Stamp PicoはESP系なのだ。こりゃあ作り直しだな…。
M5Stamp(ESP)での割り込み処理
困ったときは、サンプルスケッチを動かすに限る。M5Stampでの割り込み処理は、メニューの「スケッチ例>ESP32>Timer>RepeatTimer」にあった。

サンプルスケッチから、自分のプログラムでは不要なものを削ってコメントを付けていったら、なんだか使い方が分かってきたぞ。
//
// タイマー割り込みを使う際のおまじない
//
hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
//
// タイマー割り込みで呼ばれる関数は専用の宣言が必要
// (きっとそれ用の領域を追加するんだろうな)
//
void ARDUINO_ISR_ATTR onTimer(){
portENTER_CRITICAL_ISR(&timerMux);
//
// ここに処理を書く
//
portEXIT_CRITICAL_ISR(&timerMux);
//
// タイマー到達を知らせる仕組み(セマフォ)
//
xSemaphoreGiveFromISR(timerSemaphore, NULL);
//
// digitalWriteとかは、ここに置いてもいいらしい。
//
}
void setup() {
//
// タイマー割り込みに関するおまじない
//
timerSemaphore = xSemaphoreCreateBinary();
timer = timerBegin(0, 80, true);
//
// タイマー割り込みで呼ばれる関数を実際に登録
//
timerAttachInterrupt(timer, &onTimer, true);
//
// タイマー割り込みを繰り返しアラームに設定
// 期間は、16666マイクロ秒=16.666ミリ秒=1/60秒
//
timerAlarmWrite(timer, 16666, true);
timerAlarmEnable(timer);
}
void loop() {
//
// タイマー到達した場合、if文の中が動く
//
if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
portENTER_CRITICAL(&timerMux);
//
// ここに処理を書く(割り込みの影響を受けないように?)
//
portEXIT_CRITICAL(&timerMux);
}
//
// 普通のループ処理はここに書く
//
}
これをテンプレートにして、自分の処理を書いていけばいいかな。ライブラリ化されていれば4~5行で済むプログラムが、こんなに長くなってるよ。ライブラリがいかに偉大かってことだな。うむ。
プログラムを書く
俺はゲーム屋なんで、描画はモニターの垂直同期割り込み(Vブランク)毎に処理するのが身に染み付いている。今回も同じような仕組みでプログラムを書くことにした。っていうか↑のプログラムでも、タイマーの周期は16.666ms=1/60秒に設定してあるんだよね。いわゆる60fpsってやつだ。ゲーム屋にとっては直感的に分かりやすい設定だといえよう。
割り込みルーチン内では2つの処理を行わせることにした。
ひとつは、背景用フレームバッファ配列と、アニメーション用フレームバッファ配列を合成して、描画用フレームバッファ配列に書き込む処理。要は普通の描画処理だ。
もうひとつは、アニメーションコントローラー。アニメーション用のフラグが立っていたら、あらかじめ定義してあるアニメーション配列を読み出して、アニメーション用フレームバッファに書き込む処理だ。
この2つさえ作ってしまえば、メイン(loop)はアニメーションを指定してフラグを立てるだけでいい。
ほーらできちゃった。
メインは変えたい表情(平静・笑い・泣き・怒り)を指定して、フラグを立てるだけ。ここではdelay文で2秒ごとにフラグを立てている。あとは、Wi-Fiからの制御信号でフラグを立てる処理に変えれば、完成というわけだ。あと一息!
あと少しで完成…だけど…
あと1日ぐらいで完成しそうな勢いだけど、ここで困ったことになってしまった。このLEDゴーグルは、元々ライブの小道具として作っているんだけど、今は11月18日の午前2時55分。肝心のライブは明日(11月19日)なんだよね。
…間に合わねえよ。どーすんだよw
(次回に続く)