4.3インチタッチパネル付きESP32-8048S043

概要

上記の解像度800×480版の詳細記事です。

LovyanGFXの使い方

PSRAM有効化

現在PSRAMを使うことが必須です。無効な状態で実行するとリセットがかかるので注意してください。また、PSRAMを搭載しているボードなので、通常は有効にして利用したほうがよいと思います。ただしちょっと有効化が面倒です。

Arduino IDE

まず、Arduino IDEの場合にはPSRAMを「OPI PSRAM」を選択する必要があります。ESP32は8MBのPSRAMを利用しても4MBまでしか一度にアクセスすることができませんでしたが、ESP32-S3では8MB全部アクセスできるようになりました。たぶん、その影響で選択肢が増えています。

PlatformIO

[env:esp32s3box]
platform = espressif32
board = esp32s3box
framework = arduino
monitor_speed = 115200
build_flags =
    -DCORE_DEBUG_LEVEL=5             ;0:None, 1:Error, 2:Warn, 3:Info, 4:Debug, 5:Verbose
lib_deps =
  lovyan03/LovyanGFX

「esp32-s3-devkitc-1」はPSRAMを搭載していないボードのため、「esp32s3box」を利用します。iniファイルから指定できそうですが、現状のところ指定したらビルドができなくなってしまいました。

platform-espressif32/esp32s3box.json at develop · platformio/platform-espressif32
Espressif 32: development platform for PlatformIO. Contribute to platformio/platform-espressif32 development by creating an account on GitHub.

上記がボード定義になります。

  "build": {
    "arduino":{
      "ldscript": "esp32s3_out.ld",
      "memory_type": "qio_opi"
    },

冒頭部分のmemory_typeが「qio_opi」になっていないとPSRAMが使えませんでした。

board_build.arduino.memory_type = dio_opi

上記の指定で大丈夫と書いてあるのですが、指定がないボードで指定するとビルドに失敗します。

シンプルスケッチ例

#include <Arduino.h>
#include <driver/i2c.h>
#include <LovyanGFX.hpp>
#include <lgfx_user/LGFX_ESP32S3_RGB_ESP32-8048S043.h>

LGFX display;

void setup(void)
{
  display.init();
  display.setTextSize(2);
  display.fillScreen(TFT_BLACK);
}

uint32_t count = ~0;
void loop(void)
{
  display.startWrite();

  display.setRotation(++count & 7);
  display.setColorDepth((count & 8) ? 16 : 24);

  if (count % 8 == 0)
  {
    display.fillScreen(TFT_BLACK);
  }

  display.setTextColor(TFT_WHITE);
  display.drawNumber(display.getRotation(), 16, 0);

  display.setTextColor(0xFF0000U);
  display.drawString("R", 30, 16);
  display.setTextColor(0x00FF00U);
  display.drawString("G", 40, 16);
  display.setTextColor(0x0000FFU);
  display.drawString("B", 50, 16);

  display.drawRect(30, 30, display.width() - 60, display.height() - 60, count * 7);
  display.drawFastHLine(0, 0, 10);

  display.endWrite();

  delay(500);
}

上記で動きます。

LovyanGFX/LGFX_ESP32S3_RGB_ESP32-8048S043.h at 0.5.0 · lovyan03/LovyanGFX
SPI LCD graphics library for ESP32 (ESP-IDF/ArduinoESP32) / ESP8266 (ArduinoESP8266) / SAMD51(Seeed ArduinoSAMD51) - LovyanGFX/LGFX_ESP32S3_RGB_ESP32-8048S043.h...

上記にこのボードの設定例があります。ただしタッチパネルが動きませんでした。

カスタム設定

#include <driver/i2c.h>
#include <LovyanGFX.hpp>

#include <lgfx/v1/platforms/esp32s3/Panel_RGB.hpp>
#include <lgfx/v1/platforms/esp32s3/Bus_RGB.hpp>

class LGFX : public lgfx::LGFX_Device {
public:

  lgfx::Bus_RGB _bus_instance;
  lgfx::Panel_RGB _panel_instance;
  lgfx::Light_PWM _light_instance;
  lgfx::Touch_GT911 _touch_instance;

  LGFX(void) {
    {
      auto cfg = _panel_instance.config();

      cfg.memory_width = 800;
      cfg.memory_height = 480;
      cfg.panel_width = 800;
      cfg.panel_height = 480;

      cfg.offset_x = 0;
      cfg.offset_y = 0;

      _panel_instance.config(cfg);
    }

    {
      auto cfg = _panel_instance.config_detail();

      cfg.use_psram = 1;

      _panel_instance.config_detail(cfg);
    }

    {
      auto cfg = _bus_instance.config();
      cfg.panel = &_panel_instance;
      cfg.pin_d0 = GPIO_NUM_8;    // B0
      cfg.pin_d1 = GPIO_NUM_3;    // B1
      cfg.pin_d2 = GPIO_NUM_46;   // B2
      cfg.pin_d3 = GPIO_NUM_9;    // B3
      cfg.pin_d4 = GPIO_NUM_1;    // B4
      cfg.pin_d5 = GPIO_NUM_5;    // G0
      cfg.pin_d6 = GPIO_NUM_6;    // G1
      cfg.pin_d7 = GPIO_NUM_7;    // G2
      cfg.pin_d8 = GPIO_NUM_15;   // G3
      cfg.pin_d9 = GPIO_NUM_16;   // G4
      cfg.pin_d10 = GPIO_NUM_4;   // G5
      cfg.pin_d11 = GPIO_NUM_45;  // R0
      cfg.pin_d12 = GPIO_NUM_48;  // R1
      cfg.pin_d13 = GPIO_NUM_47;  // R2
      cfg.pin_d14 = GPIO_NUM_21;  // R3
      cfg.pin_d15 = GPIO_NUM_14;  // R4

      cfg.pin_henable = GPIO_NUM_40;
      cfg.pin_vsync = GPIO_NUM_41;
      cfg.pin_hsync = GPIO_NUM_39;
      cfg.pin_pclk = GPIO_NUM_42;
      cfg.freq_write = 16000000;

      cfg.hsync_polarity = 0;
      cfg.hsync_front_porch = 8;
      cfg.hsync_pulse_width = 4;
      cfg.hsync_back_porch = 16;
      cfg.vsync_polarity = 0;
      cfg.vsync_front_porch = 4;
      cfg.vsync_pulse_width = 4;
      cfg.vsync_back_porch = 4;
      cfg.pclk_idle_high = 1;
      _bus_instance.config(cfg);
    }
    _panel_instance.setBus(&_bus_instance);

    {
      auto cfg = _light_instance.config();
      cfg.pin_bl = GPIO_NUM_2;
      _light_instance.config(cfg);
    }
    _panel_instance.light(&_light_instance);

    {
      auto cfg = _touch_instance.config();
      cfg.x_min = 25;
      cfg.x_max = 473;
      cfg.y_min = 14;
      cfg.y_max = 264;
      cfg.pin_int = -1;
      cfg.bus_shared = true;
      cfg.offset_rotation = 0;
      // I2C接続
      cfg.i2c_port = I2C_NUM_1;
      cfg.pin_sda = GPIO_NUM_19;
      cfg.pin_scl = GPIO_NUM_20;
      cfg.freq = 400000;
      cfg.i2c_addr = 0x5D;  // 0x5D , 0x14
      _touch_instance.config(cfg);
      _panel_instance.setTouch(&_touch_instance);
    }

    setPanel(&_panel_instance);
  }
};

LGFX display;

void setup(void) {
  Serial.begin(115200);
  display.init();

  display.setTextSize(2);

  if (display.touch() && true) {
    if (display.width() < display.height()) display.setRotation(display.getRotation() ^ 1);

    display.setTextDatum(textdatum_t::middle_center);
    display.drawString("touch the arrow marker.", display.width() >> 1, display.height() >> 1);
    display.setTextDatum(textdatum_t::top_left);

    std::uint16_t fg = TFT_WHITE;
    std::uint16_t bg = TFT_BLACK;
    if (display.isEPD()) std::swap(fg, bg);
    uint16_t calibrateData[8];
    display.calibrateTouch(calibrateData, fg, bg, std::max(display.width(), display.height()) >> 3);
    Serial.printf("[0] x_min = %d\n", calibrateData[0]);
    Serial.printf("[1] y_min = %d\n", calibrateData[1]);
    Serial.printf("[2] x_min = %d\n", calibrateData[2]);
    Serial.printf("[3] y_max = %d\n", calibrateData[3]);
    Serial.printf("[4] x_max = %d\n", calibrateData[4]);
    Serial.printf("[5] y_min = %d\n", calibrateData[5]);
    Serial.printf("[6] x_max = %d\n", calibrateData[6]);
    Serial.printf("[7] y_max = %d\n", calibrateData[7]);
    Serial.printf("x_min = %d\n", (calibrateData[0] + calibrateData[2]) / 2);
    Serial.printf("x_max = %d\n", (calibrateData[4] + calibrateData[6]) / 2);
    Serial.printf("y_min = %d\n", (calibrateData[1] + calibrateData[5]) / 2);
    Serial.printf("y_max = %d\n", (calibrateData[3] + calibrateData[3]) / 2);
  }

  display.fillScreen(TFT_BLACK);
}

uint32_t count = ~0;
void loop(void) {
  display.startWrite();
  display.setRotation(++count & 7);
  display.setColorDepth((count & 8) ? 16 : 24);

  display.setTextColor(TFT_WHITE);
  display.drawNumber(display.getRotation(), 16, 0);

  display.setTextColor(0xFF0000U);
  display.drawString("R", 30, 16);
  display.setTextColor(0x00FF00U);
  display.drawString("G", 40, 16);
  display.setTextColor(0x0000FFU);
  display.drawString("B", 50, 16);

  display.drawRect(30, 30, display.width() - 60, display.height() - 60, count * 7);
  display.drawFastHLine(0, 0, 10);

  int32_t x, y;
  if (display.getTouch(&x, &y)) {
    lgfx::touch_point_t tp;
    display.getTouchRaw(&tp);
    Serial.printf("raw_x = %d, raw_y = %d\n", tp.x, tp.y);

    display.fillRect(x - 2, y - 2, 5, 5, count * 7);
  }

  display.endWrite();
}

まだなんかおかしいです。以下変更点です。

タッチパネルの通知

      cfg.pin_int = -1;

上記を未使用にしています。

手元の基板では上記のR17が未実装なので、IO18に接続されていませんでした。おそらく圧電式のタッチパネルはR5でプルアップ。静電容量のタッチパネルはR5を未実装にして、R17で接続という使い分けだと思います。

私のはR5でプルアップされていて、R17が未実装なので圧電式の実装になっています。。。ただしい基板実装であればGPIO_NUM_18を指定すると、変更があった場合のみI2C経由で取得することになりますが、現状は定期的にI2Cで取得する形となります。

タッチパネルのアドレス変更

      cfg.i2c_addr = 0x5D;  // 0x5D , 0x14

このタッチパネルは2種類のアドレスがあって、手元のは0x5Dだったため変更しています。動かないときにはI2Cスキャナなどを利用して確認してください。

なんかへん?

タッチパネルの座標が画面を回したときにちゃんと追従できていませんね。getTouchRaw()の値は問題なかったので、offset_rotationなどの初期回転方向がずれいている可能性があります。

まとめ

設定例がありましたが、おもったより動かすのに手がかかりました。タッチパネルはもう少し調整が必要そうでした。

コメント

タイトルとURLをコピーしました