ESP32 2432S028R (CYD)にサーモグラフィカメラを移植しました
LVGL の学習用に「黄色い基板」を AliExpress で購入したところ、1500円台という格安にもかかわらず意外と使えそうということがわかりました。
ただ運悪くハズレを引いたので、再度の技適ガチャは覚悟の上で「lvgl開発ボード」と謳われた品を 再手配 しました。またハズレた方は「国内の技適なしマイコン、特例届出を行いました」を参考に、「技適未取得機器を用いた実験等の特例制度」を申請中です。
ちょーどその頃、下記のようなお問い合わせを頂きました。そこで LVGL の学習は一旦脇に置き、CYD でも動くプログラムに再構成したので、ここに共有したいと思います ✌
ハードウェア
2432S028R、通称 Cheap Yellow Display について

ラングシップさんの「黄色いESP32液晶ボードシリーズまとめ|Lang-ship」や「ESP32 Cheap Yellow Display (CYD) Pinout (ESP32-2432S028R)|Random Nerd Tutorials」が詳しく、大いに参考にさせてもらいました。
本章では、XIAO 版サーモグラフィカメラ の移植に必要な、I2C 接続とバッテリー駆動についての調査結果を報告します。
MLX90640 の I2C 接続
「拡張 I/O コネクタ」の P3
と CN1
のうち、3.3V と GND が来ている CN1
で I2C 接続が可能です。回路図では CN1
の3番ピンがどこにも接続されていませんが、基板のシルク印刷や下記情報により、IO22 に接続されていることが分かります。
-
witnessmenow/ESP32-Cheap-Yellow-Display
- I2C support? #32 … I2C に関する調査
-
Wires - ADDONS.md …
CN1
のピン配 - 回路図 … 中国サイトからダウンロードした技術資料
下記図中のワイヤー色は、CYD に同梱された JST 1.25mm コネクタ付きワイヤーの色です。


上記「2. Wires - ADDONS.md」と今回作成のプログラムでは、I2C 用の SDA
と SCL
のピン設定を逆にしているので注意してください。ハード上の接続とソフト上の設定が合っていればどちらでも動作しますが、僕としては CYD 用ボードパッケージ ESP32-2432S028 CYD
(後述)で読み込まれる pins_arduino.h
に準拠した設定にすべきと考えています。
さて CN1
の2番ピン(IO27、今回 SDA
に割り当て)は、内部的に 10KΩ でプルアップされていますが、3番ピン(IO22、今回 SCL
に割り当て)はノーケアです。これらは外部から見れば I2C の要件に合致していないので、外付けでもプルアップすべきと思います。
実際には「プルアップ無し」でも動作することは確認しましたが、ソフトウェア編 でも触れた通り、SDA
、SCL
とも 1KΩ でプルアップすれば 信号の立ち上がりがシャープになります。



ちなみに、アナログ/デジタル入出力用と思われる P3
の1番ピンは、バックライト制御用の IO21 に接続されているため、 CN1
を I2C 用とした場合に使える GPIO は、両コネクタに共通の IO22 を除いた IO35 だけとなることを書き添えておきます。
ピン No | CN1 | P3 |
---|---|---|
1 | 3.3V | IO21 → バックライト制御用 |
2 | IO27 → I2C SDA に割り当て | IO22 → CN1 で I2C に割り当て |
3 | IO22 → I2C SCL に割り当て | IO35 → デジタル入出力のみ可 |
4 | GND | GND |
バッテリー駆動
CYD をカメラとして使うにはバッテリー駆動が必須ですよネ。ということで下記を参考に Li-Po と充電器を手配し、実験してみました。
- witnessmenow/ESP32-Cheap-Yellow-Display
- TP4056 lithium charger module - modification to add power sharing
Li-Po バッテリーの接続

バッテリーは、USB 端子横の(シリアル入出力と共通の)P1
(旧バージョン)または P5
(新バージョン)に接続可能です。回路図上の Q1
は P チャネルのパワー MOSFET で、逆接保護用と思われます。
試しに 3.7V の Li-Po を直に接続してみたところ、MLX90640 の出力にブロックノイズが乗ったような状態となりました。未確認ですが、I2C に十分な電圧が出力できていないためと思われます。

ということで、昇圧回路付き、かつ充放電統合タイプの充電器を AliExpress で探し、USB-C タイプとブレークアウト基板のタイプをそれぞれ1個づつ、お試して購入してみました(送料の方が高かったデス 😅)
- USB-C タイプ
- ブレークアウト基板タイプ
Amazon なら「バッテリー充放電統合モジュール」を商品検索すれば、類似品が出て来ると思います。動作は未確認なので、ご利用は自己責任でお願いします。
動作検証
ブレークアウト基板タイプは、USB のメスが手元になく給電が難しかったので、USB-C タイプで実験してみました。
購入した充電器には Vout 調整トリマが付いています。テスターで Vout を測ると 5.7V 出ていたので、時計ドライバーでトリマを調整し 5.0V に合わせる必要がありました。また Li-Po を接続する ±B 端子からは 4.2V が出ていることが確認できました。



次に発熱状況を調べるため、10分程度の動作後に作成したカメラで可視化してみました。カメラと対象との間に空気層があるため、実際の温度は表示温度よりもう少し高いと思いますが、問題は無さそうです(TP4056 動作温度:-40℃〜85℃)。
また Li-Po の充電が完了すると青色の LED が点灯しますが、負荷(CDY)をオンにしてしばらくすると赤色に変わったので、多少 Li-Po からの持ち出しが発生しているのかもしれません。
そこからさらに赤色のまま充電が完了しそうにない振る舞いが見られましたが、CYD をオフしてしばらくすると青色に戻りました。ちょっとした回路定数のバラつきが原因かもしれませんが、放電しながらの充電は出来ているようです。
パッケージングの課題
Li-Po 用の 5V 系充電器はどれも小さく、どうやってカメラとしてパッケージングするかが課題になると思います。加工が難しいですが、micro-USB と USB-C の両方付いた新しい基板なら、micro-USB の方をパターンカットし、ブレークアウト基板タイプの充電器を使うのがベストと思いますが、どうでしょう…
端子について

Li-Po バッテリーの端子は、それぞれの用途に応じて 1.25mm、PH (2mm)、XH (2.5mm) があるようですが、どれでも対応できるよう部品を持っておくのが吉と思います。
-
JST PH
ピンピッチが 2mm なので、取り扱いが楽です。- PHコネクター ベース付ポスト トップ型 2P B2B-PH-K-S 秋月電子 1個¥10(税込)
- PHコネクター ベース付ポスト サイド型 2P S2B-PH-K-S 秋月電子 1個¥10(税込)
-
JST 1.25mm
CYD に周辺機器を接続するには2ピンと4ピンが必要です。先端が半田メッキされたワイヤー付きなので、圧着工具なしで使えるので便利です。 - ご参考
ソフトウエア
ソースコード一式を GitHub リポジトリ「embedded-kiddie/MLX90640
」に上げました。現状はドキュメント(README.md)が未整備なので、インストール、設定、キャリブレーションの各方法について取り急ぎ解説したいと思います。
想定する環境は以下の通りです。
- Arduino IDE : 2.3.4
- ボードパッケージ : esp32 by Espressif Systems : 3.1.1
- MLX90640 ライブラリ : adafruit/Adafruit_MLX90640 1.1.1
- グラフィックスライブラリ
インストール
まず、コンパイルが可能になるまでの手順を示します。

1.リポジトリからコードをダウンロードし、解凍すると MLX90640-main
というフォルダができるので、MLX90640
にリネーム後、ご自分のスケッチ用フォルダに移します。

2.MLX90640/MLX90640.ino
を開き、Arduino IDE メニューの「他のボードとポートを選択」から ESP32-2432S028R CYD
を選択、CYD が接続されたポートを設定します。
これにより、CYD 用の pins_arduino.h
が読み込まれるようになります。

3.IDE のツールメニューから、Partition Shceme
と Upload Speed
を確認します。
パーティションは、タッチスクリーンのキャリブレーション結果を Flash に保存する場合、少なくとも2つが切られていることが必要ですが、コード中に埋め込むことも可能なので、必須ではありません。
またアップロードのボーレート 921600
は少し下げます。Mac や Linux では 460800
、Windows では 512000
が board.txt に設定された適切な値と思います。
設定
続いて IDE で MLX90640.ino を開き、次のステップに従い構成を設定します。CYD の場合、Step 2. でカメラの向きを設定すれば、後はデフォルトのままで OK だと思います。
Step 1: デバッグ用シリアル出力の設定
不具合でも起きない限り、変更する必要ありません。
MLX90640.ino 10〜18行目
/*--------------------------------------------------------------------------------
* Step 1: Configure serial output for debugging
*--------------------------------------------------------------------------------*/
#define DEBUG false
#if DEBUG
#define DBG_EXEC(x) x
#else
#define DBG_EXEC(x)
#endif
Step 2: 動作の設定
バイリニア補間、マルチタスクの設定はそのままで OK です。ENA_OUTWARD_CAMERA
は、MLX90640 が内向き(自撮り)の場合は false
を、外向きの場合は true
を設定します。
MLX90640.ino 20〜25行目
/*--------------------------------------------------------------------------------
* Step 2: Configure operational settings
*--------------------------------------------------------------------------------*/
#define ENA_INTERPOLATION true // Enable interpolation
#define ENA_MULTITASKING true // Enable multi-task by FreeRTOS
#define ENA_OUTWARD_CAMERA false // Camera orientation (true: Outward, false: Selfie)
Step 3: グラフィックスライブラリの設定
CYD では LovyanGFX のみ有効としているので、そのままで OK です。新旧どちらの CYD でも LovyanGFX の自動設定を有効にしています。
MLX90640.ino 27〜49行目
/*--------------------------------------------------------------------------------
* Step 3: Select GFX Library
*--------------------------------------------------------------------------------*/
#if 1
#define USE_LOVYAN_GFX
/*--------------------------------------------------------------------------------
* LovyanGFX
* Note: Currently 'AUTODETECT' only works for 'ESP32 2432S028R'.
* For other boards you need to configure appropriately to fit your device.
* See https://github.com/lovyan03/LovyanGFX/blob/master/src/lgfx/boards.hpp
*--------------------------------------------------------------------------------*/
#define USE_AUTODETECT true
#else
#define USE_TFT_ESPI
/*--------------------------------------------------------------------------------
* TFT_eSPI
* It does not allow the display and touch screen to be on different SPI buses.
*--------------------------------------------------------------------------------*/
#ifdef ARDUINO_ESP32_2432S028R
#error Not yet supported // CYD needs XPT2046_Touchscreen library
#endif
#endif
ご参考
TFT_eSPI のタッチ機能が使えず XPT2046_Touchscreen が必要になる理由です。
Step 4: キャリブレーション用データの保存先設定
本プログラムでは、タッチスクリーンのキャリブレーション用データの保存に Preferences を利用し Flash に保存するオプションを用意しています。キャリブレーション時に再コンパイルが不要な true
を推奨しますが、デフォルトは false
としています。
MLX90640.ino 51〜55行目
/*--------------------------------------------------------------------------------
* Step 4: Configure flash memory setting to save touch calibration data
*--------------------------------------------------------------------------------*/
#define USE_PREFERENCES false
Step 5: 解像度の設定
性能の低い CPU 向けの設定なので、CYD ではデフォルトのままで OK です。
MLX90640.ino 57〜68行目
/*--------------------------------------------------------------------------------
* Step 5: Configure resolution settings
*--------------------------------------------------------------------------------*/
#if ENA_INTERPOLATION
#define INTERPOLATE_SCALE 8
#define BOX_SIZE 1
#define REFRESH_RATE (ENA_MULTITASKING ? MLX90640_32_HZ : MLX90640_16_HZ)
#else
#define INTERPOLATE_SCALE 1
#define BOX_SIZE 8
#define REFRESH_RATE (ENA_MULTITASKING ? MLX90640_32_HZ : MLX90640_16_HZ)
#endif
タッチスクリーンのキャリブレーション
Step 4. で USE_PREFERENCES
を false
に設定した場合の埋め込み方法を説明します。true
に設定した場合は埋め込みデータは無視されるので、単にキャリブレーションを実行するだけで OK です。

1.コンパイル&アップロード後にプログラムが起動すると、タッチスクリーンのキャリブレーション画面に移るので、矢印をタッチする前にシリアルモニターを開いてください。ボーレートは 115200
です。
2.四隅を順にタッチすると、シリアルモニターに以下のようなテキストが出力されるので、選択してコピーします。
// LovyanGFX
.cal = { 303, 3765, 311, 179, 3808, 3757, 3764, 196 },
3.IDE から touch.hpp を開き、コピーしたテキストを該当箇所に上書きでペーストします。再コンパイル後は、キャリブレーションは実行されず、通常のカメラ機能が起動します。
touch.hpp 25〜48行目
/*--------------------------------------------------------------------------------
* Touch panel calibration parameters
* When 'USE_PREFERENCES' is 'false', the calibration result must be embedded.
*--------------------------------------------------------------------------------*/
TouchConfig_t tch_cnf = {
#if defined (LOVYANGFX_HPP_)
// LovyanGFX
.cal = { 0, 0, 0, 0, 0, 0, 0, 0 },
#elif defined (_XPT2046_Touchscreen_h_)
// XPT2046_Touchscreen
.cal = { 0, 0, 0, 0, 0, },
#else
// TFT_eSPI
.cal = { 0, 0, 0, 0, 0, },
#endif
.offset = { 0, },
};
以上です。お疲れ様でした 🙂
Tips
ドキュメントの整備はボチボチ進めていきますが、ここでは幾つか Tips を紹介しておきます。
I2C の不具合

I2C でエラーが発生すると、画面に Failed
が表示されます。この場合、ハード的な接続か、ピン配を再確認してください。
特に SDA
と SCL
を逆に設定すると、Failed
の表示と共にリブートし続ける事象にハマります。この場合は一旦電源を切り、Boot ボタンを押しながら電源を入れ直し、正しく設定したスケッチを再アップロードしてください。
メインスクリーンのタッチ動作

画面は、特定の領域を占める幾つかのウィジェットで構成されていて、それぞれクリック時の機能が決まっています。
ここでは2つの機能について補足的な説明をします。
特定点のサンプリング
「A」の領域をクリックすると、クリック地点の温度を表示します。数秒のウィンドー幅を持つ移動平均的なフィルターが適用されるので、安定するまで待ってください。また表示を消す場合は、領域「B」をクリックします。
サーモグラフィ画面へのショートカット
領域「C」をクリックすると、表示温度の設定画面にショートカットします。
ファイルマネージャー画面でのビデオ再生
表示の色合い(Rainbow/Inferno)や温度範囲は、サーモグラフィ画面の設定が適用されます。
起動時のデフォルト設定を変更する
自由度は少ないですが、以下のコードを直接編集することで、幾つか変更が可能です。
mlx.hpp 85〜94行
constexpr MLXConfig_t mlx_ini = {
.interpolation = INTERPOLATE_SCALE, // 1, 2, 4, 6, 8
.box_size = BOX_SIZE, // 1, 2, 4, 8
.refresh_rate = REFRESH_RATE, // sampline frequency (32Hz, 16Hz, 8Hz, 4Hz, 2Hz)
.color_scheme = 0, // 0: rainbow, 1: inferno
.marker_mode = 0, // 0: off, 1: min/max, 2: picked up by user
.range_auto = false, // automatic measurement of temperature min/max
.range_min = MINTEMP, // minimum temperature (20 deg)
.range_max = MAXTEMP, // maximum temperature (35 deg)
};
実は…
冒頭の写真にあるように、画角 110°の近距離用(MLX90640 BAA)と画角 55°の中距離用(MLX90640 BAB)の2つの MLX90640 を持っています。
中距離用は、室内の温度分布とかを可視化しています。床付近と天井とでは 2℃〜 4℃ ほども違うことがあり、エアコンの風向きを変えたりサーキュレーターで循環させたりと、暖房効率の向上に一役買ってます
さて本件関連の今後ですが、MLX90640Viewer の使い勝手が悪いので、Processing のプログラミングで GUI の改善をユルユルと進めようかと思っているところです