0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

M5UnifiedでカスタムLCDを繋ぐ

0
Last updated at Posted at 2026-03-15

M5Unifiedで、m5シリーズではないカスタムボードに接続されたLCDを扱えるようにします。

Waveshare ESP32-S3 3.5inch Touch LCD Touchscreen Display N16R8 Development Board

https://ja.aliexpress.com/item/1005009056920045.html
https://www.waveshare.com/esp32-s3-touch-lcd-3.5.htm

LCDのコントロールチップとして、「ST7789」を使っているようです。

コントロールロジックとPIN設定の2つに分かれます。

M5Unifiedは、M5GFXを内部で使っており、LovyanGFXをベースとしているため、コントローラをサポートしている場合がありますが、このコントロールチップはありませんでした。
しかし、LovyanGFXにはあったので、そこから拝借しました。

Panel_ST7796.hpp
/*----------------------------------------------------------------------------/
  Lovyan GFX - Graphics library for embedded devices.

Original Source:
 https://github.com/lovyan03/LovyanGFX/

Licence:
 [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt)

Author:
 [lovyan03](https://twitter.com/lovyan03)

Contributors:
 [ciniml](https://github.com/ciniml)
 [mongonta0716](https://github.com/mongonta0716)
 [tobozo](https://github.com/tobozo)
/----------------------------------------------------------------------------*/
#pragma once

#include <lgfx/v1/panel/Panel_LCD.hpp>

namespace lgfx
{
 inline namespace v1
 {
//----------------------------------------------------------------------------

  struct Panel_ST7796  : public Panel_LCD
  {
    Panel_ST7796(void)
    {
      _cfg.panel_width  = _cfg.memory_width  = 320;
      _cfg.panel_height = _cfg.memory_height = 480;

      _cfg.dummy_read_pixel = 8;
    }

  protected:

    static constexpr uint8_t CMD_FRMCTR1 = 0xB1;
    static constexpr uint8_t CMD_FRMCTR2 = 0xB2;
    static constexpr uint8_t CMD_FRMCTR3 = 0xB3;
    static constexpr uint8_t CMD_INVCTR  = 0xB4;
    static constexpr uint8_t CMD_DFUNCTR = 0xB6;
    static constexpr uint8_t CMD_ETMOD   = 0xB7;
    static constexpr uint8_t CMD_PWCTR1  = 0xC0;
    static constexpr uint8_t CMD_PWCTR2  = 0xC1;
    static constexpr uint8_t CMD_PWCTR3  = 0xC2;
    static constexpr uint8_t CMD_PWCTR4  = 0xC3;
    static constexpr uint8_t CMD_PWCTR5  = 0xC4;
    static constexpr uint8_t CMD_VMCTR   = 0xC5;
    static constexpr uint8_t CMD_GMCTRP1 = 0xE0; // Positive Gamma Correction
    static constexpr uint8_t CMD_GMCTRN1 = 0xE1; // Negative Gamma Correction
    static constexpr uint8_t CMD_DOCA    = 0xE8; // Display Output Ctrl Adjust
    static constexpr uint8_t CMD_CSCON   = 0xF0; // Command Set Control

    const uint8_t* getInitCommands(uint8_t listno) const override {
      static constexpr uint8_t list0[] = {
          CMD_CSCON,   1, 0xC3,  // Enable extension command 2 partI
          CMD_CSCON,   1, 0x96,  // Enable extension command 2 partII
          CMD_INVCTR,  1, 0x01,  //1-dot inversion
          CMD_DFUNCTR, 3, 0x80,  //Display Function Control //Bypass
                          0x22,  //Source Output Scan from S1 to S960, Gate Output scan from G1 to G480, scan cycle=2
                          0x3B,  //LCD Drive Line=8*(59+1)
          CMD_DOCA,    8, 0x40,
                          0x8A,
                          0x00,
                          0x00,
                          0x29,  //Source eqaulizing period time= 22.5 us
                          0x19,  //Timing for "Gate start"=25 (Tclk)
                          0xA5,  //Timing for "Gate End"=37 (Tclk), Gate driver EQ function ON
                          0x33,
          CMD_PWCTR2,  1, 0x06,  //Power control2   //VAP(GVDD)=3.85+( vcom+vcom offset), VAN(GVCL)=-3.85+( vcom+vcom offset)
          CMD_PWCTR3,  1, 0xA7,  //Power control 3  //Source driving current level=low, Gamma driving current level=High
          CMD_VMCTR,   1+CMD_INIT_DELAY, 0x18, 120, //VCOM Control    //VCOM=0.9
          CMD_GMCTRP1,14, 0xF0, 0x09, 0x0B, 0x06, 0x04, 0x15, 0x2F,
                          0x54, 0x42, 0x3C, 0x17, 0x14, 0x18, 0x1B,
          CMD_GMCTRN1,14+CMD_INIT_DELAY,
                          0xE0, 0x09, 0x0B, 0x06, 0x04, 0x03, 0x2B,
                          0x43, 0x42, 0x3B, 0x16, 0x14, 0x17, 0x1B,
                          120,
          CMD_CSCON,   1, 0x3C, //Command Set control // Disable extension command 2 partI
          CMD_CSCON,   1, 0x69, //Command Set control // Disable extension command 2 partII

          CMD_SLPOUT, 0+CMD_INIT_DELAY, 130,    // Exit sleep mode
          CMD_IDMOFF, 0,
          CMD_DISPON, 0,
          0xFF,0xFF, // end
      };
      switch (listno) {
      case 0: return list0;
      default: return nullptr;
      }
    }

    void setColorDepth_impl(color_depth_t depth) override
    {
      _write_depth = ((int)depth & color_depth_t::bit_mask) > 16 ? rgb888_3Byte : rgb565_2Byte;
      _read_depth = _write_depth;
    }
  };

//----------------------------------------------------------------------------
 }
}

次が、PIN設定です。
LCDをリセットするために、TCA9554がありますが、ボードによってはない場合もあります。

Panel_ST9996_Pin_Config.cpp
#include <Arduino.h>
#include "main_config.h"

#ifdef _PANEL_ST7796_

#include <Wire.h>
#include <M5Unified.h>

#include <lgfx/v1/touch/Touch_FT5x06.hpp>
#include "Panel_ST7796.hpp"
#include "TCA9554.h"

int Panel_ST7796_display_index = -1;
int Panel_ST7796_display_type = -1;

static lgfx::Panel_ST7796 _panel;
static lgfx::Bus_SPI      _bus;
static lgfx::Touch_FT5x06 _touch;
static lgfx::Light_PWM     _light;
static M5GFX              _display;

#define PANEL_I2C_SDA 8
#define PANEL_I2C_SCL 7
#define PIN_BACKLIGHT 6

static TCA9554 TCA(0x20);

static void lcd_reset(void) {
  TCA.write1(1, 1);
  delay(10);
  TCA.write1(1, 0);
  delay(10);
  TCA.write1(1, 1);
  delay(200);
}

long Panel_ST7796_Pin_Init(void) {
  {
    auto cfg = _bus.config();
    cfg.spi_host   = SPI2_HOST;
    cfg.spi_mode   = 0;
    cfg.freq_write = 40000000;
    cfg.freq_read  = 16000000;
    cfg.pin_sclk   = 5;
    cfg.pin_mosi   = 1;
    cfg.pin_miso   = 2;
    cfg.pin_dc     = 3;
    _bus.config(cfg);
    _panel.setBus(&_bus);
  }

  {
    auto cfg = _panel.config();
    cfg.pin_cs       = -1;
    cfg.pin_rst      = -1;
    cfg.panel_width  = 320;
    cfg.panel_height = 480;
    cfg.offset_x     = 0;
    cfg.offset_y     = 0;
    cfg.bus_shared   = false;
    cfg.invert       = true;
    _panel.config(cfg);
  }

  {
    auto cfg = _light.config();
    cfg.pin_bl      = PIN_BACKLIGHT;
    cfg.invert      = false;
    cfg.freq        = 44100;
    cfg.pwm_channel = 7;
    _light.config(cfg);
    _panel.setLight(&_light);
  }

  {
    auto cfg = _touch.config();
    cfg.freq       = 100000;
    cfg.x_min      = 0;
    cfg.x_max      = 319;
    cfg.y_min      = 0;
    cfg.y_max      = 479;
    cfg.pin_sda    = PANEL_I2C_SDA;
    cfg.pin_scl    = PANEL_I2C_SCL;
    cfg.i2c_port   = 0;
    cfg.i2c_addr   = 0x38;
    cfg.bus_shared = false;
    cfg.pin_int    = -1;
    cfg.pin_rst    = -1;
    _touch.config(cfg);
    _panel.setTouch(&_touch);
  }

  Wire.begin(PANEL_I2C_SDA, PANEL_I2C_SCL);
  TCA.begin();
  TCA.pinMode1(1, OUTPUT);
  lcd_reset();

//  _display.init(&_panel);
//  M5.addDisplay(_display);
  M5.Display.init(&_panel);
  Wire.end();

  Panel_ST7796_display_index = M5.getDisplayCount() - 1;
  Panel_ST7796_display_type = m5gfx::board_t::board_unknown;

  return 0;
}

#endif

あとはこんな感じで使います。

main.cpp
  auto cfg = M5.config();
  M5.begin(cfg);

  delay(500);

  Panel_ST7796_Pin_Init();
  M5.setPrimaryDisplay(Panel_ST7796_display_index);

WT32-SC01

次はちょっと古いですが、コントロールチップが「ST7789」を使っています。

ちょうどこのコントロールロジックがついていたのでそのまま使います。

lgfx/v1/panel/Panel_ST7789.hpp

次が、PIN設定です。

Panel_ST7789_Pin_Config.cpp
#include <Arduino.h>
#include "main_config.h"

#ifdef _PANEL_ST7789_

#include <M5Unified.h>

#include <lgfx/v1/panel/Panel_ST7789.hpp>
#include <lgfx/v1/touch/Touch_FT5x06.hpp>

int Panel_ST7789_display_index = -1;
int Panel_ST7789_display_type = -1;

static lgfx::Panel_ST7789  _panel;
static lgfx::Bus_SPI       _bus;
static lgfx::Light_PWM     _light;
static lgfx::Touch_FT5x06  _touch;
//static M5GFX              _display;

// WT32-SC01 pin assignments
// LCD (ST7796): SPI2/HSPI
//   SCLK=14, MOSI=13, MISO=12, DC=21, CS=15, RST=22, BL=23
// Touch (FT6336U / FT5x06 compatible): I2C
//   SDA=18, SCL=19, INT=39

long Panel_ST7789_Pin_Init(void) {
  {
    auto cfg = _bus.config();
    cfg.spi_host    = SPI2_HOST;
    cfg.spi_mode    = 0;
    cfg.freq_write  = 40000000;
    cfg.freq_read   = 16000000;
    cfg.spi_3wire   = false;
    cfg.pin_sclk    = 14;
    cfg.pin_mosi    = 13;
    cfg.pin_miso    = 12;
    cfg.pin_dc      = 21;
    _bus.config(cfg);
    _panel.setBus(&_bus);
  }

  // Panel (ST7796 / 320x480, CS=15, RST=22)
  {
    auto cfg = _panel.config();
    cfg.pin_cs           = 15;
    cfg.pin_rst          = 22;
    cfg.pin_busy         = -1;
    cfg.memory_width     = 320;
    cfg.memory_height    = 480;
    cfg.panel_width      = 320;
    cfg.panel_height     = 480;
    cfg.offset_x         = 0;
    cfg.offset_y         = 0;
    cfg.offset_rotation  = 6;
    cfg.dummy_read_pixel = 8;
    cfg.dummy_read_bits  = 1;
    cfg.readable         = false;
    cfg.invert           = false;
    cfg.rgb_order        = false;
    cfg.dlen_16bit       = false;
    cfg.bus_shared       = false;
    _panel.config(cfg);
  }

  // Backlight (BL=23, PWM ch7)
  {
    auto cfg = _light.config();
    cfg.pin_bl      = 23;
    cfg.invert      = false;
    cfg.freq        = 44100;
    cfg.pwm_channel = 7;
    _light.config(cfg);
    _panel.setLight(&_light);
  }

  // Touch (FT6336U / FT5x06: I2C1, SDA=18, SCL=19, INT=39, addr=0x38)
  {
    auto cfg = _touch.config();
    cfg.x_min           = 319;
    cfg.x_max           = 0;
    cfg.y_min           = 479;
    cfg.y_max           = 0;
    cfg.pin_int         = 39;
    cfg.bus_shared      = false;
    cfg.offset_rotation = 0;
    cfg.i2c_port        = 1;
    cfg.i2c_addr        = 0x38;
    cfg.pin_sda         = 18;
    cfg.pin_scl         = 19;
    cfg.freq            = 400000;
    _touch.config(cfg);
    _panel.setTouch(&_touch);
  }

//  _display.init(&_panel);
//  M5.addDisplay(_display);
  M5.Display.init(&_panel);

  Panel_ST7789_display_index = M5.getDisplayCount() - 1;
  Panel_ST7789_display_type = m5gfx::board_t::board_unknown;

  return 0;
};

#endif

使うときには以下です。
実はちょうどこのボードは、GPIO22を使っており、M5Unifiedが内部的につかんでおり、解放してから初期化しました。

main.cpp
  auto cfg = M5.config();
  M5.begin(cfg);

  delay(500);

  M5.In_I2C.release();
  gpio_reset_pin(GPIO_NUM_21);
  gpio_reset_pin(GPIO_NUM_22);

  Panel_ST7789_Pin_Init();
  M5.setPrimaryDisplay(Panel_ST7789_display_index);

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?