概要
もともとM5StickCの互換ライブラリを準備していたのですが、らびやんさん作成の高速LCDライブラリのLovyanGFXが複数ボードの自動認識機能が実装されたのでM5StickC風のライブラリで、M5シリーズを単独ソースの単独バイナリで同時開発できるものを作ってみました。
対応表
ボード | LCD/LED | 電源管理 | IMU | RTC | ボタンA | ボタンB | ボタンC | Tone |
M5StickC | M5.Lcd LovyanGFX | M5.Axp AXP192 | M5.Imu SH200Q MPU6886 | M5.Rtc BM8563 | M5.BtnA GPIO37 | M5.BtnB GPIO39 | M5.BtnC 電源ボタン | |
M5StickC Plus | M5.Lcd LovyanGFX | M5.Axp AXP192 | M5.Imu MPU6886 | M5.Rtc BM8563 | M5.BtnA GPIO37 | M5.BtnB GPIO39 | 電源ボタン | M5.Beep |
M5Stack BASIC | M5.Lcd LovyanGFX | M5.Power IP5306 | M5.BtnA GPIO39 | M5.BtnB GPIO38 | M5.BtnC GPIO37 | M5.Beep | ||
M5Stack Gray | M5.Lcd LovyanGFX | M5.Power IP5306 | M5.Imu MPU6886 | M5.BtnA GPIO39 | M5.BtnB GPIO38 | M5.BtnC GPIO37 | M5.Beep | |
M5Stack Fire | M5.Lcd LovyanGFX | M5.Power IP5306 | M5.Imu SH200Q MPU6886 | M5.BtnA GPIO39 | M5.BtnB GPIO38 | M5.BtnC GPIO37 | M5.Beep | |
ATOM Lite | M5.dis FastLED | M5.BtnA GPIO39 | ||||||
ATOM Matrix | M5.dis FastLED | M5.Imu MPU6886 | M5.BtnA GPIO39 | |||||
ATOM Echo | M5.dis FastLED | M5.BtnA GPIO39 | ||||||
TTGO T-watch | M5.Lcd LovyanGFX | M5.Imu BMA423 | M5.Rtc BM8563 | M5.BtnA GPIO36 |
ちょっと大きな表になってしまいましたが、対応表になります。
利用ライブラリ
外部ライブラリ
LovyanGFX
ボード自動判定機能付きのLCDライブラリです。既存のTFT_eSPIライブラリとの互換性はありますので、ほぼ同じイメージで利用可能です。
FastLED
ATOMでのLED制御で利用しています。既存ライブラリと同じなので特に変わりはありません。
I2C_AXP192
M5StickCの電源管理などで使われているAXP192の単独ライブラリはなかったので、自作しました。既存との互換性は考えずに、単独で使いやすいように作っています。
I2C_MPU6886
こちらもM5StickCの6軸IMU用ライブラリを自作しました。
I2C_BM8563
こちらもM5StickCのRTC用ライブラリの自作ですが、そもそも他のRTCコンパチだったので既存ライブラリが使えた気がします、、、
内蔵ライブラリ
I2C_SH200Q
古いM5StickCなどで使われている6軸IMUですが、あまり利用例がないので独立ライブラリではなく内蔵させています。
I2C_IP5306
M5Stackで使われている電源管理ライブラリです。もともとはモバイルバッテリーなどの管理用ICなのでAXP192と比べるとかなり機能が少ないです。
I2C_BMA423
TTGO T-watchの3軸IMUです。M5シリーズではないのですが、対応できそうなので作ってみました。
使い方
ライブラリマネージャーに登録済みなので、「ESP32LitePack」で検索してください。
インストールするときに、必要なライブラリも一緒にインストールするかと聞かれるので「Install all」を選んでください。
ちなみにM5StickCやM5Stackの既存ライブラリは必要ありません。公式ライブラリには依存せずに互換ライブラリを構築しています。
スケッチ例
#include "M5Lite.h"
void setup() {
M5.begin();
M5.Axp.ScreenBreath(10);
Serial.printf("Lcd Width=%d, Height=%d\n", M5.Lcd.width(), M5.Lcd.height());
M5.Imu.Init();
Serial.printf("IMU : %d\n", M5.Imu.imuType);
M5.dis.drawpix(0, CRGB(255, 0, 0));
M5.dis.drawpix(2, CRGB(0, 255, 0));
M5.dis.drawpix(4, CRGB(0, 0, 255));
M5.dis.drawpix(6, CRGB::White);
// Not Support(ESP_LOGE)
//M5.Axp.GetWarningLevel();
}
void loop() {
static int vol = 11;
M5.update();
M5.Lcd.setCursor(0, 4, 1);
M5.Lcd.printf("M5Lite\n");
M5.Lcd.printf("Battery\n");
M5.Lcd.printf(" Temp :%6.1f\n", M5.Axp.GetTempInAXP192()); // AXP192 Internal temperature
M5.Lcd.printf(" V(V) :%6.3f\n", M5.Axp.GetBatVoltage()); // Battery Voltage(3.0V-4.2V)
M5.Lcd.printf(" I(mA):%6.1f\n", M5.Axp.GetBatCurrent()); // Battery Current(+:charge, -:decharge)
M5.Lcd.printf("ASP\n");
M5.Lcd.printf(" V(V) :%6.3f\n", M5.Axp.GetAPSVoltage()); // ESP32 Voltage
M5.Lcd.printf("VBus(USB)\n");
M5.Lcd.printf(" V(V) :%6.3f\n", M5.Axp.GetVBusVoltage()); // USB Voltage
M5.Lcd.printf(" I(mA):%6.1f\n", M5.Axp.GetVBusCurrent()); // USB Current
M5.Lcd.printf("VIN(5V-In)\n");
M5.Lcd.printf(" V(V) :%6.3f\n", M5.Axp.GetVinVoltage()); // 5V IN Voltage
M5.Lcd.printf(" I(mA):%6.1f\n", M5.Axp.GetVinCurrent()); // 5V IN Current
if (M5.Imu.imuType != 0) {
float ax;
float ay;
float az;
float gx;
float gy;
float gz;
float t;
M5.Imu.getAccelData(&ax, &ay, &az);
M5.Imu.getGyroData(&gx, &gy, &gz);
M5.Imu.getTempData(&t);
Serial.printf(" %f,%f,%f,%f,%f,%f,%f\n", ax, ay, az, gx, gy, gz, t);
M5.Lcd.printf(" Accel Gyro\n");
M5.Lcd.printf("X%5.2f%7.1f\n", ax, gx);
M5.Lcd.printf("Y%5.2f%7.1f\n", ay, gy);
M5.Lcd.printf("Z%5.2f%7.1f\n", az, gz);
}
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
M5.Rtc.GetTime(&RTC_TimeStruct);
M5.Rtc.GetData(&RTC_DateStruct);
M5.Lcd.printf("%04d-%02d-%02d\n", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date);
M5.Lcd.printf("%02d:%02d:%02d\n", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
if (M5.BtnA.wasPressed()) {
Serial.println("M5.BtnA.wasPressed()");
M5.Beep.tone(1000, 100);
}
if (M5.BtnB.wasPressed()) {
Serial.println("M5.BtnB.wasPressed()");
vol--;
M5.Beep.setVolume(vol);
Serial.printf("vol = %d\n", vol);
}
if (M5.BtnC.wasPressed()) {
Serial.println("M5.BtnC.wasPressed()");
vol++;
M5.Beep.setVolume(vol);
Serial.printf("vol = %d\n", vol);
}
if (M5.BtnA.wasReleased()) {
Serial.println("M5.BtnA.wasReleased()");
}
if (M5.BtnB.wasReleased()) {
Serial.println("M5.BtnB.wasReleased()");
}
if (M5.BtnC.wasReleased()) {
Serial.println("M5.BtnC.wasReleased()");
}
delay(100);
}
M5Lite.hを読み込むことで、M5StickC的なライブラリ構成でプログラムを行うことができます。基本的に利用できないデバイスのクラスを呼んでもエラーにならないようになっています。画面の大きさやボタンの数などで条件わけをする必要はありますが、既存に比べると同一ソースでプログラムをしやすいとは思います。
クラスの紹介
M5クラス
begin()とupdate()関数以外はクラスを持っているだけです。begin()の引数はM5StickCのものを採用していますが、通常は引数無しで実行するだけで良いと思います。
update()関数はBeep.updte()も内部で呼んでいます。
M5.Lcdクラス
LovyanGFXライブラリを利用していますので、互換性はありますがかなりの数の機能が追加されています。既存の機能もかなり高速化されています。
M5.disクラス
ATOMのLED制御クラスです。ほぼ同じラッパークラスを作っているので同じように利用できると思います。ただし、色の並びがおかしいのは修正していますのでCRGB::RedやCRGB(255, 0, 0)は正しく赤く光ります。
M5.Imuクラス
M5StickCのImu自動判定と同じようなことをしています。自動判定自体私がPRして本家に取り込んでもらったので、、、
SH200Q、MPU6886、BMA423を自動判定しています。M5Stack系は自動判定がなかったのでかなり便利に使えるのではないでしょうか?
今後軸が違う可能性があるので、座標系をM5StickCに合わせる改修が入る可能性があります。TTGOのT-watchで使われているBMA423は3軸なんで加速度しか取れませんのでご注意ください。
MahonyAHRSはまだ取り込んでいませんので使えませんので注意してください。MahonyAHRSは単体ライブラリとして存在しているので、そちらを使うのを推奨します。そのうち依存ライブラリに追加して内部に取り込むかもしれません。
M5.Axpクラス
AXP192の既存ライブラリで使いそうな関数のみ実装しています。Sleep系は実装していませんのでご注意ください。
M5.Powerクラス
M5Stackの電源管理クラスです。バッテリー残量取得などは実装していますがスリープ系は未実装です。使える機能が少ないのでAxpクラスに統合するかもしれません。
M5.Rtcクラス
M5StickCとM5StickC Plus、TTGO T-watchで使われているRTCをサポートしています。
M5.BtnA, BtnB, BtnCクラス
ここはM5StickCではなく、M5Stackにそろえています。M5StickCの電源ボタンはM5.Axp.GetBtnPress()ではなく、M5.BtnC.wasReleased()を利用してください。
ATOMとTTGO T-watchは物理的にボタンが1つしかないので、BtnAのみになります。
M5.Beepクラス
M5StackC PlusのBeepクラスをベースにしています。M5StackはSpeakerクラスだったので注意してください。M5Stackは爆音か変な音だったのであまり使っている人がいないのでしょうか?
M5Stackは、M5StackC Plusと同じぐらいの大きさのクリアな音がするように調整しました。ただPWMで出力を絞っているだけなので、周波数が変わって音がちょっと違います。。。
Wire1クラス
内蔵しているI2Cにアクセスするクラスになります。こちらはATOMだけピン配置が違うのですがボードの自動判定に応じたピンで初期化してあります。
Groveなどの端子で別系統のI2Cを使う場合にはWireクラスの方を利用してください。M5StackのPortAなどは内部と同じ端子が出ているのでWire1になります。
開発の注意点
開発で利用するボードは常にM5Stick-Cで大丈夫です。シリアルポートだけ利用するボードに変更してください。アップロード速度は1500000のままで、すべてのボードに転送できます。
また、一部サポートしていない関数があるので、Core Debug Levelはエラー以上にしてもらえると、シリアルモニタにで「Not Support」と関数名と一緒に表示されると思います。
まとめ
まだ資料が圧倒的に足りていませんが、M5StickCの開発経験がある人であればそれほど違和感なくM5Stackの開発もできると思います。とにかくシリアルポートを変更することだけで複数のボードで開発できるのは便利です!
当初はM5StickCとM5StickC Plusを同時開発するライブラリの予定だったのですが、LovyanGFXが他のボードも自動判定してくれたのでこんな感じのライブラリになりました。
もともとは個人的に便利なスケッチ例などを入れる予定だったので、ESP32LitePackという名前になっているので、中身と名前がミスマッチなのです、、、
コメント
こ、これはすごい!
らびやんさんといい、たなかさんといい、すごすぎる。
あれ?
M5StackAuto.h ってなくなっちゃいました?
ESP32LitePack を install しても M5Lite 周りだけになっている模様ですが・・・・
すみません。現状中身をちょっと変えてM5Lite.hになっています。。。
Oh……..
画面周りを完全依存で作っていたのでヒャーって状態ですw
基本はM5のままでも動くので、読み込むhファイル名変えるだけのはずです、、、
すみません、、、
勝手にお世話になってます
LovyanGFXライブラリを利用しているということはスプライトにも対応しているのでしょうか?
使い方がわからないので、サンプル提示して頂けたらありがたいです。
いまからM5Lite使うのであれば、ほぼ同じでM5Stack純正であるM5Unifiedをおすすめします
https://github.com/m5stack/M5Unified
どちらも中身はLovyanGFXを使っていますので同じように使えます。
こんにちは!
大変遅くなりましたが、やっとM5STACK Fire に M5Unifiedでのスプライト、WIFI、SDカード、IMU を同時に詰め込むことが出来ました。
情報が少なくて苦労しましたが、たなかさんのHPを読み返してなんとかなりました。
ありがとうございました
よかったです!
いまサウンドも準備しているようでして、もうすぐ使えるようになるみたいです
ありがとうございます
レスポンス悪くてすいません、完成させてお礼のコメントを書こうと思ったのですが、無理でした、、
教えていただいた、M5Unified で 頑張ってましたが、残念ながら今日現在も、うまく動作せずです^^;
マルチタスクで口パクのアイコンとMP3の疑似音声なのですが、どうしてもウオッチドックタイマーが動作してしまって再起動を繰り返します。で、シングルタスク?に切り替えてプログラムを改造してましたが、なかなか難しくて^^;
今日のバージョン0.0.6で、マルチタスク動作は、かなり改善が見られたのですが、ギブアップで、ついつい、らびやんさんに HELPを求めてしまいました、、
LovyanGFX のように、M5Unifiedも、たなかさんの解説記事を楽しみにしていますので、これからもよろしくおねがいします。
おー、でも進捗があるってことはすばらしい!
ちなみにTwitterとかであれば気軽に聞くと教えてくれる人ばかりですので、つまったらHELPは大事だと思います