オープニング

lang-ship さんによる黄色い基板の紹介 や、CYD の名付け親とされる Brian Lough 氏の witnessmenow/ESP32-Cheap-Yellow-Display が開設されて以来、その安さと手軽さで人気を博してきた ESP32-2432S028R ですが、コスト削減の煽りか、日本の技術基準適合証明がスッ飛ばされてきたように思います。

AliExpress ではハズレ続きで、もう技適付きは絶望的かと思っていたところに、たまたま X のタイムラインに「らてさん」の書き込みを見つけました。らてさんに感謝です。

ということで、本記事ではピン配などの CYD との対比はもちろん、TFT_eSPI や LovyanGFX の設定やちょっとした注意点などをお届けしたいと思います 💫

ボード概観

ボードに関する情報は、それぞれ以下にまとめられています。

  • CrowPanel ESP32 HMI 2.8-inch Display
    回路図、ピン配、サンプルコードはもちろん、各認証機関が発行した証書(技適もあります)など、資料は充実している方だと思います。
  • ESP32-Cheap-Yellow-Display
    CYD のまとめ&情報共有のためのリポジトリです。回路図などの各種資料はもちろん、使用上のノウハウや様々な人が作成した CYD アプリケーションのリストなどが載ってます。
CrowPanel ESP32 HMI 2.8
CrowPanel ESP32 HMI 2.8
ESP32-2432S028R (CYD)
ESP32-2432S028R (CYD)

さて新し目の設計の CrowPanel ですが、さすがに外部端子のピン配はよく整理されています。LiPo バッテリーの充電管理用 IC が載っているのも嬉しいですね。一方イマイチなことに、GPIO で制御できる LED が無く、ボードの動作チェック用に Blink が使えなくなりました。

機能 CrowPanel ESP32 HMI 2.8 ESP32-2432S028R (CYD)
LCD、タッチ、SDカード SPIピン配はLCDとタッチで共通 SPIピン配がそれぞれ別々
LED 電源用LED ×1、GPIOで制御不可 RGB LED ×1、GPIOで制御可
充電管理 LTH7(LTC4054)搭載 非搭載
バッテリー BAT端子(PH2.0-2P) P5端子と共用(JST 1.25mm-4P)
UART UART1端子(HY2.0-4P) P5端子と共用(JST 1.25mm-4P)
I2C I2C端子(HY2.0-4P) CN1端子(JST 1.25mm-4P)
GPIO GPIO_D端子(HY2.0-4P) P3端子(JST 1.25mm-4P)
スピーカー SPK端子(PH2.0-2P) SPEAK端子(JST 1.25mm-2P)
フォトレジスタ(LDR) なし あり

余談ですが、画像の CYD には技適マーク の刻印がありますが、明らかにフェイクなので、0603 抵抗の交換練習用基板にしています 😎

ピン定義

ディスプレイ(ドライバ IC:ILI9341V)

CYD には ST7789 搭載のモデルがありますが、CrowPanel は ILI9341 のみです。「ESP32 2432S028R (CYD)でLVGL - ILI9341 vs ST7789 速度比較」で解析した通り、ST7789 の方が SPI バスのクロックを上げられるので 、個人的には残念に思っている事の1つです。

信号名 CrowPanel ESP32 HMI 2.8 ESP32-2432S028R (CYD)
TFT_MISO (SDO) 12 12
TFT_MOSI (SDI) 13 13
TFT_SCLK (SCK) 14 14
TFT_CS 15 15
TFT_DC 2 2
TFT_RS -1 -1
TFT_BL 27 21

タッチパネル(ドライバ:XPT2046)

ESP32 2432S028R (CYD)でLVGL - 2つのSPIバスでLCD、タッチ、SDを共存させる方法」に書いた通り、CYD ではディスプレイ、タッチパネル、SD カードの3つを共存させるには一工夫必要でしたが、CrowPanel ではピン配が改善されました。

CYD で TFT_eSPI を使う場合は別途 XPT2046_Touchscreen などが必要でしたが、この改善により CrowPanel では TFT_eSPI だけで完結するようになりました。

信号名 CrowPanel ESP32 HMI 2.8 ESP32-2432S028R (CYD)
TP_MISO 12 (TFT_MISO) 39
TP_MOSI 13 (TFT_MOSI) 32
TP_CLK 14 (TFT_SCLK) 25
TP_CS 33 33
TP_IRQ 36 36

SD カード

ESP32 の一般的なピン配で、Espressif 標準の SD ライブラリSdFat とも使用可能です。

信号名 CrowPanel ESP32 HMI 2.8 ESP32-2432S028R (CYD)
SD_MISO (TF_MISO) 19 19
SD_MOSI (TF_MOSI) 23 23
SD_SCLK (TF_CLK) 18 18
SD_CS (TF_CS) 5 5

UART

ピン配こそ違いますが、ESP32 のごく普通の設定だと思います。

信号名 CrowPanel ESP32 HMI 2.8 ESP32-2432S028R (CYD)
RX 16 3
TX 17 1

I2C

信号名 CrowPanel ESP32 HMI 2.8 ESP32-2432S028R (CYD)
SCL 21 22
SDA 22 27

CYD 用の pins_arduino.h(ESP32 コア 3.x 用)では、I2C 用のピン定義は次の通りです。

static const uint8_t SDA = 21;
static const uint8_t SCL = 22;

これを信用すると I2C は外部端子 P3 で使えそうですが、さにあらず、21 番はバックライトに接続されているので、CYD では CN1 を使う必要があります。

#define CYD_TFT_BL          21

GPIO

信号名 CrowPanel ESP32 HMI 2.8 ESP32-2432S028R (CYD)
IO21 - 21 (CYD_TFT_BL)
IO22 - 22
IO25 25 (DAC1) -
IO32 32 -
IO35 - 35

ESP32 Dev Module 用の pins_arduino.h では、25, 26 は次のように割り当てられています。1ピンだけですが、アナログ入出力が使えるのも CrowPanel のメリットでしょう。

static const uint8_t A18 = 25;
static const uint8_t A19 = 26;
static const uint8_t DAC1 = 25;
static const uint8_t DAC2 = 26;

オーディオ

信号名 ESP32-2432S028R (CYD) CrowPanel 2.8”
IO26 26 (DAC2) 26 (CYD_AUDIO_OUT)

オーディオ出力のゲインは CYD の ILI9341 タイプよりも1.5倍程度高めです。

サイン波の出力
サイン波の出力

幾つかの周波数のサイン波を入力したときの出力をスピーカー端子で観測した結果を示します。CYD の ST7789 タイプは問題外としても、ローコストなオーディオアンプ IC のためでしょう、どちらも音域が高くなるにつれ再現性が悪くなります。

ちなみに CYD ST7789 タイプのゲイン改善策については、以下を参照して下さい。

LED

信号名 CrowPanel ESP32 HMI 2.8 ESP32-2432S028R (CYD)
CYD_LED_RED - 4
CYD_LED_GREEN - 16
CYD_LED_BLUE - 17

残念ながら CrowPanel は、電源投入で赤色に光る LED だけで、GPIO で制御できる LED は搭載されていません。ちなみに CYD_LED_*pins_arduino.h で定義されるシンボルです。

LDR (Light Dependent Resistor)

信号名 CrowPanel ESP32 HMI 2.8 ESP32-2432S028R (CYD)
CYD_LDR - 34

CYD はフォトレジスタを搭載していますが、CrowPanel にはありません。ただし LDR の出力はダイナミックレンジが狭く、改修した方が良いようです。主な狙いはバックライトの明るさ制御だと思いますが、個人的には必要性を感じた事がありません。

ちなみに CYD_LDRpins_arduino.h で定義されるシンボルです。

バッテリー端子

バッテリー端子の極性に注意
バッテリー端子の極性に注意

バッテリー端子はスピーカー端子と同じ PH2.0 の2ピンですが、極性には要注意です。私は Amazon で JST-PH 2.0 オス/メスのコネクタケーブル を購入し、クロスの中継線を作りました。

充電管理 IC の動作テスト
充電管理 IC の動作テスト

また充電中はせめて LED が点滅してくれるとありがたいのですが… つきっぱなしで充電完了がわかりません。ちゃんと電流がカットされるのか心配だったので、念の為テスターを繋いでみました。大丈夫そうです 😮‍💨

グラフィックライブラリの設定について

CrowPanel-ESP32-Display-Course-File には、幾つかの例題がチュートリアルとして収められています。が、Elecrow の研究開発部門用なのか、幾つか「🤔?」な所があり、Issues やプルリクも放置されているので、参考程度に留めておくのが良いかと思います。

TFT_eSPI の設定ファイル

User_Setup.h
//                            USER DEFINED SETTINGS
//   Set driver type, fonts to be loaded, pins used and SPI control method etc
//
//   See the User_Setup_Select.h file if you wish to be able to define multiple
//   setups and then easily select which setup file is used by the compiler.
//
//   If this file is edited correctly then all the library example sketches should
//   run without the need to make any more changes for a particular hardware setup!
//   Note that some sketches are designed for a particular TFT pixel width/height

// User defined information reported by "Read_User_Setup" test & diagnostics example
#define USER_SETUP_INFO "User_Setup"

// Define to disable all #warnings in library (can be put in User_Setup_Select.h)
//#define DISABLE_ALL_LIBRARY_WARNINGS

//===================================================================================
// CrowPanel ESP32 HMI 2.8-inch
// https://github.com/Elecrow-RD/CrowPanel-ESP32-Display-Course-File
// https://www.elecrow.com/wiki/esp32-display-282727-intelligent-touch-screen-wi-fi26ble-240320-hmi-display.html
//===================================================================================

// ##################################################################################
//
// Section 1. Call up the right driver file and any options for it
//
// ##################################################################################

// Only define one driver, the other ones must be commented out
#define ILI9341_DRIVER       // Generic driver for common displays

#define TFT_WIDTH  240
#define TFT_HEIGHT 320

// ##################################################################################
//
// Section 2. Define the pins that are used to interface with the display here
//
// ##################################################################################

// If a backlight control signal is available then define the TFT_BL pin in Section 2
// below. The backlight will be turned ON when tft.begin() is called, but the library
// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
// driven with a PWM signal or turned OFF/ON then this must be handled by the user
// sketch. e.g. with digitalWrite(TFT_BL, LOW);

#define TFT_BL   27
#define TFT_BACKLIGHT_ON HIGH  // Level to turn ON back-light (HIGH or LOW)

// For ESP32 Dev board (only tested with GC9A01 display)
// The hardware SPI can be mapped to any pins
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS   15
#define TFT_DC   2
#define TFT_RST  -1

#define TOUCH_CS 33

// ##################################################################################
//
// Section 3. Define the fonts that are to be used here
//
// ##################################################################################

// Comment out the #defines below with // to stop that font being loaded
// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
// normally necessary. If all fonts are loaded the extra FLASH space required is
// about 17Kbytes. To save FLASH space only enable the fonts you need!

#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts

// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
#define SMOOTH_FONT

// ##################################################################################
//
// Section 4. Other options
//
// ##################################################################################

// Define the SPI clock frequency, this affects the graphics rendering speed. Too
// fast and the TFT driver will not keep up and display corruption appears.
// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
// With an ILI9163 display 27 MHz works OK.
#define SPI_FREQUENCY  40000000

// Optional reduced SPI frequency for reading TFT
#define SPI_READ_FREQUENCY  20000000

// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
#define SPI_TOUCH_FREQUENCY  600000   // Original
//#define SPI_TOUCH_FREQUENCY  2500000  // Testing Required

// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
// then uncomment the following line:
#define USE_HSPI_PORT   // Avoid conflict with SD card on VSPI

TFT_eSPI Setup file/2.8inch には User_Setup.h の設定例がアップされています。が、開発途中の設定でしょうか、SPI バスのクロックが 16MHz と低い値に設定されてます。

一方 XPT2046 のクロックは TFT_eSPI 作者推奨の 2.5MHz より低い 600KHz に設定されていていますが、getTouch() の処理時間はわずかに小さくなりました。次の結果は100回の平均値です。まぁ、大した違いはありませんが…

XPT2046 用 SPI バスクロック 600KHz 2.5MHz
非タッチ時 11.6 [msec] 13.9 [msec]
タッチ時 29.3 [msec] 30.3 [msec]

LovyanGFX の設定ファイル

LGFX_Elecrow_ESP32_Display_2432.hpp
#pragma once

#define LGFX_USE_V1

#include <LovyanGFX.hpp>

//===================================================================================
// CrowPanel ESP32 HMI 2.8-inch
// https://github.com/Elecrow-RD/CrowPanel-ESP32-Display-Course-File
// https://www.elecrow.com/wiki/esp32-display-282727-intelligent-touch-screen-wi-fi26ble-240320-hmi-display.html
//===================================================================================
#define TFT_MISO  12
#define TFT_MOSI  13
#define TFT_SCLK  14
#define TFT_CS    15
#define TFT_DC    2
#define TFT_RST   -1
#define TFT_BL    27

#define TP_MISO   TFT_MISO
#define TP_MOSI   TFT_MOSI
#define TP_SCLK   TFT_SCLK
#define TP_CS     33
#define TP_IRQ    36

class LGFX : public lgfx::LGFX_Device
{
  lgfx::Panel_ILI9341 _panel_instance;
  lgfx::Bus_SPI       _bus_instance;
  lgfx::Light_PWM     _light_instance;
  lgfx::Touch_XPT2046 _touch_instance;

public:

  LGFX(void)
  {
    { // バス制御の設定を行います。
      auto cfg = _bus_instance.config();    // バス設定用の構造体を取得します。

      // SPIバスの設定
      cfg.spi_host = HSPI_HOST;     // 使用するSPIを選択  ESP32-S2,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
      // ※ ESP-IDFバージョンアップに伴い、VSPI_HOST , HSPI_HOSTの記述は非推奨になるため、エラーが出る場合は代わりにSPI2_HOST , SPI3_HOSTを使用してください。
      cfg.spi_mode = 0;             // SPI通信モードを設定 (0 ~ 3)
      cfg.freq_write = 40000000;    // 送信時のSPIクロック (最大80MHz, 80MHzを整数で割った値に丸められます)
      cfg.freq_read  = 16000000;    // 受信時のSPIクロック
      cfg.spi_3wire  = false;       // 受信をMOSIピンで行う場合はtrueを設定
      cfg.use_lock   = true;        // トランザクションロックを使用する場合はtrueを設定
      cfg.dma_channel = SPI_DMA_CH_AUTO; // 使用するDMAチャンネルを設定 (0=DMA不使用 / 1=1ch / 2=ch / SPI_DMA_CH_AUTO=自動設定)
      // ※ ESP-IDFバージョンアップに伴い、DMAチャンネルはSPI_DMA_CH_AUTO(自動設定)が推奨になりました。1ch,2chの指定は非推奨になります。
      cfg.pin_sclk = TFT_SCLK;      // SPIのSCLKピン番号を設定
      cfg.pin_mosi = TFT_MOSI;      // SPIのMOSIピン番号を設定
      cfg.pin_miso = TFT_MISO;      // SPIのMISOピン番号を設定 (-1 = disable)
      cfg.pin_dc   = TFT_DC;        // SPIのD/Cピン番号を設定  (-1 = disable)
      // SDカードと共通のSPIバスを使う場合、MISOは省略せず必ず設定してください。

      _bus_instance.config(cfg);              // 設定値をバスに反映します。
      _panel_instance.setBus(&_bus_instance); // バスをパネルにセットします。
    }

    { // 表示パネル制御の設定を行います。
      auto cfg = _panel_instance.config();    // 表示パネル設定用の構造体を取得します。

      cfg.pin_cs           = TFT_CS; // CSが接続されているピン番号   (-1 = disable)
      cfg.pin_rst          = TFT_RST;// RSTが接続されているピン番号  (-1 = disable)
      cfg.pin_busy         =    -1;  // BUSYが接続されているピン番号 (-1 = disable)

      // ※ 以下の設定値はパネル毎に一般的な初期値が設定されていますので、不明な項目はコメントアウトして試してみてください。
      cfg.panel_width      =   240;  // 実際に表示可能な幅
      cfg.panel_height     =   320;  // 実際に表示可能な高さ
      cfg.offset_x         =     0;  // パネルのX方向オフセット量
      cfg.offset_y         =     0;  // パネルのY方向オフセット量
      cfg.offset_rotation  =     2;  // 回転方向の値のオフセット 0~7 (4~7は上下反転)
      cfg.dummy_read_pixel =     8;  // ピクセル読出し前のダミーリードのビット数
      cfg.dummy_read_bits  =     1;  // ピクセル以外のデータ読出し前のダミーリードのビット数
      cfg.readable         =  true;  // データ読出しが可能な場合 trueに設定
      cfg.invert           = false;  // パネルの明暗が反転してしまう場合 trueに設定
      cfg.rgb_order        = false;  // パネルの赤と青が入れ替わってしまう場合 trueに設定
      cfg.dlen_16bit       = false;  // 16bitパラレルやSPIでデータ長を16bit単位で送信するパネルの場合 trueに設定
      cfg.bus_shared       =  true;  // SDカードとバスを共有している場合 trueに設定(drawJpgFile等でバス制御を行います)

      _panel_instance.config(cfg);
    }

    { // バックライト制御の設定を行います。(必要なければ削除)
      auto cfg = _light_instance.config();    // バックライト設定用の構造体を取得します。

      cfg.pin_bl = TFT_BL;          // バックライトが接続されているピン番号
      cfg.invert = false;           // バックライトの輝度を反転させる場合 true
      cfg.freq   = 44100;           // バックライトのPWM周波数
      cfg.pwm_channel = 7;          // 使用するPWMのチャンネル番号

      _light_instance.config(cfg);
      _panel_instance.setLight(&_light_instance);  // バックライトをパネルにセットします。
    }

    { // タッチスクリーン制御の設定を行います。(必要なければ削除)
      auto cfg = _touch_instance.config();

      cfg.x_min      = 240;     // タッチスクリーンから得られる最小のX値(生の値)
      cfg.x_max      = 3800;    // タッチスクリーンから得られる最大のX値(生の値)
      cfg.y_min      = 3700;    // タッチスクリーンから得られる最小のY値(生の値)
      cfg.y_max      = 200;     // タッチスクリーンから得られる最大のY値(生の値)
      cfg.pin_int    = TP_IRQ;  // INTが接続されているピン番号
      cfg.bus_shared = true;    // 画面と共通のバスを使用している場合 trueを設定
      cfg.offset_rotation = 0;  // 表示とタッチの向きのが一致しない場合の調整 0~7の値で設定

      // SPI接続の場合
      cfg.spi_host = HSPI_HOST; // 使用するSPIを選択 (HSPI_HOST or VSPI_HOST)
      cfg.freq = 1000000;       // SPIクロックを設定
      cfg.pin_sclk = TP_SCLK;   // SCLKが接続されているピン番号
      cfg.pin_mosi = TP_MOSI;   // MOSIが接続されているピン番号
      cfg.pin_miso = TP_MISO;   // MISOが接続されているピン番号
      cfg.pin_cs   = TP_CS;     //   CSが接続されているピン番号

      _touch_instance.config(cfg);
      _panel_instance.setTouch(&_touch_instance);  // タッチスクリーンをパネルにセットします。
    }

    setPanel(&_panel_instance); // 使用するパネルをセットします。
  }
};

フォルダ名に反して Lesson 2 Draw GUI with LovyanGFX には 2.8 インチ用の設定が見つからず、LGFX_ESP32_sample.hpp を元に作成しました。XPT2046 用のクロックが TFT_eSPI 用とは異なりますが、動作は CYD_MP3Player で実証済みです。

描画性能について

参考までに TFT_graphicstest_PDQ の実行結果を貼っておきます。やはり 16MHz では遅く、LovyanGFX がオススメです。

TFT_graphicstest_PDQ 実行結果
TFT_graphicstest_PDQ 実行結果

アップロード時のエラーについて

CrowPanel ではたまに exit status 2 が発生します。そんな時は電源を入れ直すか、それでもダメな場合はフラッシュモード 1 に入れないと書き込みが出来ない事がありました。

A fatal error occurred: Failed to connect to ESP32: No serial data received.
Failed uploading: uploading error: exit status 2
A fatal error occurred: Packet content transfer stopped (received 8 bytes)
Failed uploading: uploading error: exit status 2
Hard resetting via RTS pin...
Failed uploading: uploading error: exit status 2

黄、赤、黒

CYD の低価格は魅力的ですが、もう「黄色い基板」は買いません。惜しい点が幾つかあったり「赤い基板」の見た目が安っぽかったりしますが、何といっても技適付きは大きいです。

さらにお高くなりますが、ESP32S3 と ST7789 を搭載した進化版の「黒い基板」もあるので、お財布に余裕ができたら試してみたいと思います 🤑


  1. BOOT ボタンを押しながら電源を入れて放す、または BOOT ボタンを押したまま RESET ボタンを押して放し、その後 BOOT ボタンを放す