Slide 1

Slide 1 text

M5Unified の紹介 Core, Core2, Tough, StickC/CPlus, CoreInk, Paper, Station, Atom, Stamp… すべてに使える共通ライブラリ

Slide 2

Slide 2 text

登壇者の自己紹介 ・ハンドルネーム : @lovyan03 / らびやん / 古井凡人 ・約25年程 Windows用 業務アプリ開発の会社に在籍。 (稀にマイコン向け案件も…) ・2018年夏頃、個人的にM5Stackを購入、見事にハマる。 ・2020年春頃、自作のグラフィックライブラリ LovyanGFX を公開。 ・2021年春頃より、スイッチサイエンス経由で M5Stack製品のソフト開発を受託。 ・2023年4月、スイッチサイエンスに入社。

Slide 3

Slide 3 text

今回の発表内容の前提条件… ・Arduino 環境 (および ESP-IDF )を対象とします。 ・UIFlow (MicroPython) をお使いの方には直接の関係はありませんが…   今後、UIFlow2.0 に移行する際には、少し関係があります。

Slide 4

Slide 4 text

M5StackをArduinoIDE環境で使用するには? (一般的に知られている手順) ・M5Stack + Arduino というキーワードで検索すると すぐ見つかる手順はこんな感じ。 ・ボードマネージャに Espressif 公式の   (またはM5Stack公式の)  ボード定義をインストールする。 ・ライブラリマネージャで「 M5Stack」  ライブラリをインストールする。

Slide 5

Slide 5 text

M5StackをArduinoIDE環境で使用するには? (一般的に知られている手順) ・ボードの設定と、ライブラリの準備ができたら … ・「M5Stack.h」ライブラリを include すると、  「M5」オブジェクトが使用可能になる。 ・例:画面へのテキスト表示はこんな感じ。⇒ #include void setup() { M5.begin(); } void loop() { M5.update(); M5.Lcd.print("Hello M5Stack!"); }

Slide 6

Slide 6 text

M5StackCore2や他の機種を使用するには? ・「M5Stack」ライブラリは M5StackCore専用。 ・機種ごとに専用のライブラリが個別に用意されており、使い分けが必要。 ・また、使用する機種に合ったボード定義をメニューから選ぶ必要がある。 M5Stack.h M5Core2.h M5Tough.h M5StickC.h M5StickCPlus.h M5CoreInk.h M5EPD.h

Slide 7

Slide 7 text

複数の機種に対応するには? ・基本的には、どの機種で使うかを予め決め、  その機種の専用のコードを書いていく。 ・「複数の機種に対応したい 」と思った場合…  どれをinclude するか、手作業で変更する …? // #include #include // #include // #include void setup() { M5.begin(); } void loop() { M5.update(); M5.Lcd.print("Hello M5Stack!"); }

Slide 8

Slide 8 text

複数の機種に対応するには? ・ボードマネージャの選択に応じて、  ARDUINO_M5STACK_Core2 のような  機種別のdefine値が自動生成される。 ・# if defined で値の有無を判定すれば、  機種別の分岐を作ることができる。 ・うまく書ければ、ひとつのソースで  複数機種に対応することも …一応可能。 #if defined (ARDUINO_M5STACK_Core2) #include #elif defined (ARDUINO_M5Stick_C) #include #elif defined (ARDUINO_M5Stick_C_Plus) #include #else #include #endif

Slide 9

Slide 9 text

複数の機種に対応するには? ・しかし、仕様が異なる部分がたくさんあるため、完全な共通化はとても難しい。  ・LCD搭載モデル・CoreInk・M5Paperの3種類の描画関数が統一されていない。  ・スピーカーがI2Sオーディオ・アナログ・ブザー…と異なる方式になっている。  ・ボタンの数が異なる。また、タッチパネル搭載モデルにはボタンがない。  ・「M5Stackにある あの関数がCore2には無い…!?」という状況が頻繁に生じる。

Slide 10

Slide 10 text

どうにか統一する方法はないか…? ・どの機種でも対応できるソフトを書きたい …と思っても、簡単にはできない。 ・各製品のハードウェア構成の内容を比較していくと、  全く別の構成・仕様になっており、共通点が殆どない。 ・ライブラリを修正するとしても、製品個別にライブラリがあるため数が多い。  全部の相違点を統一化するためのメンテナンスは困難を極める。 ・既に大勢に使われているライブラリの仕様を大幅に変更するのは望ましくない。

Slide 11

Slide 11 text

どうにか統一する方法はないか…? ・どの機種でも対応できるソフトを書きたい …と思っても、簡単にはできない。 ・各製品のハードウェア構成の内容を比較していくと、  全く別の構成・仕様になっており、共通点が殆どない。 ・ライブラリを修正するとしても、製品個別にライブラリがあるため数が多い。  全部の相違点を統一化するためのメンテナンスは困難を極める。 ・既に大勢に使われているライブラリの仕様を大幅に変更するのは望ましくない。 もういっそ  新規に作ろう  ライブラリ

Slide 12

Slide 12 text

というわけで全機種共通の統合ライブラリ 「M5Unified」を作成しました…! ・これひとつで全機種共通! ・ディスプレイがLCDでもEPDでも共通操作! ・スピーカーがI2Sオーディオでもアナログ接続でもブザーでも共通操作! ・Arduino環境だけでなく、ESP-IDF 環境でも使用可能! M5Unified.h M5Unified.h M5Unified.h M5Unified.h M5Unified.h M5Unified.h M5Unified.h

Slide 13

Slide 13 text

というわけで全機種共通の統合ライブラリ 「M5Unified」を作成しました…! ・ATOMS3やSTAMPC3にも対応! ・外部画面にも対応可能! ※UnitRCAはG25orG26が必要  ESP32-S3は非対応 M5Unified.h M5Unified.h M5Unified.h M5Unified.h M5Unified.h M5Unified.h

Slide 14

Slide 14 text

・本体内蔵画面+外部接続画面の複数画面にも対応可能!※RCAはG25orG26が必要、S3は非対応 というわけで全機種共通の統合ライブラリ 「M5Unified」を作成しました…! M5Unified.h M5Unified.h M5Unified.h M5Unified.h M5Unified.h M5Unified.h M5Unified.h

Slide 15

Slide 15 text

・カラーもモノクロも区別なく同じ方法で使用できます! ・自動的にモノクロ減色処理が行われるため、カラー LCDとの違いを気にしなくて OK! 画面がモノクロの場合はどうなるの…?

Slide 16

Slide 16 text

・もちろん外付けスピーカにも対応。  ・HAT SPK  ・HAT SPK2  ・ATOMIC SPK  ・Module RCA  ・Module Display ・上記以外の独自に接続したスピーカも、  設定を少し記述すれば対応可能。 スピーカーが外付けの場合はどうなるの…?

Slide 17

Slide 17 text

UIFlow も v2からM5Unifiedを採用 ・UIFlow (MicroPython) は ESP-IDF 用。Arduino ではビルドできない。 ・M5StackライブラリはArduino用。ESP-IDF ではビルドできない。 ・このため、Arduino用ライブラリとUIFlowの仕様には共通点がなく、別々のものだった。 ・一方、M5UnifiedならArduinoでもESP-IDFでもビルド可能。 ・ただし従来のUIFlowとは仕様が大きく変更となる …。 ・メジャーバージョンを刷新し、 M5Unifiedを採用したUIFlow2の開発をする運びとなった。

Slide 18

Slide 18 text

M5Unifiedを使用するには? ・ライブラリマネージャから “M5Unified” をインストールする。 ・”M5Unified” の依存ライブラリとして “M5GFX” もインストールする。 ※ ArduinoIDE および PlatformIO のライブラリに登録済みです。

Slide 19

Slide 19 text

M5Unifiedを使用するには? ・どの機種でも「#include 」でOK。 ・しかもボード選択で対象機種を間違えていても、  大抵の場合は普通に動作する。  (例:M5StickCを選択してCore2に書いてもOK)  注:16MB Flash設定で4MB Flashモデル機に書いたり、   ESP32-S3,C3 等 異なるMCUを選んだ場合は…   さすがに動作しませんが …。 #include void setup() { M5.begin(); } void loop() { M5.update(); M5.Display.print( "Hello M5Stack!"); }

Slide 20

Slide 20 text

M5Unifiedで後付けの画面を使うには? ・外部画面を使う場合は、  先頭に#includeの記述を追加すると動きます。  ※ M5Unified.hより前に記述が必要。 #include #include #include #include void setup() { M5.begin(); } void loop() { M5.update(); M5.Display.print( "Hello M5Stack!"); }

Slide 21

Slide 21 text

M5Unifiedで複数の画面を使うには? ・複数の画面を使う場合は …  M5.getDisplayCount 関数で画面の数を取得し、  M5.Displays(番号). に対して操作を行えば OK。 #include #include #include #include void setup() { M5.begin(); int c=M5.getDisplayCount(); for(int i=0;i

Slide 22

Slide 22 text

M5Unifiedで音を鳴らすには? ・音の再生も共通に。 ・単純な音であれば、 M5.Speaker.tone 関数。  引数1で周波数、引数2で再生時間を設定。 ・別タスクで動作するので自動的に止まる。 ・右の例はド・ミ・ソの3つの音を順に  500 msec間隔で開始、各音を2秒再生。   ( 和音になります! ) ・最大8音まで重ねることが可能。 #include void setup() { M5.begin(); M5.Speaker.tone(523.251, 2000); delay(500); M5.Speaker.tone(659.255, 2000); delay(500); M5.Speaker.tone(783.991, 2000); }

Slide 23

Slide 23 text

M5Unifiedで後付けスピーカを使うには? ・外部スピーカを使用したい場合は M5.begin 関数の実行時に設定を行えば OK。 #include void setup() { auto cfg = M5.config(); // 使用するスピーカに true を設定する cfg.external_speaker.hat_spk = true; cfg.external_speaker.hat_spk2 = true; cfg.external_speaker.atomic_spk = true; cfg.external_speaker.module_rca = true; cfg.external_speaker.module_display=true; M5.begin(cfg); }

Slide 24

Slide 24 text

複数機種に対応したコードを書くコツ ・どの機種でも使えるライブラリですが … コードを書くときに工夫が必要な部分があります。 ・例えば… ・画面への描画座標は自前で座標計算をする。 ・画面の比率に応じて 画面のレイアウトを切り替える。 ・機種に応じて ボタンの操作方法を切り替える。 ・外部画面の有無によって 描画先を切り替える。

Slide 25

Slide 25 text

複数機種に対応したコードを書くコツ (例:画面中央に円を描くには?) ・例えば、右のコードのような書き方をした場合 …  画面サイズが 320×240 ならば、  狙い通り、画面の中央に表示される。 M5.Display.fillCircle( 160, // 中心X座標 120, // 中心Y座標 60, // 円の半径 TFT_GREEN // 円の色 );

Slide 26

Slide 26 text

複数機種に対応したコードを書くコツ (例:画面中央に円を描くには?) ・しかし画面サイズが異なると …  画面サイズが 320×240 以外では、  位置がずれてしまう。 M5.Display.fillCircle( 160, // 中心X座標 120, // 中心Y座標 60, // 円の半径 TFT_GREEN // 円の色 );

Slide 27

Slide 27 text

複数機種に対応したコードを書くコツ (例:画面中央に円を描くには?) ・計算で求めればOK!  M5.Display.width() : 画面の幅  M5.Display.height() : 画面の高さ  2で割ると中心座標が得られる。 M5.Display.fillCircle( M5.Display.width() / 2, M5.Display.height() / 2, M5.Display.height() / 4, TFT_GREEN );

Slide 28

Slide 28 text

複数機種に対応したコードを書くコツ (例:画面の縦横比で配置を変えるには?) ・例えば、画面を半分に分け、別々の表示をしたい …  しかし、縦長の画面の場合、細長く分割される。  なるべく正方形に近い形に分割するには …? M5.Display.fillRect( 0, 0, M5.Display.width() / 2, M5.Display.height(), TFT_BLUE); M5.Display.fillRect( M5.Display.width() / 2, 0, M5.Display.width() / 2, M5.Display.height(), TFT_YELLOW);

Slide 29

Slide 29 text

複数機種に対応したコードを書くコツ (例:画面の縦横比で配置を変えるには?) ・画面の幅と高さを比較して分岐すれば OK。  横長なら 左右に分割して描画する。  縦長なら 上下に分割して描画する。 if (M5.Display.width() >= M5.Display.height()) { // 画面が正方形~横長の場合 // 左右に分割する描画をする } else { // 画面が縦長の場合 // 上下に分割する描画をする }

Slide 30

Slide 30 text

複数機種に対応したコードを書くコツ (例:画面の縦横比で配置を変えるには?) ・より実践的には…  分岐の中では座標計算のみを行う。 ・描画は分岐の外で行うと、一か所に纏められる。 ・さらに、描画処理を自作関数化しておくと、  呼び出し側の記述をシンプルにできます。 ・この例では fillRect1 と fillRect2 が自作関数。  関数内で、引数の座標に描画すれば OK! int w = M5.Display.width(); int h = M5.Display.height(); int x = 0, y = 0; if (w >= h) { w /= 2; // 描画幅を半分に x = w; // X座標を変更 } else { h /= 2; // 描画高さを半分に y = h; // Y座標を変更 } fillRect1(0, 0, w, h); fillRect2(x, y, w, h);

Slide 31

Slide 31 text

複数機種に対応したコードを書くコツ (例:操作方法を共通化するには?) ・例えばメニュー画面を自作するとき、  「ボタンA」= 左移動  「ボタンB」= 決定  「ボタンC」= 右移動  という操作方法を実装した場合 … if (M5.BtnA.wasClicked()){ // 左移動操作 } if (M5.BtnB.wasClicked()){ // 決定操作 } if (M5.BtnC.wasClicked()){ // 右移動操作 } A B C

Slide 32

Slide 32 text

複数機種に対応したコードを書くコツ (例:操作方法を共通化するには?) ・CoreInkやPaperは そのままでも大丈夫そう。 ・しかしStickC/CPlusにはボタンCがないので、  右移動の操作ができない。  また、できればボタン Aを決定操作にしたい。 A B C A B C A B PWR EXT PWR if (M5.BtnA.wasClicked()){ // 左移動操作 } if (M5.BtnB.wasClicked()){ // 決定操作 } if (M5.BtnC.wasClicked()){ // 右移動操作 }

Slide 33

Slide 33 text

・M5.getBoard関数で機種別に分岐を作れば OK! ・StickC/CPlusの場合のみ判定内容を変えて、  PWR = 左移動 A = 決定 B = 右移動 とする。 A B C A B C A B PWR HAT PWR 複数機種に対応したコードを書くコツ (例:操作方法を共通化するには?) switch (M5.getBoard()) { case m5gfx::board_M5StickC: case m5gfx::board_M5StickCPlus: // StickC/CPlus用の操作判定 // PWR=左移動,A=決定,B=右移動 break; default: // それ以外の機種用の操作判定 // A=左移動,B=決定,C=右移動 break; }

Slide 34

Slide 34 text

・例えばM5StackにModuleDisplayを取り付けても、  M5.Displayに描画すると内蔵画面に描画される。 ・ModuleDisplayが接続されている場合には  そちらに描画できないか …? 複数機種に対応したコードを書くコツ (例:外部画面を優先して使うには?) #include #include void setup() { M5.begin(); M5.Display.print(”which?”); } M5.Display

Slide 35

Slide 35 text

・M5.setPrimaryDisplayType関数を使って、  メインで使いたい画面タイプを指定すれば OK! ※画面が見つからない場合は効果を及ぼさない。 複数機種に対応したコードを書くコツ (例:外部画面を優先して使うには?) #include #include void setup() { M5.begin(); M5.setPrimaryDisplayType({ m5gfx::board_M5ModuleDisplay}); M5.Display.print(”which?”); } M5.Display

Slide 36

Slide 36 text

まとめ… M5Unifiedのメリット・デメリット メリット: ・どの機種でも同じコードで動作でき、複数機種への対応が簡単にできる。 ・実行時に機種判定を行うため、ひとつのバイナリで複数機種に対応できる。 ・Arduino環境でもESP-IDF環境でも、M5Unifiedの機能は同じように呼び出せる。 デメリット: ・名称が製品名と一致していないことや、後発ライブラリであることから、知名度が低い。 ・従来のライブラリと完全互換ではなく、機種固有の機能への対応がまだ万全ではない。 ・起動時に一瞬だけ、機種判別のための信号がGPIOから出ることがある。

Slide 37

Slide 37 text

M5Unifiedを是非ご活用ください! ご清聴、ありがとうございました!