M5Stackで高速なセンシングを目指したら苦労した話 - Sat, Dec 24, 2022
Writer: 竹田 大将
M5Stackで高速にデータを入出力するのは大変
この記事は「IoTLT Advent Calendar 2022」の23日目です。
1.M5Stackっていいよね
M5Stackとは、ESP32を搭載したマイコンモジュールで、モノによりますが最初から液晶付いてるし、ボタン付いてるし、スピーカー/マイク、IMUなど初期搭載センサー山盛りで、Wi-FiやBluetoothまで繋がっちゃうというめっちゃ便利な開発機です。
便利さもさることながら、今まで私がIoT工作でよく使っていたRaspberryPiは最近個人では入手しづらいですが、M5Stackは安定して売っています!欲しいなって思ったときに秋葉原で買えます。
そんな入手し安さも相まって、最近は業務の製品開発でも使ったりお気に入りになりつつあるデバイスです。
— 大将(Taisyo) (@T_taisyou) December 21, 2022
2. M5Stackを本格的に使いたかった
M5StackはIoT入門教材にも使われたり、個人的には初心者の勉強向きかなとも思っていたんですが「画面も付いてるし、SDスロット付いてるし、中身ESP32だし、これをベースに組み込みシステム作ってもいいんじゃない?」ということで今までPICとかAVRとかPSoCとかをベースにマイコンから基板起こしてLCDやSDカードドライバなどを自分で書いていたようなシステムのベースをこれに置き換えて、もっと開発を簡単にしよう!と本格的な使用を検討することになりました。
ということで、自作したコントローラーの入力でロボットを操作することを想定して、単純にA/Dで入力した値をそのままD/Aで出すデバイスを試しに作ってみようと思いました。
M5StackにはSDカードスロットや液晶が付いてるので、操作記録をSDに記録したり、今のロボットのパワー出力を画面にかっこよく表示させることも将来的にできるかなと思ってベースにM5を選んでみました。
仕様としては、コントローラ操作(アナログスティックとか)の細かい動きや素早い動きでも反応良くしたかったのと、
処理内容としては「ADCで値を取得して、ちょっと計算して、DACで出すだけ」というマイコンにやらせる仕事にしてはとても簡単だったので希望動作周期は1kHzとしました。
PICマイコンならもっとセンサーやタスクが多くてもこれぐらいの速度でADC->DACできたし、ESP32がコアのM5Stackならバッチリっでしょ。と思っていました。
3. ADC/DACに何を使うか
M5Stack Base V2.6の場合、GPIOで使えるADC, DACはそれぞれ2個ずつで、 扱える電圧は0~3.3V、分解能は12bitで「もうちょっと分解能欲しいときもあるかもだけど、とりあえずまぁいいかなぁ」と思っていたんですが、個体差あるかもしれませんがどうやらノイズが凄いらしいという情報もいくつかあったので、内蔵AD/DAは使わない方向で作ることにしました。
ESP32のADC、元々電圧範囲真ん中以外かなり線形性悪かったような気がします。M5Stack固有でさらにノイズ乗ってる可能性も高いです。
— Kenta IDA (@ciniml) March 4, 2020
M5Stackといえばユニット(センサーなど)がケーブル1本接続するだけで簡単に使えるのが特徴の一つです。
探してみたらADC/DACモジュールもあったので 「これをM5に ちょいと くっつけて、 さっ とコード書いたらもう完成じゃん!!」 とM5の便利さに興奮しつつADC/DACはこれを使うことにしました。
ADCは0〜12V検出で最大分解能16bit、DACは最大分解能12bitで出力電圧0〜3.3Vです。
今回使おうと思っていたM5Stack Basicにはユニットを繋げられる穴が一つしかなかったのでハブも買いました。
将来的にいっぱい繋げることも考えて6ポートに増やせるやつを選びました。
チャンネルの取得制御の仕方はポーリング制御らしいです。
4-1. 速さが足りない - うっかりミス編
ちょっと察しのいい方はすでに先ほど貼った商品ページのスペックからオチが予想できていたかもしれませんが…
速さが足りない!!
それも当たり前、M5StackのADCユニット(中身はADS1100)のサンプルレートはMAX 128Hz
だからです。
仕様を知った時「遅い!!」と思わず最初は言ってしまったが、電子工作ではこれぐらいで十分のことも多くて、私の要求が異常なだけだなと反省。
ともかく、1kHzなんてハナから無理な構成でした。「仕様をちゃんと読んで買いましょう」という初歩的な教訓になりました。
4-2. 速さが足りない - 公式ユニットの限界編
ということでADCをどうしようか考えていたところ、M5Stack用 I/O拡張ユニット2なるものを発見。
なんとこれは1個で、ADCとしても使えるI/Oポートが8個も拡張できるらしい。
中身はSTM32F030マイコンで、データシートを読んでもADCは3.3V 12bit分解能で1MHzのスピードでできそうだったので変換スピードは問題なさそうでした。
標準のWire.h
を使うとI2C通信は高速モードでも400kHz
だが、まぁ今回の 1kHz or 2kHz 要求には耐えられる速度が出るだろうと雑に考えていました。
しかし...
速さが足りない!!
I2C高速モード400kHz
で、公式ライブラリのM5_EXTIO2からデータを読み取る以下の関数を使って時間計測をした。
bool M5_EXTIO2::readBytes(uint8_t addr, uint8_t reg, uint8_t *buffer,
uint8_t length) {
uint8_t index = 0;
// (1)-----------------------------------
_wire->beginTransmission(addr);
_wire->write(reg);
_wire->endTransmission();
// --------------------------------------
// (2)-----------------------------------
if (_wire->requestFrom(addr, length)) {
for (uint8_t i = 0; i < length; i++) {
buffer[index++] = _wire->read();
}
// --------------------------------------
return true;
}
return false;
}
結果は以下の通り。
(1) | (2) | 合計 |
118μs | 299μs | 417μs |
1ポート読み取るのに417μs
もかかっていたら、3ポートも読み取ったら1ms
超えてしまう…
どうも思っていたスペックで動作するような設定になっていなそうだし、変換完了の割り込みとかあればもっと高速に読み取れたりするのにな…とSTM32F030の動作設定を自分でしたくなったが、ファームウェア書き込み済みで埋め込まれているSTM32F030を取り出して自分で書き込み直すのはものすごく面倒だったので結果諦めました・・・
その他にも、
- * DACユニットも読み取りに
183μs
かかる。 - * PaHub2ユニットでポートセレクトして通信するのに
108μs
かかる。 - * 公式ライブラリでの画面描画はとても時間がかかる(これはLovyanGFXで軽減できる)
などなど調査でわかり….
ソフトウェア的にマルチコア/マルチスレッドや割り込みを駆使しても、そもそも公式ユニットの組み合わせで物理的に私が期待する速度で動作させることはできない…という結論に至りました。
5. 解決方法
結果、公式ユニットや公式のライブラリを使って開発することは諦め、いつも使ってるSPI対応ADC/DACであるMCP3204, MCP4922を秋月で買って自分で回路を組んで、ドライバと言うほどのものでもないですが自分で関数を実装して組み上げることにしました。
M5StackでSPIのポートを1つ指定し、複数のADC/DACの扱いはCSを使ってポーリングで制御するようにしました。
一瞬でできました。
入力(AD)4ch/出力(DA)4chで AD->ちょっとした計算->DA しても全然1ms周期で動作します。
6. 結論
M5Stackの公式ユニットでリアルタイムシステムを作るのは期待する条件にもよりますが難しいね。という話でした。
結局回路を組まないといけないことがわかっていれば、作業コスト・金銭的なコスト的に見ても最初からPICなどのマイコンベースで作ってたほうがよかったかも…と思いました。
しかし、M5StackはWi-Fi、Bluetoothも使えて、液晶やSDカードスロットが最初からついてるところが魅力で実際センサーや外部チップとの高精度・高速なやり取りを考えなければ全体的に開発しやすかったので、リアルタイム処理はマイコンに任せて、M5Stackは操作端末として通信で連携させちゃうというリッチ構成もありかなとも思います。
M5Stackをバリバリ使おうという人のなにか参考になればと思います。
では、よきM5Stackライフを〜
関連記事
この記事内の調査の殆どをやってくれた弊社従業員が書いた記事です。
M5Stackで始めるIoT開発入門〜学習リモコン〜