From 0313d2617453ff2835d4a8d4d3debf193fee1b9e Mon Sep 17 00:00:00 2001 From: luoweiyuan Date: Fri, 21 Aug 2026 11:20:31 +0800 Subject: [PATCH] Add M5Stack CoreP4X display support 1. Detect CoreP4X on the internal I2C bus using GPIO11 (SDA) and GPIO9 (SCL), with M5IOE1 at 0x4F and M5PM1 at 0x6E. 2. Add ST7102 MIPI DSI display and Touch_CST3530 touch support. --- CMakeLists.txt | 18 ++- src/M5GFX.cpp | 141 ++++++++++++++++++ src/lgfx/v1/platforms/esp32p4/Bus_DSI.cpp | 2 +- src/lgfx/v1/platforms/esp32p4/Panel_DSI.cpp | 44 ++++-- src/lgfx/v1/platforms/esp32p4/Panel_DSI.hpp | 3 + .../v1/platforms/esp32p4/Panel_ST7102.hpp | 118 +++++++++++++++ src/lgfx/v1/touch/Touch_CSTxxx.cpp | 96 ++++++++++++ src/lgfx/v1/touch/Touch_CSTxxx.hpp | 28 ++++ 8 files changed, 431 insertions(+), 19 deletions(-) create mode 100644 src/lgfx/v1/platforms/esp32p4/Panel_ST7102.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c349e0b0..d4b121e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,12 +10,22 @@ file(GLOB SRCS src/lgfx/v1/misc/*.cpp src/lgfx/v1/panel/*.cpp src/lgfx/v1/platforms/esp32/*.cpp - src/lgfx/v1/platforms/esp32c3/*.cpp - src/lgfx/v1/platforms/esp32s2/*.cpp - src/lgfx/v1/platforms/esp32s3/*.cpp - src/lgfx/v1/platforms/esp32p4/*.cpp src/lgfx/v1/touch/*.cpp ) + +# Keep common ESP32 sources, then add only the active chip's implementation. +# This also prevents PlatformIO's flat object layout from colliding on same-named +# sources that live in different platform directories. +if(IDF_TARGET STREQUAL "esp32c3") + file(GLOB PLATFORM_SRCS src/lgfx/v1/platforms/esp32c3/*.cpp) +elseif(IDF_TARGET STREQUAL "esp32s2") + file(GLOB PLATFORM_SRCS src/lgfx/v1/platforms/esp32s2/*.cpp) +elseif(IDF_TARGET STREQUAL "esp32s3") + file(GLOB PLATFORM_SRCS src/lgfx/v1/platforms/esp32s3/*.cpp) +elseif(IDF_TARGET STREQUAL "esp32p4") + file(GLOB PLATFORM_SRCS src/lgfx/v1/platforms/esp32p4/*.cpp) +endif() +list(APPEND SRCS ${PLATFORM_SRCS}) set(COMPONENT_SRCS ${SRCS}) if (IDF_VERSION_MAJOR GREATER_EQUAL 6) diff --git a/src/M5GFX.cpp b/src/M5GFX.cpp index cfd1cd09..a64627ee 100644 --- a/src/M5GFX.cpp +++ b/src/M5GFX.cpp @@ -35,6 +35,7 @@ #include "lgfx/v1/platforms/esp32p4/Bus_DSI.hpp" #include "lgfx/v1/platforms/esp32p4/Panel_ILI9881C.hpp" +#include "lgfx/v1/platforms/esp32p4/Panel_ST7102.hpp" #include "lgfx/v1/platforms/esp32p4/Panel_ST7121.hpp" #include "lgfx/v1/platforms/esp32p4/Panel_ST7123.hpp" #include "lgfx/v1/platforms/esp32p4/Touch_ST7123.hpp" @@ -209,6 +210,34 @@ namespace m5gfx return false; } +#if defined (CONFIG_IDF_TARGET_ESP32P4) + struct Light_M5CoreP4X : public lgfx::ILight + { + bool init(uint8_t brightness) override + { + static constexpr uint16_t pwm_freq = 1000; + const uint8_t freq_data[] = { + 0x25, static_cast(pwm_freq), static_cast(pwm_freq >> 8) + }; + lgfx::i2c::transactionWrite(in_i2c_port, m5ioe1_i2c_addr, + freq_data, sizeof(freq_data), m5ioe1_i2c_freq); + lgfx::i2c::bitOn(in_i2c_port, m5ioe1_i2c_addr, 0x06, 1u << 0, m5ioe1_i2c_freq); + setBrightness(brightness); + return true; + } + + void setBrightness(uint8_t brightness) override + { + uint16_t duty = (brightness << 4) | (brightness >> 4); + const uint8_t duty_data[] = { + 0x1B, static_cast(duty), static_cast(0x80 | (duty >> 8)) + }; + lgfx::i2c::transactionWrite(in_i2c_port, m5ioe1_i2c_addr, + duty_data, sizeof(duty_data), m5ioe1_i2c_freq); + } + }; +#endif + #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32) static constexpr std::int32_t axp_i2c_freq = 400000; static constexpr std::uint_fast8_t axp_i2c_addr = 0x34; @@ -2921,6 +2950,117 @@ The usage of each pin is as follows. if (pkg_ver == 0) // pkg_ver == EFUSE_RD_CHIP_VER_PKG_ { + if (board == 0 || board == board_t::board_M5CoreP4X) + { + static constexpr uint8_t corep4x_i2c_addr_list[] = { + 0x4Fu, // M5IOE1 + 0x6Eu, // M5PM1 + 0u + }; + uint32_t i2c_result = _detect_i2c_device(GPIO_NUM_11, GPIO_NUM_9, corep4x_i2c_addr_list); + if (i2c_result == ~0u) { + lgfx::i2c::init(in_i2c_port, GPIO_NUM_11, GPIO_NUM_9); + board = board_t::board_M5CoreP4X; + ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5CoreP4X"); + + lgfx::i2c::writeRegister8(in_i2c_port, m5pm1_i2c_addr, 0x09, 0x00, 0, m5pm1_i2c_freq); + lgfx::i2c::writeRegister8(in_i2c_port, m5pm1_i2c_addr, 0x0A, 0x00, 0, m5pm1_i2c_freq); + lgfx::i2c::bitOn(in_i2c_port, m5pm1_i2c_addr, 0x06, 1u << 3, m5pm1_i2c_freq); + + // M5IOE1 G8/G9/G10/G11 control touch reset, backlight, LCD power, + // and LCD reset. G12 supplies the shared 3V3 rail for MBUS, TF card, IMU, + // infrared and Ethernet. + static constexpr uint8_t touch_reset_bit = 1u << 7; + static constexpr uint8_t display_bits_h = 0b00000111; + static constexpr uint8_t shared_power_bit = 1u << 3; + lgfx::i2c::writeRegister8(in_i2c_port, m5ioe1_i2c_addr, 0x23, 0x00, 0, m5ioe1_i2c_freq); + lgfx::i2c::bitOff(in_i2c_port, m5ioe1_i2c_addr, 0x13, touch_reset_bit, m5ioe1_i2c_freq); + lgfx::i2c::bitOff(in_i2c_port, m5ioe1_i2c_addr, 0x14, display_bits_h, m5ioe1_i2c_freq); + lgfx::i2c::bitOff(in_i2c_port, m5ioe1_i2c_addr, 0x14, shared_power_bit, m5ioe1_i2c_freq); + lgfx::i2c::bitOn( in_i2c_port, m5ioe1_i2c_addr, 0x03, touch_reset_bit, m5ioe1_i2c_freq); + lgfx::i2c::bitOn( in_i2c_port, m5ioe1_i2c_addr, 0x04, display_bits_h, m5ioe1_i2c_freq); + lgfx::i2c::bitOn( in_i2c_port, m5ioe1_i2c_addr, 0x04, shared_power_bit, m5ioe1_i2c_freq); + lgfx::i2c::bitOn(in_i2c_port, m5ioe1_i2c_addr, 0x05, touch_reset_bit, m5ioe1_i2c_freq); + lgfx::i2c::bitOn(in_i2c_port, m5ioe1_i2c_addr, 0x06, display_bits_h, m5ioe1_i2c_freq); + lgfx::i2c::bitOn(in_i2c_port, m5ioe1_i2c_addr, 0x06, shared_power_bit, m5ioe1_i2c_freq); + + static constexpr uint16_t pwm_freq = 1000; + const uint8_t freq_data[] = { + 0x25, static_cast(pwm_freq), static_cast(pwm_freq >> 8) + }; + const uint8_t duty_data[] = { 0x1B, 0x00, 0x80 }; + lgfx::i2c::transactionWrite(in_i2c_port, m5ioe1_i2c_addr, + freq_data, sizeof(freq_data), m5ioe1_i2c_freq); + lgfx::i2c::transactionWrite(in_i2c_port, m5ioe1_i2c_addr, + duty_data, sizeof(duty_data), m5ioe1_i2c_freq); + lgfx::delay(150); + +#if !CONFIG_SPIRAM + ESP_LOGE(LIBRARY_NAME, "M5CoreP4X needs PSRAM enabled"); +#else + auto bus_dsi = new Bus_DSI(); + _bus_last.reset(bus_dsi); + auto bus_cfg = bus_dsi->config(); + bus_cfg.bus_id = 0; + bus_cfg.lane_num = 2; + bus_cfg.lane_mbps = 600; + bus_cfg.ldo_chan_id = 3; + bus_cfg.ldo_voltage_mv = 2500; + bus_dsi->config(bus_cfg); + if (bus_dsi->init()) { + lgfx::delay(50); + auto p = new Panel_ST7102(); + _panel_last.reset(p); + auto det = p->config_detail(); + det.dpi_freq_mhz = 24; + det.hsync_back_porch = 40; + det.hsync_pulse_width = 2; + det.hsync_front_porch = 40; + det.vsync_back_porch = 8; + det.vsync_pulse_width = 4; + det.vsync_front_porch = 200; + p->config_detail(det); + + auto cfg = p->config(); + cfg.memory_width = 480; + cfg.memory_height = 480; + cfg.panel_width = 480; + cfg.panel_height = 480; + cfg.readable = false; + cfg.rgb_order = true; + cfg.bus_shared = false; + cfg.offset_x = 0; + cfg.offset_y = 0; + cfg.offset_rotation = 2; + cfg.pin_cs = GPIO_NUM_NC; + cfg.pin_rst = GPIO_NUM_NC; + p->config(cfg); + p->setBus(bus_dsi); + + auto t = new lgfx::Touch_CST3530(); + _touch_last.reset(t); + auto tcfg = t->config(); + tcfg.pin_rst = -1; + tcfg.pin_sda = GPIO_NUM_11; + tcfg.pin_scl = GPIO_NUM_9; + tcfg.pin_int = GPIO_NUM_1; + tcfg.freq = 400000; + tcfg.x_min = 0; + tcfg.x_max = 479; + tcfg.y_min = 0; + tcfg.y_max = 479; + tcfg.i2c_port = I2C_NUM_1; + tcfg.bus_shared = false; + tcfg.offset_rotation = 2; + t->config(tcfg); + _panel_last->setTouch(t); + } + _set_backlight(new Light_M5CoreP4X()); +#endif + goto init_clear; + } + } + if (board == 0 || board == board_t::board_M5Tab5 || board == board_t::board_M5Tab5X) { // SDA = GPIO_NUM_31 @@ -3709,6 +3849,7 @@ The usage of each pin is as follows. case board_M5Station: title = "M5Station"; break; case board_M5StopWatch: title = "M5StopWatch"; break; case board_M5ChainCaptain: title = "M5ChainCaptain"; break; + case board_M5CoreP4X: title = "M5CoreP4X"; break; case board_M5AtomS3: title = "M5AtomS3"; break; case board_M5AtomS3R: title = "M5AtomS3R"; break; case board_M5Dial: title = "M5Dial"; break; diff --git a/src/lgfx/v1/platforms/esp32p4/Bus_DSI.cpp b/src/lgfx/v1/platforms/esp32p4/Bus_DSI.cpp index 98edfbda..7daf8cee 100644 --- a/src/lgfx/v1/platforms/esp32p4/Bus_DSI.cpp +++ b/src/lgfx/v1/platforms/esp32p4/Bus_DSI.cpp @@ -41,7 +41,7 @@ namespace lgfx ldo_cfg.chan_id = _cfg.ldo_chan_id; ldo_cfg.voltage_mv = _cfg.ldo_voltage_mv; - esp_lcd_dbi_io_config_t dbi_config; + esp_lcd_dbi_io_config_t dbi_config = {}; dbi_config.virtual_channel = 0; dbi_config.lcd_cmd_bits = _cfg.lcd_cmd_bits; dbi_config.lcd_param_bits = _cfg.lcd_param_bits; diff --git a/src/lgfx/v1/platforms/esp32p4/Panel_DSI.cpp b/src/lgfx/v1/platforms/esp32p4/Panel_DSI.cpp index 9462adc1..58ce42de 100644 --- a/src/lgfx/v1/platforms/esp32p4/Panel_DSI.cpp +++ b/src/lgfx/v1/platforms/esp32p4/Panel_DSI.cpp @@ -38,16 +38,10 @@ namespace lgfx auto bus = getBusDSI(); if (bus == nullptr) { return false; } - const uint8_t* params; - for (size_t i = 0; nullptr != (params = getInitParams(i)); ++i) - { - size_t len; - while (0 != (len = params[0])) { -// printf("cmd: %02x, len: %d\n", params[1], len); - bus->writeParams(params[1], ¶ms[2], len - 1); - params += len + 1; - } - vTaskDelay(pdMS_TO_TICKS(getInitDelay(i))); + const bool init_in_command_mode = initInCommandMode(); + if (!init_in_command_mode + && ESP_OK != esp_lcd_panel_init(_disp_panel_handle)) { + return false; } uint8_t madctl_val = 0; @@ -60,10 +54,24 @@ namespace lgfx colmod_val = 0x77; } - bus->writeParams(CMD_MADCTL, &(madctl_val), 1); - bus->writeParams(CMD_COLMOD, &(colmod_val), 1); + const uint8_t* params; + for (size_t i = 0; nullptr != (params = getInitParams(i)); ++i) + { + size_t len; + while (0 != (len = params[0])) { +// printf("cmd: %02x, len: %d\n", params[1], len); + bus->writeParams(params[1], ¶ms[2], len - 1); + params += len + 1; + } + vTaskDelay(pdMS_TO_TICKS(getInitDelay(i))); + } - return (ESP_OK == esp_lcd_panel_init(_disp_panel_handle)); + if (init_in_command_mode) { + bus->writeParams(CMD_MADCTL, &(madctl_val), 1); + bus->writeParams(CMD_COLMOD, &(colmod_val), 1); + return (ESP_OK == esp_lcd_panel_init(_disp_panel_handle)); + } + return true; } @@ -82,7 +90,7 @@ namespace lgfx #else dpi_config.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565; #endif - dpi_config.num_fbs = 1; + dpi_config.num_fbs = 2; dpi_config.video_timing.h_size = _cfg.panel_width; dpi_config.video_timing.v_size = _cfg.panel_height; dpi_config.video_timing.hsync_back_porch = _config_detail.hsync_back_porch; @@ -122,6 +130,14 @@ namespace lgfx auto bus = getBusDSI(); if (bus == nullptr) { return false; } + const size_t reset_delay = getResetDelayBeforeDpi(); + if (reset_delay + && (!bus->writeParams(CMD_SWRESET, nullptr, 0))) { + return false; + } + if (reset_delay) { + vTaskDelay(pdMS_TO_TICKS(reset_delay)); + } if (init_dpi(bus) && init_panel()) { esp_lcd_dpi_panel_get_frame_buffer(_disp_panel_handle, 1, &(_config_detail.buffer)); diff --git a/src/lgfx/v1/platforms/esp32p4/Panel_DSI.hpp b/src/lgfx/v1/platforms/esp32p4/Panel_DSI.hpp index 2316b53f..0c1fc543 100644 --- a/src/lgfx/v1/platforms/esp32p4/Panel_DSI.hpp +++ b/src/lgfx/v1/platforms/esp32p4/Panel_DSI.hpp @@ -74,6 +74,7 @@ namespace lgfx protected: + static constexpr uint8_t CMD_SWRESET = 0x01; static constexpr uint8_t CMD_SLPIN = 0x10; static constexpr uint8_t CMD_SLPOUT = 0x11; static constexpr uint8_t CMD_INVOFF = 0x20; @@ -87,6 +88,8 @@ namespace lgfx virtual const uint8_t* getInitParams(size_t listno) const { return nullptr; } virtual size_t getInitDelay(size_t listno) const { return 0; } + virtual size_t getResetDelayBeforeDpi(void) const { return 0; } + virtual bool initInCommandMode(void) const { return true; } bool write_params(uint32_t cmd, const uint8_t* data = nullptr, size_t length = 0); diff --git a/src/lgfx/v1/platforms/esp32p4/Panel_ST7102.hpp b/src/lgfx/v1/platforms/esp32p4/Panel_ST7102.hpp new file mode 100644 index 00000000..d7884af2 --- /dev/null +++ b/src/lgfx/v1/platforms/esp32p4/Panel_ST7102.hpp @@ -0,0 +1,118 @@ +/*----------------------------------------------------------------------------/ + Lovyan GFX - Graphics library for embedded devices. + + ST7102 MIPI DSI panel parameters for M5Stack CoreP4X. +/----------------------------------------------------------------------------*/ +#pragma once + +#include "Panel_DSI.hpp" +#if SOC_MIPI_DSI_SUPPORTED + +namespace lgfx +{ + inline namespace v1 + { + + struct Panel_ST7102 : public Panel_DSI + { + protected: + + bool initInCommandMode(void) const override { return false; } + size_t getResetDelayBeforeDpi(void) const override { return 120; } + + const uint8_t* getInitParams(size_t listno) const override + { + static constexpr uint8_t list0[] = + {//len(cmd+params), cmd, params + 4, 0x99, 0x71, 0x02, 0xA2, + 4, 0x99, 0x71, 0x02, 0xA3, + 4, 0x99, 0x71, 0x02, 0xA4, + 2, 0x78, 0x21, + 2, 0x79, 0xCF, + 8, 0xB0, 0x22, 0x43, 0x1E, 0x43, 0x2F, 0x57, 0x57, + 3, 0xB7, 0x7D, 0x7D, + 3, 0xBF, 0x7A, 0x7A, + 38, 0xC8, 0x00, 0x00, 0x13, 0x23, 0x3E, 0x00, 0x6A, 0x03, 0xB0, 0x06, + 0x11, 0x0F, 0x07, 0x85, 0x03, 0x21, 0xD5, 0x01, 0x18, 0x00, + 0x22, 0x56, 0x0F, 0x98, 0x0A, 0x32, 0xF8, 0x0D, 0x48, 0x0F, + 0xF3, 0x80, 0x0F, 0xAC, 0xC1, 0x03, 0xC4, + 38, 0xC9, 0x00, 0x00, 0x13, 0x23, 0x3E, 0x00, 0x6A, 0x03, 0xB0, 0x06, + 0x11, 0x0F, 0x07, 0x85, 0x03, 0x21, 0xD5, 0x01, 0x18, 0x00, + 0x22, 0x56, 0x0F, 0x98, 0x0A, 0x32, 0xF8, 0x0D, 0x48, 0x0F, + 0xF3, 0x80, 0x0F, 0xAC, 0xC1, 0x03, 0xC4, + 7, 0xD7, 0x10, 0x0C, 0x02, 0x19, 0x40, 0x40, + 33, 0xA3, 0x40, 0x03, 0x80, 0xCF, 0x44, 0x00, 0x00, 0x00, 0x02, 0x05, + 0x6F, 0x6F, 0x00, 0x1A, 0x00, 0x45, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x46, 0x00, 0x00, 0x02, 0x20, 0x52, 0x00, 0x05, 0x00, + 0x00, 0xFF, + 45, 0xA6, 0x02, 0x00, 0x24, 0x55, 0x35, 0x00, 0x38, 0x00, 0x97, 0x97, + 0x00, 0x24, 0x55, 0x36, 0x00, 0x37, 0x00, 0x97, 0x97, 0x02, + 0xAC, 0x51, 0x3A, 0x00, 0x00, 0x00, 0x97, 0x97, 0x00, 0xAC, + 0x21, 0x00, 0x0B, 0x00, 0x00, 0x97, 0x97, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, + 49, 0xA7, 0x19, 0x19, 0x00, 0x64, 0x40, 0x07, 0x16, 0x40, 0x00, 0x04, + 0x03, 0x97, 0x97, 0x00, 0x64, 0x40, 0x25, 0x34, 0x00, 0x00, + 0x02, 0x01, 0x97, 0x97, 0x00, 0x64, 0x40, 0x4B, 0x5A, 0x00, + 0x00, 0x02, 0x01, 0x97, 0x97, 0x00, 0x24, 0x40, 0x69, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x97, 0x97, 0x00, 0x44, + 38, 0xAC, 0x11, 0x08, 0x13, 0x0A, 0x18, 0x1A, 0x1B, 0x00, 0x06, 0x03, + 0x19, 0x1B, 0x1B, 0x1B, 0x18, 0x1B, 0x10, 0x09, 0x12, 0x0B, + 0x18, 0x1A, 0x1B, 0x02, 0x06, 0x01, 0x19, 0x1B, 0x1B, 0x1B, + 0x18, 0x1B, 0xFF, 0x67, 0xFF, 0x67, 0x00, + 8, 0xAD, 0xCC, 0x40, 0x46, 0x11, 0x04, 0x6F, 0x6F, + 15, 0xE8, 0x30, 0x07, 0x00, 0xB3, 0xB3, 0x9C, 0x00, 0xE2, 0x04, 0x00, + 0x00, 0x00, 0x00, 0xEF, + 3, 0x75, 0x03, 0x04, + 34, 0xE7, 0x8B, 0x3C, 0x00, 0x0C, 0xF0, 0x5D, 0x00, 0x5D, 0x00, 0x5D, + 0x00, 0x5D, 0x00, 0xFF, 0x00, 0x08, 0x7B, 0x00, 0x00, 0xC8, + 0x6A, 0x5A, 0x08, 0x1A, 0x3C, 0x00, 0x71, 0x01, 0x8C, 0x01, + 0x7F, 0xF0, 0x22, + 10, 0xE9, 0x3C, 0x7F, 0x08, 0x07, 0x1A, 0x7A, 0x22, 0x1A, 0x33, + 0, + }; + + static constexpr uint8_t list1[] = + { + 1, CMD_SLPOUT, + 0, + }; + + static constexpr uint8_t list2[] = + { + 2, CMD_MADCTL, 0b11, + 1, CMD_DISPON, + 0, + }; + + static constexpr uint8_t list3[] = + { + 2, 0x35, 0x00, + 1, CMD_DISPON, + 0, + }; + + switch (listno) + { + case 0: return list0; + case 1: return list1; + case 2: return list2; + case 3: return list3; + default: return nullptr; + } + } + + size_t getInitDelay(size_t listno) const override + { + switch (listno) + { + case 1: return 20; + case 2: return 20; + default: return 0; + } + } + }; + + } +} + +#endif diff --git a/src/lgfx/v1/touch/Touch_CSTxxx.cpp b/src/lgfx/v1/touch/Touch_CSTxxx.cpp index ea8ca19c..e1e0a4c2 100644 --- a/src/lgfx/v1/touch/Touch_CSTxxx.cpp +++ b/src/lgfx/v1/touch/Touch_CSTxxx.cpp @@ -27,6 +27,102 @@ namespace lgfx { inline namespace v1 { +//---------------------------------------------------------------------------- + + bool Touch_CST3530::_write_reg32(uint32_t reg) + { + uint8_t data[4] = + { static_cast(reg >> 24) + , static_cast(reg >> 16) + , static_cast(reg >> 8) + , static_cast(reg) + }; + return i2c::transactionWrite(_cfg.i2c_port, _cfg.i2c_addr, data, sizeof(data), _cfg.freq).has_value(); + } + + bool Touch_CST3530::_read_reg32(uint32_t reg, uint8_t* data, size_t length) + { + uint8_t address[4] = + { static_cast(reg >> 24) + , static_cast(reg >> 16) + , static_cast(reg >> 8) + , static_cast(reg) + }; + return i2c::transactionWriteRead(_cfg.i2c_port, _cfg.i2c_addr, address, sizeof(address), data, length, _cfg.freq).has_value(); + } + + bool Touch_CST3530::_check_init(void) + { + if (_inited) return true; + + bool ok = _write_reg32(0xD0000400); + lgfx::delay(20); + ok = _write_reg32(0xD0000400) && ok; + lgfx::delay(20); + ok = _write_reg32(0xD0000000) && ok; + ok = _write_reg32(0xD0000C00) && ok; + ok = _write_reg32(0xD0000100) && ok; + _inited = ok; + return _inited; + } + + bool Touch_CST3530::init(void) + { + _inited = false; + if (_cfg.pin_int >= 0) { + lgfx::pinMode(_cfg.pin_int, pin_mode_t::input); + } + i2c::init(_cfg.i2c_port, _cfg.pin_sda, _cfg.pin_scl).has_value(); + return true; + } + + void Touch_CST3530::wakeup(void) + { + _inited = false; + _check_init(); + } + + void Touch_CST3530::sleep(void) + { + } + + uint_fast8_t Touch_CST3530::getTouchRaw(touch_point_t* tp, uint_fast8_t count) + { + if (count == 0 || !_check_init()) return 0; + + uint8_t data[50] = { 0 }; + if (!_read_reg32(0xD0070000, data, 9)) return 0; + + uint8_t finger_num = data[3] & 0x0F; + uint8_t key_num = (data[3] >> 4) & 0x0F; + uint8_t total_num = key_num + finger_num; + if (total_num > 1) { + size_t extra_length = (total_num - 1) * 5; + if (extra_length > sizeof(data) - 9) extra_length = sizeof(data) - 9; + if (!i2c::transactionRead(_cfg.i2c_port, _cfg.i2c_addr, &data[9], extra_length, _cfg.freq).has_value()) { + _write_reg32(0xD00002AB); + return 0; + } + } + _write_reg32(0xD00002AB); + + if (finger_num == 0 || (data[8] >> 4) == 0) return 0; + + uint_fast8_t points = finger_num; + if (points > max_touch_points) points = max_touch_points; + if (points > count) points = count; + for (uint_fast8_t i = 0; i < points; ++i) { + uint16_t index = (key_num + i) * 5; + uint16_t x = data[index + 4] | ((uint16_t)(data[index + 7] & 0x0F) << 8); + uint16_t y = data[index + 5] | ((uint16_t)(data[index + 7] & 0xF0) << 4); + tp[i].id = i; + tp[i].size = 1; + tp[i].x = x; + tp[i].y = y; + } + return points; + } + //---------------------------------------------------------------------------- static constexpr uint8_t CST816S_TOUCH_REG = 0x01; diff --git a/src/lgfx/v1/touch/Touch_CSTxxx.hpp b/src/lgfx/v1/touch/Touch_CSTxxx.hpp index 15b78d6c..9390c2d4 100644 --- a/src/lgfx/v1/touch/Touch_CSTxxx.hpp +++ b/src/lgfx/v1/touch/Touch_CSTxxx.hpp @@ -28,6 +28,34 @@ namespace lgfx struct Touch_CST226; // CST226/CST226SE struct Touch_CST816S; + struct Touch_CST3530; + + +//---------------------------------------------------------------------------- + + struct Touch_CST3530 : public ITouch + { + Touch_CST3530(void) + { + _cfg.i2c_addr = 0x58; + _cfg.x_min = 0; + _cfg.x_max = 479; + _cfg.y_min = 0; + _cfg.y_max = 479; + } + + bool init(void) override; + void wakeup(void) override; + void sleep(void) override; + uint_fast8_t getTouchRaw(touch_point_t* tp, uint_fast8_t count) override; + + private: + static constexpr uint_fast8_t max_touch_points = 5; + + bool _check_init(void); + bool _write_reg32(uint32_t reg); + bool _read_reg32(uint32_t reg, uint8_t* data, size_t length); + }; //----------------------------------------------------------------------------