UNO R3/Mega 2560 用シールドを UNO R4 WiFi で使う
UNO R3/Mega 2560 用シールドを UNO R4 WiFi で使う

はじめに

ESP32 と UNO R4 WiFi で動作する ArduinoOpenWeather の制作で Arduino GFX(IDE ライブラリ マネージャ上は GFX Library for Arduino)を使ってみました。

UNO R4 とカラー TFT LCD の組み合わせでは、Adafruit GFX がよく使われていますし、稀に UNO R3/Mega 2560 用 LCD シールドを MCUFRIEND_kbv で 動かした例 を見つける事ができます。

Arduino GFX はこれらのライブラリに比べて適用範囲の広さと速さがウリですが、正しく動作させるには設定に注意が必要な事が分かりました。ソレさえ分かれば他の LCD にも応用できると期待しています。

ということで、本記事では Arduino_GFX に関して以下を共有したいと思います。

と、その前に今回購入した LCD の紹介です。

おことわり

本記事では、「見た目が似ていても、中身がどこか違う製品がある」ことを、「クローン」や「派生」ではなく「変異体(Variant)」と表現しています。コロナウィルスの「変異株」に近いニュアンスです。ご了解ください。

本記事で取り上げる LCD

Aliexpress で TFT LCD を探すと、仕様が不明なモノや、基板やピンの色違い、設計が古そうなモノなど「変異体」が数多くあり、自分のボードで動くか心配になりますよネ。

開拓精神が旺盛な方はともかく、私は LCD wiki と見比べながら、以下を購入しました。

SPI 系

2.4/2.8インチ ST7789/ILI9341 SPI
2.4/2.8インチ ST7789/ILI9341 SPI

8-bit パラレル系シールドタイプ

「Arduino UNO/Mega2560 用」として販売されているシールドです。LCD wiki からデモを落とすか、MCUFRIEND_kbv を Adafruit GFX と組み合わせるのが一般的のようです。

一方 Arduino GFX では、このプルリク で UNO R4 系でも動作するようになりました。

2.4インチ 8-bit パラレル
2.4インチ 8-bit パラレル
  • 2.4inch Arduino Display - LCD wiki
    写真の左側は TZT 社 (TuoZhanTeng Electronic Technology Co., Ltd) 製で、LCD wiki に掲載のモノと同一のようです。

残りの2つは設計が少し古そうで、画面が少し暗めです。これらは ILI9341 版と ST7789 版をペアで購入してみました。

3.5インチ ILI9486 8-bit パラレル
3.5インチ ILI9486 8-bit パラレル

ハードウェア仕様の確認と消費電流の測定

公式マニュアルの UNO R4 Minima 編 や UNO R4 WiFi 編 によると、ボードへの電源を VIN から供給した場合はオンボードのレギュレータで 5V に降圧され、最大 1.2A の供給能力があるとのことです(ボード自体の消費電流を含む)。

また 3.3V の供給可能な最大電流に関しては、「Arduino UNO R4 その3(RA4M1 の隠された機能)」の見積もりによると、50mA 程度が安心のようです。

一方、過去に サーモカメラを製作した経験から、2.4 インチ LCD で 90mA 近くを消費していたことを考えると、ちゃんと検証しないとヤバそうです。

事実、少々古い記事(2019年 9月) ですが、シールドタイプの変異体には次のような仕様のモノが存在したようです。

現在のMcufriendシールドの設計は誤っています。バックライトの電源をArduinoの3.3Vピンから取っている点が間違いです。本来のシールドでは、ディスプレイ基板上に3.3Vレギュレータが搭載されており、そこへ5Vピンから電源が供給される仕組みになっていました。
…
とても単純な話です。基板を見てみてください。 元の基板にはAMS1117レギュレータが搭載されており、5Vピンと3.3Vピンの両方が使用されています。 現在の基板にはSOIC-8用の空きパターンがあるだけで、レギュレータは搭載されていません。使用されているのは3.3Vピンのみです。

レギュレータなし基板の例
レギュレータなし基板の例

コストダウンのためにレギュレータを取っちゃったのでしょう。2026 年の現在ではそういう粗悪な基板はないと思いますが、念の為に回路図を確認し、3.3V、5V のそれぞれから引き出される電流を実測してみました。

SPI 系の回路図と消費電流測定

LCD wiki に添付された回路図を見ると、次の事が分かります。

  • VCC 選択用はんだジャンパ J1 は、開放で 5V、短絡で 3.3V を切り替え
  • TFT_BL は、内部のトランジスタがスイッチとなり4つのバックライト用 LED を駆動

以下はこれらを裏付ける測定結果で、何れも許容範囲内でした。メデタシ、メデタシ 🤗

端子 2.4インチ 2.8インチ
3.3V 端子 3.2mA 3.3mA
5V 端子 82.1mA 67.3mA
回路図
回路図
2.4インチ ILI9341 消費電流
2.4インチ ILI9341 消費電流
2.8インチ ILI9341 消費電流
2.8インチ ILI9341 消費電流

8-bit パラレル系シールドタイプの消費電流測定

購入したレギュレータ付き基板
購入したレギュレータ付き基板

LCD wiki に添付された回路図は、.SchLib ファイルを開く環境が構築できず未確認です 😅 が、3.3V で直接バックライトを駆動していることもなく、安心しました 😮‍💨

端子 2.4inch Arduino Display 3.5inch Arduino Display-UNO
3.3V 端子 0 0
5V 端子 46mA 105.6mA
2.4インチの消費電流
2.4インチの消費電流
3.5インチの消費電流
3.5インチの消費電流

Arduino GFX 設定の注意点

Arduino GFX では MCU ⇔ LCD 間の通信を、経路である「データバス」クラスとディスプレイ ドライバ IC に送るデータを扱う「ディスプレイ」クラスに分けることで、様々なデバイス間で動作するように設計されています。

これを踏まえ、特に本章では Adafruit GFX との違いについて、次の二点を掘り下げます。

  • データバスのクロック周波数
  • ディプレイ変数のコンストラクタ

データバスのクロック周波数

ここでの「データバス」は SPI バスとします。Arduino の SPI クラスにおけるクロック周波数の最大値は 12MHz とされています。事実、Adafruit GFX では ILI9341 用クラスの begin() にクロック周波数を指定できますが、12MHz より大きな値を指定してもベンチマークの結果(後述)は変わりませんでした。

一方 Arduino GFX の ILI9341 用 begin() には 24MHz(RA4M1 で設定可能な最大値)も指定可能で、(さすがに2倍とまではいきませんが…)ベンチマーク結果も向上します。

拙作の記事「ESP32 2432S028R (CYD)でLVGL - ILI9341 vs ST7789 速度比較」で調べた通り、ILI9341 は 40MHz までは行けるので大丈夫だとは思いますが、Arduino_GFX は内部の VRAM を読み出す機能がないので描画結果の比較ができません。どこかおかしい?と感じたらデフォルトの 12MHz を設定してください 😓

ディプレイ変数のコンストラクタ

Arduino GFX で特質すべきは、例えば同じ ILI9341 用ドライバでも変異体による動作の違いにもキッチリ対応している点です。

例えば ILI9341 用のコンストラクタ は、次のように多くの引数が指定可能となっています。

Arduino_ILI9341(
  Arduino_DataBus *bus, int8_t rst = GFX_NOT_DEFINED, uint8_t r = 0,
  bool ips = false, int16_t w = ILI9341_TFTWIDTH, int16_t h = ILI9341_TFTHEIGHT,
  uint8_t col_offset1 = 0, uint8_t row_offset1 = 0, uint8_t col_offset2 = 0, uint8_t row_offset2 = 0,
  const uint8_t *init_operations = ili9341_type1_init_operations, size_t init_operations_len = sizeof(ili9341_type1_init_operations)
);

ここでの col_offset1 〜 row_offset2 は、最終的に Arduino_TFT::setRotation() でビデオ RAM の開始・終了座標に反映されます。つまり LCD パネル上の原点座標 (0, 0) の位置が微妙に異なる変異体に対応できるようになっています。

また 注目すべきは、初期化シーケンスを指定する init_operations です。デフォルトでは ili9341_type1_init_operations が設定されますが、変異体の違いを吸収する type1 〜 type3 の3種類が定義済み なことです。3.5 インチの ILI9486 版シールドを除き、今回取り上げた LCD では全て type2 を指定しないと「色ズレ」が起きる事が分かりました。

ILI9341 の色ズレ問題

次に挙げる例は、パンダの JPEG 元画像に対し Adafruit GFX と Arduino GFX の結果を比較したものです。LCD が同じならグラフィック ライブラリが異なっても見た目が同じになる事が期待されますが、デフォルトの type1 ではパンダの頭頂部と鼻の頭の部分で「色ズレ」が顕著となりました。

パンダ(元画像)
パンダ(元画像)
Adafruit GFX
Adafruit GFX
Arduino GFX (type2)
Arduino GFX (type2)
デフォルト(色ズレあり)
デフォルト(色ズレあり)

また次の画像は、上段にはRGB565 ビットマップ画像を 、下段には JPEG 画像を描画させていますが、デフォルトの type1 ではオレンジ色が濃くなり、また JPEG 特有のブロックノイズが見えてしまっています。

OpenWeather ロゴ
OpenWeather(元画像)
Adafruit GFX
Adafruit GFX
Arduino GFX (type2)
Arduino GFX (type2)
デフォルト(色ズレあり)
デフォルト(色ズレあり)

この問題は「黄色い基板」で知られる ILI9341 版 CYD でも再現します。解決策としては、次のように「ディスプレイ」クラスのコンストラクタに type2 を指定します。

// Data Bus
Arduino_DataBus *bus = new Arduino_HWSPI(TFT_DC, TFT_CS);

// Display
Arduino_GFX *gfx = new Arduino_ILI9341(
  bus, TFT_RST, TFT_ROTATION, false /* ips */, ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT,
  0 /* col offset 1 */,  0 /* row offset 1 */,  0 /* col offset 2 */,  0 /* row offset 2 */,
  ili9341_type2_init_operations, sizeof(ili9341_type2_init_operations)
);

この設定により、Arduino_GFX.h で定義された色 の色味も変わります。W3C Wiki の色見本 を元に定義しているようですが、RGB の値が微妙に調整されているようなので、type2 を使う場合はマクロ RGB565(r, g, b) で独自に定義した方が良いと思います。

ST7789 の色ズレ問題

同様の問題は ST7789 でも発生します。デフォルトの type1 では、Adafruit GFX と比較しなければ気付けない程度に色合いが薄くなります。まぁ気付かなければソレまでですが…

パンダ(元画像)
パンダ(元画像)
Adafruit GFX
Adafruit GFX
Arduino GFX (type2)
Arduino GFX (type2)
デフォルト(色ズレあり)
デフォルト(色ズレあり)
OpenWeather ロゴ
OpenWeather(元画像)
Adafruit GFX
Adafruit GFX
Arduino GFX (type2)
Arduino GFX (type2)
デフォルト(色ズレあり)
デフォルト(色ズレあり)

この問題も ST7789 版の CYD で再現します。UNO R4 + ST7789 の場合、解決には次のコードを使います(ST7789 のデータバスでは、Arduino_HWSPI() が正しく動作しませんでした)。

// Data Bus
Arduino_DataBus *bus = new Arduino_SWSPI(TFT_DC, TFT_CS, TFT_SCLK, TFT_MOSI, TFT_MISO);

// Display
Arduino_GFX *gfx = new Arduino_ST7789(
  bus, TFT_RST, TFT_ROTATION, false /* ips */, ST7789_TFTWIDTH, ST7789_TFTHEIGHT,
  0 /* col offset 1 */,  0 /* row offset 1 */,  0 /* col offset 2 */,  0 /* row offset 2 */,
  st7789_type2_init_operations, sizeof(st7789_type2_init_operations)
);

参考情報

Adafruit GFX を含むベンチマークの結果

お待ちかねのベンチマークは、Arduino GFX の PDQgraphicstest を Adafruit GFX でも動作するよう改修したプログラムで実施しました。

ILI9341

Adafruit GFX vs Arduino GFX の結果です。vs Adafruit は AdafruitGFXArduinoGFX24MHz\frac{Adafruit GFX}{Arduino GFX 24MHz} の値です。

Benchmark Adafruit GFX Arduino GFX 12MHz Arduino GFX 24MHz vs Adafruit
Screen fill 1,203,542 634,214 358,586 3.36
Text 253,111 69,719 52,867 4.79
Pixels 2,079,712 2,102,500 1,871,040 1.11
Lines 2,901,661 1,947,032 1,659,398 1.75
Horiz/Vert Lines 99,076 53,533 31,229 3.17
Rectangles (filled) 2,499,381 1,317,816 745,556 3.35
Rectangles (outline) 64,015 35,969 21,816 2.93
Triangles (filled) 816,981 474,307 295,822 2.76
Triangles (outline) 164,926 110,819 93,449 1.76
Circles (filled) 310,746 213,795 151,732 2.05
Circles (outline) 318,964 183,797 157,789 2.02
Arcs (filled) N/A 148,367 125,878 N/A
Arcs (outline) N/A 290,474 264,986 N/A
Rounded rects (filled) 2,468,541 1,342,219 769,934 3.21
Rounded rects (outline) 157,607 95,652 75,322 2.09

ST7789

2.4 インチの SPI 版と 8-bit パラレル版の比較です。Adafruit GFX の結果が比較対象にならないくらい遅いのは、LCD が Adafruit の純正品ではないからでしょう。

また Arduino GFX では、SPI 版の「データバス」クラスに Arduino_SWSPI を使わざるを得なかったため、ILI9341 版よりかなり遅めです。8-bit パラレル版もそれほど早くないので、UNO R4 では敢えて ST7789 版を購入する理由が見当たらないという結果になりました。

Benchmark Adafruit GFX Arduino GFX SPI 24MHz Arduino GFX 8-bit parallel
Screen fill 14,374,396 2,307,269 407,549
Text 2,537,210 187,994 52,502
Pixels 18,874,093 2,991,252 1,250,543
Lines 25,261,955 3,373,366 1,250,933
Horiz/Vert Lines 1,169,842 215,490 49,335
Rectangles (filled) 29,848,812 5,497,272 1,231,500
Rectangles (outline) 745,337 137,923 32,373
Triangles (filled) 9,417,678 1,748,627 417,373
Triangles (outline) 1,455,392 202,099 71,827
Circles (filled) 3,355,058 634,576 172,282
Circles (outline) 2,797,201 287,582 109,493
Arcs (filled) N/A 281,382 114,577
Arcs (outline) N/A 393,430 216,604
Rounded rects (filled) 29,114,681 5,509,766 1,237,597
Rounded rects (outline) 1,371,760 220,505 69,683

今回作成したプログラムについて

Arduino GFX Library Lab に次の2本を上げたので、興味があれば覗いてみてください。

  • ColorAlignment
    色ズレの有無を確認するスケッチです。ColorAlignment.ino の冒頭でサンプルの画像を選択し、Adafruit GFX の利用の有無、ドライバの種類、初期化シーケンスを設定します。また gfx_config.hpp で UNO R4 と CYD のピン配を定義しているので、実行環境に合わせて修正してください。

  • PDQgraphicstest
    ベンチマークのスケッチです。PDQgraphicstest.ino の冒頭にある元のデバイス定義を無効化し、Adafruit GFX の利用の有無、ドライバの種類、初期化シーケンスを設定します。また gfx_config.hpp で LCD のピン配を定義しています。ちなみにこのベンチマークは UNO R3 でも動作します(Arduino GFX の ST7789 を除く)。

ところで、MCUFRIEND って何?

と思ったのは私だけでしょうか? Google AI によると、データシートもない変異体の格安版が氾濫したとのこと。例えば「ArduinoUNO用のTFTシールド」を拝見すると、正に「ドライバ IC ガチャ」な状態だったようです 😱

当の “mcufriend.com” といえば、過当競争に敗れた結果、今では インターネットアーカイブにその名残を見る事ができるだけ です。

そんなを状況を改善すべく開発されたのが MCUFRIEND_kbv です。作者の David Prentice 氏が立ち上げた Arduino フォーラム上のスレッド「MCUFRIEND_kbv Library for Uno 2.4, 2.8, 3.5, 3.6, 3.95 inch mcufriend Shields」を見ると、当時の奮闘ぶりが伝わってきます。

ちなみに kbv は氏独自のサインのようなもらしいです。ただ残念なことに「David Prentice RIP」によれば、氏は 2022 年交通事故で亡くなられたとのことで、以来ライブラリの開発は止まったままです。

おわりに

今回購入した LCD はどれも抵抗式のタッチパネルと SD カードスロットが付いてます。今のところ使う見込みありませんが、動作確認ができたら改めて報告しようと思います 🌾