はじめに
最近、SenseCAP Indicator D1を使って、ちょっとしたPC用の情報表示・操作パネルを作ったりしています。
画面には時計やPCのCPU使用率、メモリ使用量を表示したり、ランチャー機能を持たせたデバイスにしたいと思っています。
今回の記事では、その途中で遭遇したLCDのちらつき問題について書いてみます。
もともとChatGPTに聞きながらファームウェアをつくっていて、LCD表示の動作確認していたら、妙に画面がチラつく現象が起きるようになりました。
自分でもチラつきの原因が知りたかったので、ChatGPTに逐一現状を相談して改善方法を出してもらうみたいな方法で進めました。
最終的には、LCDのBounce Buffer というものを有効にすることで、チラつきがなくなりました。
今回は備忘録としてその過程を書いてみようと思いました。
今回の環境
今回使用しているのは、Seeed StudioのSenseCAP Indicator D1 というタッチLCD付きマイコンボードです(LCD付きでケースに収められているのでボードというより、ガジェット感が強いものになっています)
- 搭載マイコン:ESP32-S3 & RP2040
- 480×480 RGB LCD
- タッチパネル
- Arduino IDEでファームウェア開発
- LVGLを使用
- EEZ Studioを使用(画面UI設計用のツール)
- Arduino_GFXライブラリを使用(LCD描画用のグラフィックライブラリ)
この環境で、Wi-Fi接続を行いながらLVGLで画面を更新するような動作をさせています。
何かLCDの表示がちらつく
最初、画面の遷移(LVGLを使って画面表示の切替)を行った瞬間に、一瞬画面がチラつくことがありました。
個人的な趣味で作っているので、まあ多少チラついても良いかと思っていたのですが、
Wi-Fiを使うようにしてからLCDが周期的にチラつくようになり、かなり気になる頻度で発生するため、対処することにしました。
AIに相談しながら原因を切り分ける
SenseCap Indicatorはマイコンで動くデバイスで、ファームウェア書き込みや動作確認は自分でしないといけないので、都度ChatGPTの提案を聞いて、
- Wi-FiをOFFにしてみる
- Wi-Fi.begin()だけ実行してみる
- CPUコアを確認する
- delay()を変更する
- LVGLを止める
- DIRECT_MODEを変更する
- LCDのPCLKを変更する
など、原因になっていそうな部分を一つずつ切り分ける感じで進めました。
まずWi-Fiを疑ってみる
まずはWi-Fiが悪さをしているかどうかを調べようということになり、Wi-Fiを完全にOFFにすると、ちらつきはほぼ発生しなくなりました。
次に
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);//WiFiのネットワークに接続
Wi-Fiのネットワーク接続だけを実行するようにしてみると、チラつきが発生。
さらに、
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
WiFi.mode(WIFI_OFF);//WiFiをオフ
としてみると、チラつきがなくなる。
一方、
WiFi.begin();//WiFiを有効にしただけ
でもチラつきが発生。
この結果から、Wi-Fiを使用している状態そのものがLCD表示に影響している可能性が高そうだと分かりました。
LVGLを止めてもちらつく
次に、LVGLの処理が悪さをしているかどうかを確認するため、LVGLによる画面更新を止め、単純にLCDへ色を塗るだけにしてみます。
gfx->fillScreen(RGB565_WHITE);
setup()内に上記処理で白画面表示だけをさせたところ、それでもチラつきは発生しました。
さらに
チラつきとは別で、画面の下側に横方向に表示が乱れるような、描画しきらないような現象も見られました。
自分としてはWiFiが干渉して、ディスプレイ制御用のSPI通信線にノイズが乗っているのかな?と考えたのですが、
ChatGPTさん的には「ノイズではなく、WiFiの処理によってマイコン側の処理負荷やメモリアクセスが増えて、LCD表示処理と競合している可能性がある」という考えのようでした。
PCLKを変更してみる
次にLCDのPCLKを変更を提案されたので、試してみました。
12MHz、10MHz、6MHzなどを試してみましたが、ちらつきは改善しませんでした。
逆に24MHzまで上げると、ちらつきがかなり激しくなりました。
このあたりから、LVGLの問題というよりも、RGB LCDへのデータ転送そのものに関係しているのではないかとChatGPTさんは考えるようになったようです。
以下はその時のChatGPTの回答**********************************
さきほどの写真の状態(白画面で描画しきらない状態)は単なる「LVGLのちらつき」というより、RGB LCDの走査中にフレームバッファからデータを供給しきれず、画面下部で表示が崩れているような状態に見えます。
そして、実はEspressifの公式ドキュメントに今回の症状とかなり近い説明があります。
EspressifのRGB LCDドキュメントでは、DMAがLCDの消費速度に追いつかないと、RGB peripheralがダミーデータを出力し、その結果として表示位置がずれる(drift)ことが説明されています。
ESP32-S3のRGB LCDについて、Espressifは「display drift」の原因として、
- RGBのPCLKが高すぎてPSRAM/GDMAの帯域が足りない
- PSRAMとFlashが共有インターフェースを使用する
- 大量のFlash/PSRAMアクセスによって帯域が不足する
などを挙げています。また、Wi-Fiなどによる処理でこの問題が顕在化する場合があると説明しています。
さらに、ESP-IDFにはこの対策としてRGBのBounce Bufferという仕組みがあります。PSRAM上のフレームバッファから内部RAMのバッファへあらかじめデータをコピーし、LCD DMAは内部RAM側から読むことで、短時間のPSRAM帯域不足に強くする仕組みです。
そこでBounce Bufferを試してみる
簡単に言うと、
WiFiの処理が発生すると、PSRAM上のフレームバッファの読み込みが追い付かなくなり画面の表示が乱れる みたいなことらしいです。
そこで、ChatGPTさんから「Bounce Bufferを使ってみな」という提案が出たので
Arduino_GFXのLCDを駆動するための設定箇所に、
4800 /* bounce_buffer_size_px */
という項目を追加しました。
元々は下記のような設定でした。
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(
18 /* DE */, 17 /* VSYNC */, 16 /* HSYNC */, 21 /* PCLK */,
4 /* R0 */, 3 /* R1 */, 2 /* R2 */, 1 /* R3 */, 0 /* R4 */,
10 /* G0 */, 9 /* G1 */, 8 /* G2 */, 7 /* G3 */, 6 /* G4 */, 5 /* G5 */,
15 /* B0 */, 14 /* B1 */, 13 /* B2 */, 12 /* B3 */, 11 /* B4 */,
1 /* hsync_polarity */,
10 /* hsync_front_porch */,
8 /* hsync_pulse_width */,
50 /* hsync_back_porch */,
1 /* vsync_polarity */,
10 /* vsync_front_porch */,
8 /* vsync_pulse_width */,
20 /* vsync_back_porch */
);
これを下記の設定の設定内容に変更しました。
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(
18 /* DE */, 17 /* VSYNC */, 16 /* HSYNC */, 21 /* PCLK */,
4 /* R0 */, 3 /* R1 */, 2 /* R2 */, 1 /* R3 */, 0 /* R4 */,
10 /* G0 */, 9 /* G1 */, 8 /* G2 */, 7 /* G3 */, 6 /* G4 */, 5 /* G5 */,
15 /* B0 */, 14 /* B1 */, 13 /* B2 */, 12 /* B3 */, 11 /* B4 */,
1 /* hsync_polarity */,
10 /* hsync_front_porch */,
8 /* hsync_pulse_width */,
50 /* hsync_back_porch */,
1 /* vsync_polarity */,
10 /* vsync_front_porch */,
8 /* vsync_pulse_width */,
20 /* vsync_back_porch */,
0 /* pclk_active_neg */, //←追加
GFX_NOT_DEFINED /* prefer_speed */, //←追加
false /* useBigEndian */, //←追加
0 /* de_idle_high */, //←追加
0 /* pclk_idle_high */, //←追加
4800 /* bounce_buffer_size_px */ //←追加
);
そして、PLCKは元の12MHzに戻して
gfx->begin(12000000L);
として動かしてみます。
すると……
ちらつきが完全になくなりました。
チラつき現象の解決
自分ではノイズが原因では?と思ってましたが、ChatGPTさんの考え通り、マイコン内部の処理の問題のようでした。
それまで、
- 時計更新を止める
- Wi-Fi設定を変える
- delayを変更する
- CPUコアを確認する
- LVGLを止める
- DIRECT_MODEを変更する
- PCLKを変更する
といろいろ試して、それでも解決しませんでしたが、Bounce Bufferを有効にしたところ、今まで発生していたちらつきがきれいになくなりました。
Bounce BufferはPSRAM上のメインフレームバッファを直接LCDのDMAに読ませるのではなく、
PSRAM
│
│ CPUがコピー
↓
内部RAM Bounce Buffer
│
│ DMA
↓
RGB LCD
という経路にして、PSRAM上のフレームバッファのデータの一部を一旦、内部RAMに読み込んでおくような仕組みらしいです。
これによって、PSRAMへの短時間のアクセス集中が起きてもLCD側がデータ不足になりにくくなるようです。
その後、LVGLの処理を元に戻して確認しても問題ありませんでした。
さらに、画面遷移時(画面を切り替えたとき)に発生していたちらつきもなくなりました。
Bounce Bufferを有効にするとチラつきが解消した
今回の実験だけで内部の動作を完全に証明できたわけではありませんが、検証結果としては、
SenseCap Indicatorで、
・Wi-Fiを使用した状態でLCDを動かすとちらつきが発生する(主にフレームバッファを使用した画面更新の場合)
・Bounce Bufferを有効にすると解消した
ということは確認できました。
ESP32-S3では、LCDの表示データ転送、PSRAM、DMA、WiFiなどの処理が関係しているため、これらのリソースの競合やデータ供給のタイミングが影響していた可能性があるようです。
SenseCapの動作設定
現在は、
- Wi-Fi ON
- LVGL使用
- EEZ Studio使用
- PCLK 12MHz
- Bounce Buffer 4800px
という構成で、LCDの画面表示は安定して動作しています。
最初は単純なLCDのちらつきだと思っていましたが、実際にはいろいろな条件を変えながら原因を切り分けることになりました。
ChatGPTが「次に何を試せば原因を切り分けられるか」を考えてくれたのでかなり効率よく進めることができましたが、あれこれ試したので案外大変でした。。
今後はこのSenseCAP Indicator D1に、PCのCPU使用率やメモリ、GPU、VRAM使用量などを表示できるようにしていく予定です。
先日、M5STACK Tab5も購入したのでこちらも時間があればいろいろ動かしてみたいと思っています(時間があれば。。。)

