04.M5Tab5でLVGL9テスト
04.M5Tab5でLVGL9テスト
M5Stack Tab5にLVGL v9をインストールし、LVGL_Arduino.inoを修正したAkihiroさんのスケッチを元に、日本語表示とサンプルスケッチも一部確認します。
LVGLの公式ドキュメント
v9.4 (最新) https://docs.lvgl.io/master/v9.3 https://docs.lvgl.io/9.3/
LVGLのVerについて
Arduino-IDEのライブラリマネージャーでの最新はv9.3.0です。1. メジャーVerとは
例:v5.0.0, v6.0.0
互換性の無いAPIの変更
v8.0 発表2021/6
v9.0 発表2024/1 約2年半後
2-3年で最新Verとは互換性がなくなってしまう。
2. マイナーVerとは
例:v6.1.0, v6.2.0
下位互換
サポートは発表後1年
v8.4は、2024/3発表で、2025/3にサポート終了しています。
現在のサポートはv9.3以降です。
3. パッチVerとは
例:v6.1.1, v6.1.2
バグ修正
LVGLのセットアップ
これからの作成は、現在例が色々あるLVGL v8よりも最新のLVGL v9を選びました。LVGLのインストール
Arduino-IDE > ライブラリマネージャー > lvglで検索 > lvgl by kisvegabor 9.3.0 (最新)をインストール設定
1. lv_conf_template.hをリネームしてlibrarisホルダにcopyArduino-IDE > ファイル > 基本設定... > "スケッチブックの場所"
の
c:\Users\.....\Documents\Arduino
より、以下をエクスプローラーで開きます
(続けて)\libraries\lvgl\lv_conf_template.h
そしてこのファイルを
(同じく)\libraries\lv_conf_template.h
にコピーし、リネームして
(同じく)\libraries\lv_conf.h
にします。(lvglのホルダが見れる場所)
2. lv.conf.hを編集
上記ファイルの15行目"#if 0"を"#if 1"に変更し保存
"1"にしないと、このファイルの内容を修正時に有効になりません。
3. サンプルスケッチを使用する場合
lvgl/examples を
lvgl/src/examples にcopyする。
スケッチのVer
・Arduino-IDE 2.3.6・LVGL 9.3.0
・M5Unified 0.2.7
・M5GFX 0.2.9
新しくても古くてもVer違いで動作しなくなることがあります。
スケッチの内容について
スケッチ例でのArduino-IDE > ファイル > スケッチ例 > (カスタムライブラリのスケッチ例) lvgl > arduino > LVGL_Arduino
これは、LVGL初めてではうまく動作しなかったので別を探します。
参考は、「LVGL V9をM5StackCore2で動かしてみる」
https://zenn.dev/akihiro_ya/articles/25f37c3075f4bc
です。これは、LVGL_Arduino.inoを元にしてM5用に書換えたスケッチです。
参考からの変更点
1. 画面変更
M5Stack Tab5の画面サイズは1280x720pxです。さらに、右手で電池部を握るのが楽なので
M5.Display.setRotation(3);
を使用します。LVGLには文字の回転は無いようです。(たぶん)
2. 日本語表示
上で修正した"lv.conf.h"の581行目から下にいろいろなfontの設定があります。589行目 #define LV_FONT_MONTSERRAT_14 1→0
602行目 #define LV_FONT_MONTSERRAT_40 0→1
縦14pxはTab5では小さすぎるの40pxに変更します。
614行目 #define LV_FONT_SOURCE_HAN_SANS_SC_16_CJK 0→1
この特殊fontも使用可とし、日本語表示します。
CJKは、中国・日本・韓国語のフォントです。
C:\Users\.....\Documents\Arduino\libraries\lvgl\src\font\lv_font_source_han_sans_sc_16_cjk.c
に、内蔵文字がそのファイルの最初に記載されています。ただ、縦16pxと小さい文字なのでそれをズーム拡大して表示しますが、多少読みづらくなってしまいます。
632行目 #define LV_FONT_DEFAULT &lv_font_montserrat_40
で、_14→_40 デフォルトは英文用40pxとします。(とりあえず)
今回のスケッチでは、M5GFXのM5.Display.printは使用していません。
3. サンプルの確認
いくつかはコメントを外す事により簡単に確認できます。修正前のスケッチでは、日本語表示のみします。サンプルの確認をする場合は、日本語表示の部分のスケッチ5行をコメントとし(あると重なって表示をしてしまいます)、スケッチ上の
lv_example_...();
のコメントを1つ外して実行します。
サンプルが表示できることを確認し、それぞれやその他のサンプルは深く修正していません。
スケッチ
// LVGL_Arduino.inoが元の
// https://zenn.dev/akihiro_ya/articles/25f37c3075f4bc を修正
// M5.Display.printを使用せず、LVGLにて1行表示 一部サンプルも表示可能
// Arduino-IDE 2.3.6
// LVGL 9.3.0
// M5Unified 0.2.7
// M5GFX 0.2.9
#include <lvgl.h> // LVGL 9.3.0を使用
#include <M5Unified.h> // M5統合ライブラリ SDが先に
#include <examples/lv_examples.h> // 例を使用
// "lvgl/examples" を "lvgl/src/examples" にcopyしておく
//#include <demos/lv_demos.h> // デモを使用 未確認
// "lvgl/demos" を "lvgl/src/demos" にcopyしておく 未確認
#define TFT_HOR_RES 720 // 画面幅 Tab5
#define TFT_VER_RES 1280 // 画面高さ
#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8))
//LVGLはこのバッファに描画を行う、画面サイズの1/10バイト
uint32_t draw_buf[DRAW_BUF_SIZE / 4]; //
#if LV_USE_LOG != 0 // ログを表示するなら デフォルトは0
void my_print(lv_log_level_t level, const char *buf) {
//
LV_UNUSED(level); // 未使用の変数?
Serial.println(buf); // bufをシリアルモニタに表示
Serial.flush(); // 送信完まで待つ
}
#endif
void my_disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
//レンダリングされた画像をdisplayにcopyする自作関数
uint32_t width = (area->x2 - area->x1 + 1); //
uint32_t height = (area->y2 - area->y1 + 1); //
lv_draw_sw_rgb565_swap(px_map, width * height);
// RGB565バッファの上位バイトと下位バイトを入れ替えます(バッファへのポインタ,ピクセル数)
M5.Display.pushImageDMA<uint16_t>(area->x1, area->y1, width, height, (uint16_t *)px_map);
// DMAを使用して画像を効率的に表示(x0,y0,w,h,画像データへのポインタ、通常は16bit RGB565)
lv_display_flush_ready(disp); // 書込完でdisplayドライバから呼出す
}
void my_touchpad_read(lv_indev_t *indev, lv_indev_data_t *data) {
// タッチを取得する自作関数
lgfx::touch_point_t tp; //
M5.update(); // touch状態更新
if (M5.Display.getTouch(&tp)) { // タッチパネルの情報を取得
data->point.x = tp.x; //
data->point.y = tp.y; //
data->state = LV_INDEV_STATE_PRESSED; // 入力デバイスが押された状態
} else { // タッチしていなければ
data->state = LV_INDEV_STATE_RELEASED; // 入力デバイスが解放の状態
}
}
static uint32_t my_tick() { // 経過時間の自作関数
return millis(); // Arduinoのmillis()を使用
}
void setup() {
M5.begin(); // M5初期化
Serial.begin(115200); // シリアルモニタの通信速度
M5.Display.setRotation(3); // LVGLに文字の回転は無いので
String LVGL_Arduino = "LVGL "; // 表示用文字変数
LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.println(LVGL_Arduino); // LVGL V9.3.0 とシリアルモニタに表示
lv_init(); // LVGLライブラリを初期化
lv_tick_set_cb(my_tick); // 経過時間(mS)を取得するためのコールバック関数
#if LV_USE_LOG != 0 // logを表示するなら
// C:\Users\.....\Documents\Arduino\libraries\lv_conf.h の278行目の #defineで0
lv_log_register_print_cb(my_print); //デバッグ用レジスタプリント
#endif
lv_display_t *disp; //
disp = lv_display_create(TFT_HOR_RES, TFT_VER_RES); // 指定解像度で新しいディスプレイを作成
lv_display_set_flush_cb(disp, my_disp_flush);
// レンダリングされたイメージをdisplayにcopyするために呼出されるコールバックを設定
lv_display_set_buffers(disp, draw_buf, nullptr, sizeof(draw_buf), LV_DISPLAY_RENDER_MODE_PARTIAL);
// displayのバッファを設定(displayへのポインタ,バッファ1,バッファ2,buf_size,レンダリングモード)
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_90); // 0と90のみ動作?
lv_indev_t *indev = lv_indev_create(); // 入力デバイスindevの作成
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); //タッチはPOINTERタイプ
lv_indev_set_read_cb(indev, my_touchpad_read);
// 入力デバイスのdataをindevに読込むためのコールバック関数を設定 タッチしてるか タッチx,y値
// C:\Users\.....\Documents\Arduino\libraries\lvgl\src\examples より
// 以下のコメントを1つずつ外して確認
//lv_example_anim_1(); // スライドon/offボタン 画面上部に状態をtxt表示
//lv_example_anim_2(); // 左右に動くボール 大きさも変わる
//lv_example_anim_3(); // スライドバー2本でグラフ変化
//lv_example_anim_4(); // 上記1の表示が1次止まる
//lv_example_anim_timeline_1();// 四角が徐々に小さくなる 下のスライドバーで途中状態で止められる
//lv_example_event_bubble();// ボタンが3行3列表示 スクロールして29まである 押すと青→赤に
//lv_example_event_button();// ボタン状態を表示 クリック,離した,longクリック
//lv_example_event_click(); // 中央にボタン クリックでボタン表示の数字が1加算
//lv_example_event_draw(); // 中央に表示の円のサイズが大きくなったり小さくなったりする
//lv_example_event_streak();// ボタンの連続クリック数を画面上に表示
//lv_example_get_started_1();// 薄い紺の地 中央に白文字
//lv_example_get_started_2();// ボタン基本
//lv_example_get_started_3();// 角ボタンとRのついたボタン
//lv_example_get_started_4();// スライドボタン 上部に0-100の表示
//lv_example_grad_1();// 白から赤までのグラディション
//lv_example_grad_2();// 1行が画面からはみ出て、手でスクロール
//lv_example_grad_3();// 上と同じ NGか?
//lv_example_grad_4();// 上と同じ NGか?
//lv_example_flex_1();// 横スクロールをして10個のボタン、縦スクロールも
//lv_example_flex_2();// 2行3列の四角、スクロールして8個まで表示
//lv_example_flex_3();// 画面に表示 動作わからない?????
//lv_example_flex_4();// 画面に表示 動作わからない?????
//lv_example_flex_5();// 四角内の数字とボタンが揺れている
//lv_example_flex_6();// 2行3列の四角 中は右から左に数字 スクロールして20個の四角
//lv_example_grid_1();// 3x3個のボタン
//lv_example_grid_2();// 四角が重なり合っている NGか?????
//lv_example_grid_3();// 3x3の四角 動作わからない?????
//lv_example_grid_4();// 上と同じ
//lv_example_grid_5();// 3x3の四角 上下に揺れている
//lv_example_grid_6();// 3x3の四角 右から数字
// \libs\..... にて
//lv_example_barcode_1();
//lv_example_bmp_1();// エラー
//lv_example_ffmpeg_1();
//lv_example_ffmpeg_2();
//lv_example_freetype_1();
//lv_example_freetype_2();
//lv_example_freetype_3();
//lv_example_gif_1();
//lv_example_libjpeg_turbo_1();
//lv_example_libpng_1();
//lv_example_lodepng_1();
//lv_example_qrcode_1();
//lv_example_rlottie_1();
//lv_example_rlottie_2();
//lv_example_rlottie_approve();
//lv_example_svg_1();
//lv_example_tiny_ttf_1();// エラー
//lv_example_tiny_ttf_2();// エラー
//lv_example_tiny_ttf_3();// エラー
//lv_example_tjpgd_1();
// \others (13フォルダ) にて
// 略
// \porting\osal にて
//lv_example_osal();// 画面中央にR付青図形
// \porting にて
//lv_example_scroll_1();// 2つのボタンとスクロール
//lv_example_scroll_2();// ボタン 横スクロール 1つずつ移動
//lv_example_scroll_3();// +ボタンで項目追加
//lv_example_scroll_4();// 四角内のtxtを横スクロール
//lv_example_scroll_5();// エラー?????
//lv_example_scroll_6();// NG????? 画面の4割ぐらいが白
//lv_example_scroll_7();// チェックボタン それ以外もある?????
//lv_example_scroll_8();// ボタン横スクロールと縦スクロール
//lv_example_style_1();// ボタンらしき四角
//lv_example_style_2();// 四角内に灰から青へグラディション
//lv_example_style_3();// 四角が飛び出ているように右辺と下辺が青
//lv_example_style_4();// 灰色四角の周りに青い線
//lv_example_style_5();// 灰色四角の周りに青いにじみ
//lv_example_style_6();// 画面半分づつ白黒 中央に図形 NGか?????
//lv_example_style_7();// 円状のスクロール設定
//lv_example_style_8();// 四角内にアンダーライン付文字
//lv_example_style_9();// 白地に灰色のレ点
//lv_example_style_10();// 白四角をタッチで赤茶色、離すと白
//lv_example_style_11();// 青ボタンと黄ボタン 影付き
//lv_example_style_12();// 橙四角 4辺黄緑
//lv_example_style_13();// 赤と水色のスライド設定 タッチで赤が太くなる
//lv_example_style_14();// 青のボタンと緑のボタン
//lv_example_style_15();// ボタンが斜め
//lv_example_style_16();// NG?????
//lv_example_style_17();// NG?????
//lv_example_style_18();// NG?????
//lv_example_style_19();// 青ボタン スライド設定 黄ボタン
// \widgets (33フォルダ) にて
// 略
//lv_demo_widgets(); lv_conf.hでデモを有効にする。例:LV_USE_DEMOS_WIDGETS 未確認
// サンプルを表示する時はした5行をコメントにする
lv_obj_t *label = lv_label_create(lv_screen_active()); // ラベルオブジェクトを作成
lv_obj_set_style_text_font(label, &lv_font_source_han_sans_sc_16_cjk, 0);
// フォント 16px cjk
lv_label_set_text(label, "皆様こんにちは LVGL"); // ラベルに新しいtxtを設定
lv_obj_set_style_transform_zoom(label, 1024, 0); // ズーム4(=1024/256)倍
lv_obj_align(label, LV_ALIGN_CENTER, -200, 0); // 親の位置(中心)からx,y移動(obj,位置,x,y)
// 無いと左上に表示 次の描画サイクルで表示
Serial.println("Setup 完"); // シリアルモニタに表示
}
void loop() {
//M5.update(); // いるか?
lv_timer_handler(); // 数mSごとに定期的にLVGLを呼出す
delay(5); // 5mS待つ(応答性を維持するmax値)
}
* flash memory(6.5Mbyte)のうち、スケッチが14%使用。RAM(327kbyte)のうち、global変数が84%使用、local変数で51kbyte使用可能。(1000byte=1kbyteで計算)