SenseCAP Indicator D1でLovyanGFXを使ってみる

# はじめに

M5Stackの画面より大きなデバイスが欲しくて探していたところ、SeeedStudioのSenseCAP Indicator D1を見つけたので使ってみましたが、Adruino環境で使うには少し苦労しました。

https://www.seeedstudio.com/SenseCAP-Indicator-D1-p-5643.html

https://www.switch-science.com/products/9104

# LovyanGFX

いつもお世話になっております。

```C++:main.cpp
#include <Arduino.h>

#include <LovyanGFX.hpp>

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

namespace lgfx
{
  struct Panel_SenseCapD1 : public lgfx::Panel_ST7701
  {
    static constexpr int32_t i2c_freq = 400000;
    static constexpr int_fast16_t pca9535_i2c_addr = 0x20;
    static constexpr int_fast16_t i2c_port = I2C_NUM_0;
    static constexpr int_fast16_t i2c_sda = GPIO_NUM_39;
    static constexpr int_fast16_t i2c_scl = GPIO_NUM_40;
    Panel_SenseCapD1(void)
    {
    }
    bool init(bool use_reset) override
    {
      lgfx::i2c::init(i2c_port, i2c_sda, i2c_scl);

      lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x06, 0, ~(1<<4), i2c_freq);  // IO0_4: output
      lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x06, 0, ~(1<<5), i2c_freq);  // IO0_5: output
      lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x07, 0, ~(1<<0), i2c_freq);  // IO1_0: output
      lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x07, 0, ~(1<<2), i2c_freq);  // IO1_10: output

      if (!Panel_RGB::init(use_reset))
      {
        return false;
      }

      int32_t pin_mosi = _config_detail.pin_mosi;
      int32_t pin_sclk = _config_detail.pin_sclk;
      if (pin_mosi >= 0 && pin_sclk >= 0)
      {
        lgfx::gpio::pin_backup_t backup_pins[] = { (gpio_num_t)pin_mosi, (gpio_num_t)pin_sclk };

        lgfx::gpio_lo(pin_mosi);
        lgfx::pinMode(pin_mosi, pin_mode_t::output);
        lgfx::gpio_lo(pin_sclk);
        lgfx::pinMode(pin_sclk, pin_mode_t::output);


  //      int32_t pin_cs = _config_detail.pin_cs;
  //      lgfx::gpio_lo(pin_cs);
        cs_control(false);

        writeCommand(0xFF, 1);
        writeData(0x77, 1);
        writeData(0x01, 1);
        writeData(0x00, 2);
        writeData(0x10, 1);

        // 0xC0 : LNSET : Display Line Setting
        writeCommand(0xC0, 1);
        uint32_t line1 = (_cfg.panel_height >> 3) + 1;
        uint32_t line2 = (_cfg.panel_height >> 1) & 3;
        writeData(line1 + (line2 ? 0x80 : 0x00), 1);
        writeData(line2, 1);

        // 0xC3 : RGBCTRL
        auto cfg = ((Bus_RGB*)_bus)->config();
        writeCommand(0xC3, 1);
        uint32_t rgbctrl = 0;
        if ( cfg.de_idle_high  ) rgbctrl += 0x01;
        if ( cfg.pclk_idle_high) rgbctrl += 0x02;
        if (!cfg.hsync_polarity) rgbctrl += 0x04;
        if (!cfg.vsync_polarity) rgbctrl += 0x08;
        writeData(rgbctrl, 1);
        writeData(0x10, 1);
        writeData(0x08, 1);

        for (uint8_t i = 0; auto cmds = getInitCommands(i); i++)
        {
          command_list(cmds);
        }

  //      lgfx::gpio_hi(pin_cs);
        cs_control(true);
        for (auto &bup : backup_pins) { bup.restore(); }
      }

      return true;
    }

    void reset(void) override
    {
      lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x02, 0, ~(1<<5), i2c_freq);  // LCD_RST
      lgfx::delay(40);
      lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x02, (1<<5), ~0, i2c_freq);  // LCD_RST
      lgfx::delay(140);
    }

    void cs_control(bool flg) override
    {
      if (flg)
      {
        lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x02, (1<<4), ~0, i2c_freq);  // LCD_CS
      }
      else
      {
        lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x02, 0, ~(1<<4), i2c_freq);  // LCD_CS
      }
    }
  };

  struct Touch_SenseCapD1 : public lgfx::Touch_FT5x06
  {
    static constexpr int32_t i2c_freq = 400000;
    static constexpr int_fast16_t pca9535_i2c_addr = 0x20;
    static constexpr int_fast16_t i2c_port = I2C_NUM_0;
    Touch_SenseCapD1(void)
    {
    }

    bool init(void) override
    {
      lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x02, 0, ~(1<<7), i2c_freq);  // TP_RST
      lgfx::delay(10);
      lgfx::i2c::writeRegister8(i2c_port, pca9535_i2c_addr, 0x02, (1<<7), ~0, i2c_freq);  // TP_RST
      lgfx::delay(10);

      return lgfx::Touch_FT5x06::init();
    }
  };
}

class LGFX : public lgfx::LGFX_Device
{
public:

  lgfx::Bus_RGB          _bus_instance;
  lgfx::Panel_SenseCapD1 _panel_instance;
  lgfx::Touch_SenseCapD1 _touch_instance;
  lgfx::Light_PWM        _light_instance;

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

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

      cfg.offset_x = 0;
      cfg.offset_y = 0;
      cfg.offset_rotation  = 2;

      _panel_instance.config(cfg);
    }

    {
      auto cfg = _panel_instance.config_detail();

      cfg.use_psram = 1;
      cfg.pin_cs = -1;
      cfg.pin_sclk = 41;
//      cfg.pin_miso = 47;
      cfg.pin_mosi = 48;

      _panel_instance.config_detail(cfg);
    }

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

      cfg.pin_henable = GPIO_NUM_18;
      cfg.pin_vsync   = GPIO_NUM_17;
      cfg.pin_hsync   = GPIO_NUM_16;
      cfg.pin_pclk    = GPIO_NUM_21;
      cfg.freq_write  = 16000000;

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

    {
      auto cfg = _touch_instance.config();
      cfg.x_min      = 0;
      cfg.x_max      = 480;
      cfg.y_min      = 0;
      cfg.y_max      = 480;
      cfg.bus_shared = true;

      cfg.i2c_port   = I2C_NUM_0;
      cfg.i2c_addr   = 0x48;

      cfg.pin_int    = GPIO_NUM_42;
      cfg.pin_sda    = GPIO_NUM_39;
      cfg.pin_scl    = GPIO_NUM_40;
      cfg.pin_rst    = GPIO_NUM_NC;

      cfg.freq       = 400000;
      _touch_instance.config(cfg);
      _panel_instance.setTouch(&_touch_instance);
    }

    {
      auto cfg = _light_instance.config();
      cfg.pin_bl = GPIO_NUM_45;
      cfg.pwm_channel = 0;
      cfg.invert = true;
      _light_instance.config(cfg);
    }
      _panel_instance.light(&_light_instance);

    setPanel(&_panel_instance);
  }
};

static LGFX lcd;



void setup() {

  pinMode(38, INPUT);

  lcd.init();
  lcd.fillScreen(TFT_BLACK);
  lcd.drawString("Start", 0, 0);
}

void loop() {
  int32_t x, y;
  if (lcd.getTouch(&x, &y)) {
    lgfx::touch_point_t tp;
    uint_fast8_t r = lcd.getTouchRaw(&tp);
    ESP_LOGI("test", "raw_x = %d, raw_y = %d", tp.x, tp.y);
  }
  if (digitalRead(38) == 0) {
    ESP_LOGI("test", "pressed");
  }
  delay(100);
}
```

```ini:platformio.ini
[env:esp32s3box]
platform = espressif32
board = esp32s3box
framework = arduino
monitor_speed = 115200
build_flags = 
	-DCORE_DEBUG_LEVEL=5
lib_deps = 
	lovyan03/LovyanGFX@^1.1.8

```

Long-shipさんのページを参考にboardにesp32s3boxを指定してみましたが、本機はFlashメモリが8Mバイトでesp32s3boxの定義とは異なっているためブート時にエラーが発生するので、定義を変更しています。

```json:~/.platformio/platforms/espressif32/boards/esp32s3box.json

...

  "name": "Espressif ESP32-S3-Box",
  "upload": {
    "flash_size": "8MB", <-ここ
    "maximum_ram_size": 327680,
    "maximum_size": 8388608, <-ここ
    "require_upload_port": true,
    "speed": 460800 <-ここ
  },
  "url": "https://www.adafruit.com/product/5290",
  "vendor": "Espressif"
}
```


# 参考にしたページ

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

https://lang-ship.com/blog/work/esp32-8048s043/