From 30970abd1f187391b19f1b6bc36c4f731cc4c4b4 Mon Sep 17 00:00:00 2001 From: Create123 Date: Wed, 12 Nov 2025 18:32:06 +0800 Subject: [PATCH] board/m5stack-tab5: Add new display st7123 support. (#1409) --- main/boards/m5stack-tab5/README.md | 8 +- main/boards/m5stack-tab5/config.h | 58 ++++ main/boards/m5stack-tab5/esp_lcd_st7123.c | 381 ++++++++++++++++++++++ main/boards/m5stack-tab5/esp_lcd_st7123.h | 126 +++++++ main/boards/m5stack-tab5/m5stack_tab5.cc | 360 ++++++++++++++++---- main/idf_component.yml | 7 +- 6 files changed, 861 insertions(+), 79 deletions(-) create mode 100644 main/boards/m5stack-tab5/esp_lcd_st7123.c create mode 100644 main/boards/m5stack-tab5/esp_lcd_st7123.h diff --git a/main/boards/m5stack-tab5/README.md b/main/boards/m5stack-tab5/README.md index 9187c26c..c23181c0 100644 --- a/main/boards/m5stack-tab5/README.md +++ b/main/boards/m5stack-tab5/README.md @@ -4,15 +4,11 @@ ## 快速体验 -下载编译好的 [固件](https://pan.baidu.com/s/1dgbUQtMyVLSCSBJLHARpwQ?pwd=1234) 提取码: 1234 - -```shell -esptool.py --chip esp32p4 -p /dev/ttyACM0 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 80m --flash_size 16MB 0x00 tab5_xiaozhi_v1_addr0.bin -``` +到 [M5Burner](https://docs.m5stack.com/zh_CN/uiflow/m5burner/intro) 选择 Tab5 搜索小智下载固件 ## 基础使用 -* idf version: v5.5-dev +* idf version: v6.0-dev 1. 设置编译目标为 esp32p4 diff --git a/main/boards/m5stack-tab5/config.h b/main/boards/m5stack-tab5/config.h index 7466c036..9846f343 100644 --- a/main/boards/m5stack-tab5/config.h +++ b/main/boards/m5stack-tab5/config.h @@ -258,4 +258,62 @@ const ili9881c_lcd_init_cmd_t tab5_lcd_ili9881c_specific_init_code_default[] = { //============ Gamma END=========== }; +// ST7123 vendor specific initialization commands +const st7123_lcd_init_cmd_t st7123_vendor_specific_init_default[] = { + {0x60, (uint8_t[]){0x71, 0x23, 0xa2}, 3, 0}, + {0x60, (uint8_t[]){0x71, 0x23, 0xa3}, 3, 0}, + {0x60, (uint8_t[]){0x71, 0x23, 0xa4}, 3, 0}, + {0xA4, (uint8_t[]){0x31}, 1, 0}, + {0xD7, (uint8_t[]){0x10, 0x0A, 0x10, 0x2A, 0x80, 0x80}, 6, 0}, + {0x90, (uint8_t[]){0x71, 0x23, 0x5A, 0x20, 0x24, 0x09, 0x09}, 7, 0}, + {0xA3, (uint8_t[]){0x80, 0x01, 0x88, 0x30, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, + 0x1E, 0x5C, 0x1E, 0x80, 0x00, 0x4F, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x1E, 0x5C, 0x1E, 0x80, 0x00, 0x6F, 0x58, 0x00, 0x00, 0x00, 0xFF}, + 40, 0}, + {0xA6, (uint8_t[]){0x03, 0x00, 0x24, 0x55, 0x36, 0x00, 0x39, 0x00, 0x6E, 0x6E, 0x91, 0xFF, 0x00, 0x24, + 0x55, 0x38, 0x00, 0x37, 0x00, 0x6E, 0x6E, 0x91, 0xFF, 0x00, 0x24, 0x11, 0x00, 0x00, + 0x00, 0x00, 0x6E, 0x6E, 0x91, 0xFF, 0x00, 0xEC, 0x11, 0x00, 0x03, 0x00, 0x03, 0x6E, + 0x6E, 0xFF, 0xFF, 0x00, 0x08, 0x80, 0x08, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00}, + 55, 0}, + {0xA7, (uint8_t[]){0x19, 0x19, 0x80, 0x64, 0x40, 0x07, 0x16, 0x40, 0x00, 0x44, 0x03, 0x6E, 0x6E, 0x91, 0xFF, + 0x08, 0x80, 0x64, 0x40, 0x25, 0x34, 0x40, 0x00, 0x02, 0x01, 0x6E, 0x6E, 0x91, 0xFF, 0x08, + 0x80, 0x64, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x6E, 0x6E, 0x91, 0xFF, 0x08, 0x80, + 0x64, 0x40, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x6E, 0x6E, 0x84, 0xFF, 0x08, 0x80, 0x44}, + 60, 0}, + {0xAC, (uint8_t[]){0x03, 0x19, 0x19, 0x18, 0x18, 0x06, 0x13, 0x13, 0x11, 0x11, 0x08, 0x08, 0x0A, 0x0A, 0x1C, + 0x1C, 0x07, 0x07, 0x00, 0x00, 0x02, 0x02, 0x01, 0x19, 0x19, 0x18, 0x18, 0x06, 0x12, 0x12, + 0x10, 0x10, 0x09, 0x09, 0x0B, 0x0B, 0x1C, 0x1C, 0x07, 0x07, 0x03, 0x03, 0x01, 0x01}, + 44, 0}, + {0xAD, (uint8_t[]){0xF0, 0x00, 0x46, 0x00, 0x03, 0x50, 0x50, 0xFF, 0xFF, 0xF0, 0x40, 0x06, 0x01, + 0x07, 0x42, 0x42, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}, + 25, 0}, + {0xAE, (uint8_t[]){0xFE, 0x3F, 0x3F, 0xFE, 0x3F, 0x3F, 0x00}, 7, 0}, + {0xB2, + (uint8_t[]){0x15, 0x19, 0x05, 0x23, 0x49, 0xAF, 0x03, 0x2E, 0x5C, 0xD2, 0xFF, 0x10, 0x20, 0xFD, 0x20, 0xC0, 0x00}, + 17, 0}, + {0xE8, (uint8_t[]){0x20, 0x6F, 0x04, 0x97, 0x97, 0x3E, 0x04, 0xDC, 0xDC, 0x3E, 0x06, 0xFA, 0x26, 0x3E}, 15, 0}, + {0x75, (uint8_t[]){0x03, 0x04}, 2, 0}, + {0xE7, (uint8_t[]){0x3B, 0x00, 0x00, 0x7C, 0xA1, 0x8C, 0x20, 0x1A, 0xF0, 0xB1, 0x50, 0x00, + 0x50, 0xB1, 0x50, 0xB1, 0x50, 0xD8, 0x00, 0x55, 0x00, 0xB1, 0x00, 0x45, + 0xC9, 0x6A, 0xFF, 0x5A, 0xD8, 0x18, 0x88, 0x15, 0xB1, 0x01, 0x01, 0x77}, + 36, 0}, + {0xEA, (uint8_t[]){0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2C}, 8, 0}, + {0xB0, (uint8_t[]){0x22, 0x43, 0x11, 0x61, 0x25, 0x43, 0x43}, 7, 0}, + {0xb7, (uint8_t[]){0x00, 0x00, 0x73, 0x73}, 4, 0}, + {0xBF, (uint8_t[]){0xA6, 0xAA}, 2, 0}, + {0xA9, (uint8_t[]){0x00, 0x00, 0x73, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03}, 10, 0}, + {0xC8, (uint8_t[]){0x00, 0x00, 0x10, 0x1F, 0x36, 0x00, 0x5D, 0x04, 0x9D, 0x05, 0x10, 0xF2, 0x06, + 0x60, 0x03, 0x11, 0xAD, 0x00, 0xEF, 0x01, 0x22, 0x2E, 0x0E, 0x74, 0x08, 0x32, + 0xDC, 0x09, 0x33, 0x0F, 0xF3, 0x77, 0x0D, 0xB0, 0xDC, 0x03, 0xFF}, + 37, 0}, + {0xC9, (uint8_t[]){0x00, 0x00, 0x10, 0x1F, 0x36, 0x00, 0x5D, 0x04, 0x9D, 0x05, 0x10, 0xF2, 0x06, + 0x60, 0x03, 0x11, 0xAD, 0x00, 0xEF, 0x01, 0x22, 0x2E, 0x0E, 0x74, 0x08, 0x32, + 0xDC, 0x09, 0x33, 0x0F, 0xF3, 0x77, 0x0D, 0xB0, 0xDC, 0x03, 0xFF}, + 37, 0}, + {0x36, (uint8_t[]){0x00}, 1, 0}, + {0x11, (uint8_t[]){0x00}, 1, 100}, + {0x29, (uint8_t[]){0x00}, 1, 0}, + {0x35, (uint8_t[]){0x00}, 1, 100}, +}; + #endif // _BOARD_CONFIG_H_ diff --git a/main/boards/m5stack-tab5/esp_lcd_st7123.c b/main/boards/m5stack-tab5/esp_lcd_st7123.c new file mode 100644 index 00000000..b68b1d37 --- /dev/null +++ b/main/boards/m5stack-tab5/esp_lcd_st7123.c @@ -0,0 +1,381 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include "esp_check.h" +#include "esp_log.h" +#include "esp_lcd_panel_commands.h" +#include "esp_lcd_panel_interface.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_vendor.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "esp_lcd_st7123.h" + +#define ST7123_PAD_CONTROL (0xB7) +#define ST7123_DSI_2_LANE (0x03) +#define ST7123_DSI_3_4_LANE (0x02) + +#define ST7123_CMD_GS_BIT (1 << 0) +#define ST7123_CMD_SS_BIT (1 << 1) + +typedef struct { + esp_lcd_panel_io_handle_t io; + int reset_gpio_num; + uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register + uint8_t colmod_val; // save surrent value of LCD_CMD_COLMOD register + const st7123_lcd_init_cmd_t *init_cmds; + uint16_t init_cmds_size; + uint8_t lane_num; + struct { + unsigned int reset_level: 1; + } flags; + // To save the original functions of MIPI DPI panel + esp_err_t (*del)(esp_lcd_panel_t *panel); + esp_err_t (*init)(esp_lcd_panel_t *panel); +} st7123_panel_t; + +static const char *TAG = "st7123"; + +static esp_err_t panel_st7123_del(esp_lcd_panel_t *panel); +static esp_err_t panel_st7123_init(esp_lcd_panel_t *panel); +static esp_err_t panel_st7123_reset(esp_lcd_panel_t *panel); +static esp_err_t panel_st7123_invert_color(esp_lcd_panel_t *panel, bool invert_color_data); +static esp_err_t panel_st7123_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y); +static esp_err_t panel_st7123_disp_on_off(esp_lcd_panel_t *panel, bool on_off); +static esp_err_t panel_st7123_sleep(esp_lcd_panel_t *panel, bool sleep); + +esp_err_t esp_lcd_new_panel_st7123(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, + esp_lcd_panel_handle_t *ret_panel) +{ + ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid arguments"); + st7123_vendor_config_t *vendor_config = (st7123_vendor_config_t *)panel_dev_config->vendor_config; + ESP_RETURN_ON_FALSE(vendor_config && vendor_config->mipi_config.dpi_config && vendor_config->mipi_config.dsi_bus, ESP_ERR_INVALID_ARG, TAG, + "invalid vendor config"); + + esp_err_t ret = ESP_OK; + st7123_panel_t *st7123 = (st7123_panel_t *)calloc(1, sizeof(st7123_panel_t)); + ESP_RETURN_ON_FALSE(st7123, ESP_ERR_NO_MEM, TAG, "no mem for st7123 panel"); + + if (panel_dev_config->reset_gpio_num >= 0) { + gpio_config_t io_conf = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num, + }; + ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed"); + } + + switch (panel_dev_config->rgb_ele_order) { + case LCD_RGB_ELEMENT_ORDER_RGB: + st7123->madctl_val = 0; + break; + case LCD_RGB_ELEMENT_ORDER_BGR: + st7123->madctl_val |= LCD_CMD_BGR_BIT; + break; + default: + ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color space"); + break; + } + + switch (panel_dev_config->bits_per_pixel) { + case 16: // RGB565 + st7123->colmod_val = 0x55; + break; + case 18: // RGB666 + st7123->colmod_val = 0x66; + break; + case 24: // RGB888 + st7123->colmod_val = 0x77; + break; + default: + ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width"); + break; + } + + st7123->io = io; + st7123->init_cmds = vendor_config->init_cmds; + st7123->init_cmds_size = vendor_config->init_cmds_size; + st7123->lane_num = vendor_config->mipi_config.lane_num; + st7123->reset_gpio_num = panel_dev_config->reset_gpio_num; + st7123->flags.reset_level = panel_dev_config->flags.reset_active_high; + + // Create MIPI DPI panel + ESP_GOTO_ON_ERROR(esp_lcd_new_panel_dpi(vendor_config->mipi_config.dsi_bus, vendor_config->mipi_config.dpi_config, ret_panel), err, TAG, + "create MIPI DPI panel failed"); + ESP_LOGD(TAG, "new MIPI DPI panel @%p", *ret_panel); + + // Save the original functions of MIPI DPI panel + st7123->del = (*ret_panel)->del; + st7123->init = (*ret_panel)->init; + // Overwrite the functions of MIPI DPI panel + (*ret_panel)->del = panel_st7123_del; + (*ret_panel)->init = panel_st7123_init; + (*ret_panel)->reset = panel_st7123_reset; + (*ret_panel)->mirror = panel_st7123_mirror; + (*ret_panel)->invert_color = panel_st7123_invert_color; + (*ret_panel)->disp_on_off = panel_st7123_disp_on_off; + (*ret_panel)->disp_sleep = panel_st7123_sleep; + (*ret_panel)->user_data = st7123; + ESP_LOGD(TAG, "new st7123 panel @%p", st7123); + + return ESP_OK; + + err: + if (st7123) { + if (panel_dev_config->reset_gpio_num >= 0) { + gpio_reset_pin(panel_dev_config->reset_gpio_num); + } + free(st7123); + } + return ret; +} + +static const st7123_lcd_init_cmd_t vendor_specific_init_default[] = { + // {cmd, { data }, data_size, delay_ms} + // TODO: + {0x60, (uint8_t []){0x71,0x23,0xa2}, 3, 0}, + {0x60, (uint8_t []){0x71,0x23,0xa3}, 3, 0}, + {0x60, (uint8_t []){0x71,0x23,0xa4}, 3, 0}, + {0xA4, (uint8_t []){0x31}, 1, 0}, + {0xD7, (uint8_t []){0x10,0x0A,0x10,0x2A,0x80,0x80}, 6, 0}, + {0x90, (uint8_t []){0x71,0x23,0x5A,0x20,0x24,0x09,0x09}, 7, 0}, + {0xA3, (uint8_t []){0x80,0x01,0x88,0x30,0x05,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x00,0x1E,0x5C,0x1E,0x80,0x00,0x4F,0x05,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x00,0x1E,0x5C,0x1E,0x80,0x00,0x6F,0x58,0x00,0x00,0x00,0xFF}, 40, 0}, + {0xA6, (uint8_t []){0x03,0x00,0x24,0x55,0x36,0x00,0x39,0x00,0x6E,0x6E,0x91,0xFF,0x00,0x24,0x55,0x38,0x00,0x37,0x00,0x6E,0x6E,0x91,0xFF,0x00,0x24,0x11,0x00,0x00,0x00,0x00,0x6E,0x6E,0x91,0xFF,0x00,0xEC,0x11,0x00,0x03,0x00,0x03,0x6E,0x6E,0xFF,0xFF,0x00,0x08,0x80,0x08,0x80,0x06,0x00,0x00,0x00,0x00}, 55, 0}, + {0xA7, (uint8_t []){0x19,0x19,0x80,0x64,0x40,0x07,0x16,0x40,0x00,0x44,0x03,0x6E,0x6E,0x91,0xFF,0x08,0x80,0x64,0x40,0x25,0x34,0x40,0x00,0x02,0x01,0x6E,0x6E,0x91,0xFF,0x08,0x80,0x64,0x40,0x00,0x00,0x40,0x00,0x00,0x00,0x6E,0x6E,0x91,0xFF,0x08,0x80,0x64,0x40,0x00,0x00,0x00,0x00,0x20,0x00,0x6E,0x6E,0x84,0xFF,0x08,0x80,0x44}, 60, 0}, + {0xAC, (uint8_t []){0x03,0x19,0x19,0x18,0x18,0x06,0x13,0x13,0x11,0x11,0x08,0x08,0x0A,0x0A,0x1C,0x1C,0x07,0x07,0x00,0x00,0x02,0x02,0x01,0x19,0x19,0x18,0x18,0x06,0x12,0x12,0x10,0x10,0x09,0x09,0x0B,0x0B,0x1C,0x1C,0x07,0x07,0x03,0x03,0x01,0x01}, 44, 0}, + {0xAD, (uint8_t []){0xF0,0x00,0x46,0x00,0x03,0x50,0x50,0xFF,0xFF,0xF0,0x40,0x06,0x01,0x07,0x42,0x42,0xFF,0xFF,0x01,0x00,0x00,0xFF,0xFF,0xFF,0xFF}, 25, 0}, + {0xAE, (uint8_t []){0xFE,0x3F,0x3F,0xFE,0x3F,0x3F,0x00}, 7, 0}, + {0xB2, (uint8_t []){0x15,0x19,0x05,0x23,0x49,0xAF,0x03,0x2E,0x5C,0xD2,0xFF,0x10,0x20,0xFD,0x20,0xC0,0x00}, 17, 0}, + {0xE8, (uint8_t []){0x20,0x6F,0x04,0x97,0x97,0x3E,0x04,0xDC,0xDC,0x3E,0x06,0xFA,0x26,0x3E}, 15, 0}, + {0x75, (uint8_t []){0x03,0x04}, 2, 0}, + {0xE7, (uint8_t []){0x3B,0x00,0x00,0x7C,0xA1,0x8C,0x20,0x1A,0xF0,0xB1,0x50,0x00,0x50,0xB1,0x50,0xB1,0x50,0xD8,0x00,0x55,0x00,0xB1,0x00,0x45,0xC9,0x6A,0xFF,0x5A,0xD8,0x18,0x88,0x15,0xB1,0x01,0x01,0x77}, 36, 0}, + {0xEA, (uint8_t []){0x13,0x00,0x04,0x00,0x00,0x00,0x00,0x2C}, 8, 0}, + {0xB0, (uint8_t []){0x22,0x43,0x11,0x61,0x25,0x43,0x43}, 7, 0}, + {0xb7, (uint8_t []){0x00,0x00,0x73,0x73}, 0x04, 0}, + {0xBF, (uint8_t []){0xA6,0XAA}, 2, 0}, + {0xA9, (uint8_t []){0x00,0x00,0x73,0xFF,0x00,0x00,0x03,0x00,0x00,0x03}, 10, 0}, + {0xC8, (uint8_t []){0x00,0x00,0x10,0x1F,0x36,0x00,0x5D,0x04,0x9D,0x05,0x10,0xF2,0x06,0x60,0x03,0x11,0xAD,0x00,0xEF,0x01,0x22,0x2E,0x0E,0x74,0x08,0x32,0xDC,0x09,0x33,0x0F,0xF3,0x77,0x0D,0xB0,0xDC,0x03,0xFF}, 37, 0}, + {0xC9, (uint8_t []){0x00,0x00,0x10,0x1F,0x36,0x00,0x5D,0x04,0x9D,0x05,0x10,0xF2,0x06,0x60,0x03,0x11,0xAD,0x00,0xEF,0x01,0x22,0x2E,0x0E,0x74,0x08,0x32,0xDC,0x09,0x33,0x0F,0xF3,0x77,0x0D,0xB0,0xDC,0x03,0xFF}, 37, 0}, + {0x36, (uint8_t []){0x03}, 1, 0}, + {0x11, (uint8_t []){0x00}, 1, 100}, + {0x29, (uint8_t []){0x00}, 1, 0}, + {0x35, (uint8_t []){0x00}, 1, 100}, + //============ Gamma END=========== +}; + +static esp_err_t panel_st7123_del(esp_lcd_panel_t *panel) +{ + st7123_panel_t *st7123 = (st7123_panel_t *)panel->user_data; + + if (st7123->reset_gpio_num >= 0) { + gpio_reset_pin(st7123->reset_gpio_num); + } + // Delete MIPI DPI panel + st7123->del(panel); + ESP_LOGD(TAG, "del st7123 panel @%p", st7123); + free(st7123); + + return ESP_OK; +} + +static esp_err_t panel_st7123_init(esp_lcd_panel_t *panel) +{ + st7123_panel_t *st7123 = (st7123_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = st7123->io; + const st7123_lcd_init_cmd_t *init_cmds = NULL; + uint16_t init_cmds_size = 0; + + // switch (st7123->lane_num) { + // case 0: + // case 2: + // lane_command = ST7123_DSI_2_LANE; + // break; + // case 3: + // case 4: + // lane_command = ST7123_DSI_3_4_LANE; + // break; + // default: + // ESP_LOGE(TAG, "Invalid lane number %d", st7123->lane_num); + // return ESP_ERR_INVALID_ARG; + // } + + uint8_t ID[3]; + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io, 0x04, ID, 3), TAG, "read ID failed"); + ESP_LOGI(TAG, "LCD ID: %02X %02X %02X", ID[0], ID[1], ID[2]); + + // // For modifying MIPI-DSI lane settings + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, ST7123_PAD_CONTROL, (uint8_t[]) { + // lane_command, + // }, 1), TAG, "send command failed"); + + // // back to CMD_Page 0 + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, ST7123_CMD_CNDBKxSEL, (uint8_t[]) { + // ST7123_CMD_BKxSEL_BYTE0, ST7123_CMD_BKxSEL_BYTE1, ST7123_CMD_BKxSEL_BYTE2_PAGE0 + // }, 3), TAG, "send command failed"); + // // exit sleep mode + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SLPOUT, NULL, 0), TAG, + // "io tx param failed"); + // vTaskDelay(pdMS_TO_TICKS(120)); + + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]) { + // st7123->madctl_val, + // }, 1), TAG, "send command failed"); + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_COLMOD, (uint8_t[]) { + // st7123->colmod_val, + // }, 1), TAG, "send command failed"); + + // vendor specific initialization, it can be different between manufacturers + // should consult the LCD supplier for initialization sequence code + if (st7123->init_cmds) { + init_cmds = st7123->init_cmds; + init_cmds_size = st7123->init_cmds_size; + } else { + init_cmds = vendor_specific_init_default; + init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(st7123_lcd_init_cmd_t); + } + + for (int i = 0; i < init_cmds_size; i++) { + // Check if the command has been used or conflicts with the internal + // if (is_command0_enable && init_cmds[i].data_bytes > 0) { + // switch (init_cmds[i].cmd) { + // case LCD_CMD_MADCTL: + // is_cmd_overwritten = true; + // st7123->madctl_val = ((uint8_t *)init_cmds[i].data)[0]; + // break; + // case LCD_CMD_COLMOD: + // is_cmd_overwritten = true; + // st7123->colmod_val = ((uint8_t *)init_cmds[i].data)[0]; + // break; + // default: + // is_cmd_overwritten = false; + // break; + // } + + // if (is_cmd_overwritten) { + // is_cmd_overwritten = false; + // ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence", + // init_cmds[i].cmd); + // } + // } + + // Send command + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG, "send command failed"); + vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms)); + + // if ((init_cmds[i].cmd == ST7123_CMD_CNDBKxSEL) && (((uint8_t *)init_cmds[i].data)[2] == ST7123_CMD_BKxSEL_BYTE2_PAGE0)) { + // is_command0_enable = true; + // } else if ((init_cmds[i].cmd == ST7123_CMD_CNDBKxSEL) && (((uint8_t *)init_cmds[i].data)[2] != ST7123_CMD_BKxSEL_BYTE2_PAGE0)) { + // is_command0_enable = false; + // } + } + ESP_LOGD(TAG, "send init commands success"); + + ESP_RETURN_ON_ERROR(st7123->init(panel), TAG, "init MIPI DPI panel failed"); + + return ESP_OK; +} + +static esp_err_t panel_st7123_reset(esp_lcd_panel_t *panel) +{ + st7123_panel_t *st7123 = (st7123_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = st7123->io; + + // Perform hardware reset + if (st7123->reset_gpio_num >= 0) { + gpio_set_level(st7123->reset_gpio_num, st7123->flags.reset_level); + vTaskDelay(pdMS_TO_TICKS(50)); + gpio_set_level(st7123->reset_gpio_num, !st7123->flags.reset_level); + vTaskDelay(pdMS_TO_TICKS(50)); + } else if (io) { // Perform software reset + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed"); + vTaskDelay(pdMS_TO_TICKS(20)); + } + + return ESP_OK; +} + +static esp_err_t panel_st7123_invert_color(esp_lcd_panel_t *panel, bool invert_color_data) +{ + // st7123_panel_t *st7123 = (st7123_panel_t *)panel->user_data; + // esp_lcd_panel_io_handle_t io = st7123->io; + // uint8_t command = 0; + + // ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_STATE, TAG, "invalid panel IO"); + + // if (invert_color_data) { + // command = LCD_CMD_INVON; + // } else { + // command = LCD_CMD_INVOFF; + // } + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed"); + + return ESP_OK; +} + +static esp_err_t panel_st7123_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y) +{ + // st7123_panel_t *st7123 = (st7123_panel_t *)panel->user_data; + // esp_lcd_panel_io_handle_t io = st7123->io; + // uint8_t madctl_val = st7123->madctl_val; + + // ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_STATE, TAG, "invalid panel IO"); + + // // Control mirror through LCD command + // if (mirror_x) { + // madctl_val |= ST7123_CMD_GS_BIT; + // } else { + // madctl_val &= ~ST7123_CMD_GS_BIT; + // } + // if (mirror_y) { + // madctl_val |= ST7123_CMD_SS_BIT; + // } else { + // madctl_val &= ~ST7123_CMD_SS_BIT; + // } + + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t []) { + // madctl_val + // }, 1), TAG, "send command failed"); + // st7123->madctl_val = madctl_val; + + return ESP_OK; +} + +static esp_err_t panel_st7123_disp_on_off(esp_lcd_panel_t *panel, bool on_off) +{ + // st7123_panel_t *st7123 = (st7123_panel_t *)panel->user_data; + // esp_lcd_panel_io_handle_t io = st7123->io; + // int command = 0; + + // if (on_off) { + // command = LCD_CMD_DISPON; + // } else { + // command = LCD_CMD_DISPOFF; + // } + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed"); + return ESP_OK; +} + +static esp_err_t panel_st7123_sleep(esp_lcd_panel_t *panel, bool sleep) +{ + // st7123_panel_t *st7123 = (st7123_panel_t *)panel->user_data; + // esp_lcd_panel_io_handle_t io = st7123->io; + // int command = 0; + + // if (sleep) { + // command = LCD_CMD_SLPIN; + // } else { + // command = LCD_CMD_SLPOUT; + // } + // ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed"); + // vTaskDelay(pdMS_TO_TICKS(100)); + + return ESP_OK; +} +#endif // SOC_MIPI_DSI_SUPPORTED diff --git a/main/boards/m5stack-tab5/esp_lcd_st7123.h b/main/boards/m5stack-tab5/esp_lcd_st7123.h new file mode 100644 index 00000000..3bb76702 --- /dev/null +++ b/main/boards/m5stack-tab5/esp_lcd_st7123.h @@ -0,0 +1,126 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/** + * @file + * @brief ESP LCD: ST7123 + */ + + #pragma once + + #include + #include "soc/soc_caps.h" + + #if SOC_MIPI_DSI_SUPPORTED + #include "esp_lcd_panel_vendor.h" + #include "esp_lcd_mipi_dsi.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /** + * @brief LCD panel initialization commands. + * + */ + typedef struct { + int cmd; /* +#include "esp_check.h" #include "esp_lcd_mipi_dsi.h" #include "esp_lcd_panel_ops.h" #include "esp_ldo_regulator.h" @@ -17,6 +19,7 @@ #include #include "i2c_device.h" #include "esp_lcd_touch_gt911.h" +#include "esp_lcd_touch_st7123.h" #include #define TAG "M5StackTab5Board" @@ -24,6 +27,8 @@ #define AUDIO_CODEC_ES8388_ADDR ES8388_CODEC_DEFAULT_ADDR #define LCD_MIPI_DSI_PHY_PWR_LDO_CHAN 3 // LDO_VO3 is connected to VDD_MIPI_DPHY #define LCD_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV 2500 +#define ST7123_TOUCH_I2C_ADDRESS 0x55 + // PI4IO registers #define PI4IO_REG_CHIP_RESET 0x01 @@ -37,6 +42,10 @@ #define PI4IO_REG_INT_MASK 0x11 #define PI4IO_REG_IRQ_STA 0x13 +// Bit manipulation macros +#define setbit(x, bit) ((x) |= (1U << (bit))) +#define clrbit(x, bit) ((x) &= ~(1U << (bit))) + class Pi4ioe1 : public I2cDevice { public: Pi4ioe1(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) { @@ -50,6 +59,9 @@ public: WriteReg(PI4IO_REG_INT_MASK, 0b01111111); // P7 中断使能 0 enable, 1 disable WriteReg(PI4IO_REG_OUT_SET, 0b01110110); // Output Port Register P1(SPK_EN), P2(EXT5V_EN), P4(LCD_RST), P5(TP_RST), P6(CAM)RST 输出高电平 } + + uint8_t ReadOutSet() { return ReadReg(PI4IO_REG_OUT_SET); } + void WriteOutSet(uint8_t value) { WriteReg(PI4IO_REG_OUT_SET, value); } }; class Pi4ioe2 : public I2cDevice { @@ -65,6 +77,9 @@ public: WriteReg(PI4IO_REG_INT_MASK, 0b10111111); // P6 中断使能 0 enable, 1 disable WriteReg(PI4IO_REG_OUT_SET, 0b10001001); // Output Port Register P0(WLAN_PWR_EN), P3(USB5V_EN), P7(CHG_EN) 输出高电平 } + + uint8_t ReadOutSet() { return ReadReg(PI4IO_REG_OUT_SET); } + void WriteOutSet(uint8_t value) { WriteReg(PI4IO_REG_OUT_SET, value); } }; class M5StackTab5Board : public WifiBoard { @@ -77,14 +92,13 @@ private: esp_lcd_touch_handle_t touch_ = nullptr; void InitializeI2c() { - // Initialize I2C peripheral i2c_master_bus_config_t i2c_bus_cfg = { - .i2c_port = (i2c_port_t)1, - .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN, - .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN, - .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = (i2c_port_t)1, + .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN, + .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN, + .clk_source = I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt = 7, - .intr_priority = 0, + .intr_priority = 0, .trans_queue_depth = 0, .flags = { .enable_internal_pullup = 1, @@ -93,6 +107,15 @@ private: ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_)); } + static esp_err_t bsp_enable_dsi_phy_power() { + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = LCD_MIPI_DSI_PHY_PWR_LDO_CHAN, + .voltage_mv = LCD_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, + }; + return esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy); + } + void I2cDetect() { uint8_t address; printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n"); @@ -156,37 +179,16 @@ private: tp_io_config.scl_speed_hz = 100000; esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle); esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &touch_); - - // 检测不到触摸?待更换设备测试 - // /* read data test */ - // for (uint8_t i = 0; i < 50; i++) { - // esp_lcd_touch_read_data(touch_); - // if (touch_->data.points > 0) { - // printf("\ntouch: %d, %d\n", touch_->data.coords[0].x, touch_->data.coords[0].y); - // } - // vTaskDelay(pdMS_TO_TICKS(100)); - // } - } - - void InitializeSpi() { - spi_bus_config_t buscfg = {}; - buscfg.mosi_io_num = GPIO_NUM_37; - buscfg.miso_io_num = GPIO_NUM_NC; - buscfg.sclk_io_num = GPIO_NUM_36; - buscfg.quadwp_io_num = GPIO_NUM_NC; - buscfg.quadhd_io_num = GPIO_NUM_NC; - buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t); - ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO)); } void InitializeIli9881cDisplay() { esp_lcd_panel_io_handle_t panel_io = nullptr; - esp_lcd_panel_handle_t panel = nullptr; + esp_lcd_panel_handle_t panel = nullptr; ESP_LOGI(TAG, "Turn on the power for MIPI DSI PHY"); - esp_ldo_channel_handle_t ldo_mipi_phy = NULL; + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; esp_ldo_channel_config_t ldo_mipi_phy_config = { - .chan_id = LCD_MIPI_DSI_PHY_PWR_LDO_CHAN, + .chan_id = LCD_MIPI_DSI_PHY_PWR_LDO_CHAN, .voltage_mv = LCD_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, }; ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); @@ -194,78 +196,245 @@ private: ESP_LOGI(TAG, "Install MIPI DSI LCD control panel"); esp_lcd_dsi_bus_handle_t mipi_dsi_bus; esp_lcd_dsi_bus_config_t bus_config = { - .bus_id = 0, - .num_data_lanes = 2, - .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, - .lane_bit_rate_mbps = 900, // 900MHz + .bus_id = 0, + .num_data_lanes = 2, + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, + .lane_bit_rate_mbps = 900, // 900MHz }; ESP_ERROR_CHECK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus)); ESP_LOGI(TAG, "Install panel IO"); esp_lcd_dbi_io_config_t dbi_config = { .virtual_channel = 0, - .lcd_cmd_bits = 8, + .lcd_cmd_bits = 8, .lcd_param_bits = 8, }; ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &panel_io)); ESP_LOGI(TAG, "Install LCD driver of ili9881c"); - esp_lcd_dpi_panel_config_t dpi_config = {.virtual_channel = 0, - .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, - .dpi_clock_freq_mhz = 60, - .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565, - .num_fbs = 2, - .video_timing = - { - .h_size = DISPLAY_WIDTH, - .v_size = DISPLAY_HEIGHT, - .hsync_pulse_width = 40, - .hsync_back_porch = 140, - .hsync_front_porch = 40, - .vsync_pulse_width = 4, - .vsync_back_porch = 20, - .vsync_front_porch = 20, - }, - .flags = { - .use_dma2d = false, - }}; + esp_lcd_dpi_panel_config_t dpi_config = { + .virtual_channel = 0, + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, + .dpi_clock_freq_mhz = 60, + .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565, + .num_fbs = 2, + .video_timing = { + .h_size = DISPLAY_WIDTH, + .v_size = DISPLAY_HEIGHT, + .hsync_pulse_width = 40, + .hsync_back_porch = 140, + .hsync_front_porch = 40, + .vsync_pulse_width = 4, + .vsync_back_porch = 20, + .vsync_front_porch = 20, + }, + .flags = { + .use_dma2d = false, + }, + }; ili9881c_vendor_config_t vendor_config = { - .init_cmds = tab5_lcd_ili9881c_specific_init_code_default, - .init_cmds_size = sizeof(tab5_lcd_ili9881c_specific_init_code_default) / - sizeof(tab5_lcd_ili9881c_specific_init_code_default[0]), - .mipi_config = - { - .dsi_bus = mipi_dsi_bus, - .dpi_config = &dpi_config, - .lane_num = 2, - }, + .init_cmds = tab5_lcd_ili9881c_specific_init_code_default, + .init_cmds_size = sizeof(tab5_lcd_ili9881c_specific_init_code_default) / sizeof(tab5_lcd_ili9881c_specific_init_code_default[0]), + .mipi_config = { + .dsi_bus = mipi_dsi_bus, + .dpi_config = &dpi_config, + .lane_num = 2, + }, }; esp_lcd_panel_dev_config_t lcd_dev_config = {}; - lcd_dev_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB; - lcd_dev_config.reset_gpio_num = -1; - lcd_dev_config.bits_per_pixel = 16; - lcd_dev_config.vendor_config = &vendor_config; + lcd_dev_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB; + lcd_dev_config.reset_gpio_num = -1; + lcd_dev_config.bits_per_pixel = 16; + lcd_dev_config.vendor_config = &vendor_config; ESP_ERROR_CHECK(esp_lcd_new_panel_ili9881c(panel_io, &lcd_dev_config, &panel)); ESP_ERROR_CHECK(esp_lcd_panel_reset(panel)); ESP_ERROR_CHECK(esp_lcd_panel_init(panel)); - // ESP_ERROR_CHECK(esp_lcd_panel_mirror(disp_panel, false, true)); ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true)); display_ = new MipiLcdDisplay(panel_io, panel, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY); } + void InitializeSt7123Display() { + esp_err_t ret = ESP_OK; + esp_lcd_panel_io_handle_t io = NULL; + esp_lcd_panel_handle_t disp_panel = NULL; + esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL; + + // Declare all config structures at the top to avoid goto issues + // Initialize with memset to avoid any initialization syntax that might confuse the compiler + esp_lcd_dsi_bus_config_t bus_config; + esp_lcd_dbi_io_config_t dbi_config; + esp_lcd_dpi_panel_config_t dpi_config; + st7123_vendor_config_t vendor_config; + esp_lcd_panel_dev_config_t lcd_dev_config; + + memset(&bus_config, 0, sizeof(bus_config)); + memset(&dbi_config, 0, sizeof(dbi_config)); + memset(&dpi_config, 0, sizeof(dpi_config)); + memset(&vendor_config, 0, sizeof(vendor_config)); + memset(&lcd_dev_config, 0, sizeof(lcd_dev_config)); + + ESP_ERROR_CHECK(bsp_enable_dsi_phy_power()); + + /* create MIPI DSI bus first, it will initialize the DSI PHY as well */ + bus_config.bus_id = 0; + bus_config.num_data_lanes = 2; // ST7123 uses 2 data lanes + bus_config.phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT; + bus_config.lane_bit_rate_mbps = 965; // ST7123 lane bitrate + ret = esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "New DSI bus init failed"); + goto err; + } + + ESP_LOGI(TAG, "Install MIPI DSI LCD control panel for ST7123"); + // we use DBI interface to send LCD commands and parameters + dbi_config.virtual_channel = 0; + dbi_config.lcd_cmd_bits = 8; // according to the LCD spec + dbi_config.lcd_param_bits = 8; // according to the LCD spec + ret = esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "New panel IO failed"); + goto err; + } + + ESP_LOGI(TAG, "Install LCD driver of ST7123"); + dpi_config.virtual_channel = 0; + dpi_config.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT; + dpi_config.dpi_clock_freq_mhz = 70; // ST7123 DPI clock frequency + dpi_config.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565; + dpi_config.num_fbs = 1; + dpi_config.video_timing.h_size = 720; + dpi_config.video_timing.v_size = 1280; + dpi_config.video_timing.hsync_pulse_width = 2; + dpi_config.video_timing.hsync_back_porch = 40; + dpi_config.video_timing.hsync_front_porch = 40; + dpi_config.video_timing.vsync_pulse_width = 2; + dpi_config.video_timing.vsync_back_porch = 8; + dpi_config.video_timing.vsync_front_porch = 220; + dpi_config.flags.use_dma2d = true; + + vendor_config.init_cmds = st7123_vendor_specific_init_default; + vendor_config.init_cmds_size = sizeof(st7123_vendor_specific_init_default) / sizeof(st7123_vendor_specific_init_default[0]); + vendor_config.mipi_config.dsi_bus = mipi_dsi_bus; + vendor_config.mipi_config.dpi_config = &dpi_config; + vendor_config.mipi_config.lane_num = 2; + + lcd_dev_config.reset_gpio_num = -1; + lcd_dev_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB; + lcd_dev_config.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE; + lcd_dev_config.bits_per_pixel = 24; + lcd_dev_config.vendor_config = &vendor_config; + + // 使用实际的 ST7123 驱动函数 + ret = esp_lcd_new_panel_st7123(io, &lcd_dev_config, &disp_panel); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "New LCD panel ST7123 failed"); + goto err; + } + + ret = esp_lcd_panel_reset(disp_panel); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "LCD panel reset failed"); + goto err; + } + + ret = esp_lcd_panel_init(disp_panel); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "LCD panel init failed"); + goto err; + } + + ret = esp_lcd_panel_disp_on_off(disp_panel, true); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "LCD panel display on failed"); + goto err; + } + + display_ = new MipiLcdDisplay(io, disp_panel, 720, 1280, DISPLAY_OFFSET_X, + DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY); + + ESP_LOGI(TAG, "ST7123 Display initialized with resolution %dx%d", 720, 1280); + + return; + + err: + if (disp_panel) { + esp_lcd_panel_del(disp_panel); + } + if (io) { + esp_lcd_panel_io_del(io); + } + if (mipi_dsi_bus) { + esp_lcd_del_dsi_bus(mipi_dsi_bus); + } + ESP_ERROR_CHECK(ret); + } + + void InitializeSt7123TouchPad() { + ESP_LOGI(TAG, "Init ST7123 Touch"); + + /* Initialize Touch Panel */ + ESP_LOGI(TAG, "Initialize touch IO (I2C)"); + const esp_lcd_touch_config_t tp_cfg = { + .x_max = 720, + .y_max = 1280, + .rst_gpio_num = GPIO_NUM_NC, + .int_gpio_num = TOUCH_INT_GPIO, + .levels = { + .reset = 0, + .interrupt = 0, + }, + .flags = { + .swap_xy = 0, + .mirror_x = 0, + .mirror_y = 0, + }, + }; + esp_lcd_panel_io_handle_t tp_io_handle = NULL; + esp_lcd_panel_io_i2c_config_t tp_io_config = { + .dev_addr = 0x55, + .control_phase_bytes = 1, + .dc_bit_offset = 0, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + .scl_speed_hz = 100000, + }; + ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle)); + ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_st7123(tp_io_handle, &tp_cfg, &touch_)); + } + + void InitializeDisplay() { + // after tp reset, wait for 100ms to ensure the I2C bus is stable + vTaskDelay(pdMS_TO_TICKS(100)); + // 检测 ST7123 触摸屏 (I2C地址 0x55) + esp_err_t ret = i2c_master_probe(i2c_bus_, ST7123_TOUCH_I2C_ADDRESS, 200); + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Detected ST7123 at 0x%02X, initializing ST7123 display", ST7123_TOUCH_I2C_ADDRESS); + InitializeSt7123Display(); + InitializeSt7123TouchPad(); + } else { + ESP_LOGI(TAG, "ST7123 not found at 0x%02X (ret=0x%x), using default ST7703+GT911", ST7123_TOUCH_I2C_ADDRESS, ret); + InitializeIli9881cDisplay(); + InitializeGt911TouchPad(); + } + } + public: M5StackTab5Board() : boot_button_(BOOT_BUTTON_GPIO) { InitializeI2c(); I2cDetect(); InitializePi4ioe(); - InitializeGt911TouchPad(); - InitializeIli9881cDisplay(); + InitializeDisplay(); // Auto-detect and initialize display + touch InitializeButtons(); + SetChargeQcEn(true); + SetChargeEn(true); + SetUsb5vEn(true); + SetExt5vEn(true); GetBacklight()->RestoreBrightness(); } @@ -293,6 +462,57 @@ public: static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT); return &backlight; } + + // BSP power control functions + void SetChargeQcEn(bool en) { + if (pi4ioe2_) { + uint8_t value = pi4ioe2_->ReadOutSet(); + if (en) { + clrbit(value, 5); // P5 = CHG_QC_EN (低电平使能) + } else { + setbit(value, 5); + } + pi4ioe2_->WriteOutSet(value); + } + } + + void SetChargeEn(bool en) { + if (pi4ioe2_) { + uint8_t value = pi4ioe2_->ReadOutSet(); + if (en) { + setbit(value, 7); // P7 = CHG_EN + } else { + clrbit(value, 7); + } + pi4ioe2_->WriteOutSet(value); + } + } + + void SetUsb5vEn(bool en) { + if (pi4ioe2_) { + uint8_t value = pi4ioe2_->ReadOutSet(); + if (en) { + setbit(value, 3); // P3 = USB5V_EN + } else { + clrbit(value, 3); + } + pi4ioe2_->WriteOutSet(value); + } + } + + void SetExt5vEn(bool en) { + if (pi4ioe1_) { + uint8_t value = pi4ioe1_->ReadOutSet(); + if (en) { + setbit(value, 2); // P2 = EXT5V_EN + } else { + clrbit(value, 2); + } + pi4ioe1_->WriteOutSet(value); + } + } }; + DECLARE_BOARD(M5StackTab5Board); + diff --git a/main/idf_component.yml b/main/idf_component.yml index 88507fe1..937bce8e 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -5,7 +5,7 @@ dependencies: espressif/esp_lcd_gc9a01: ==2.0.1 espressif/esp_lcd_st77916: ^1.0.1 espressif/esp_lcd_axs15231b: ^1.0.0 - + espressif/esp_lcd_st7701: version: ^1.1.4 rules: @@ -28,7 +28,7 @@ dependencies: espressif/button: ~4.1.3 espressif/knob: ^1.0.0 espressif/esp_video: - version: '==1.3.1' # for compatibility. update version may need to modify this project code. + version: ==1.3.1 # for compatibility. update version may need to modify this project code. rules: - if: target not in [esp32] espressif/esp_image_effects: @@ -67,7 +67,7 @@ dependencies: rules: - if: target in [esp32p4] espressif/esp32_p4_function_ev_board: - version: "^5.0.3" + version: ^5.0.3 rules: - if: target in [esp32p4] espressif/esp_lcd_ili9881c: @@ -99,3 +99,4 @@ dependencies: ## Required IDF version idf: version: '>=5.4.0' + espressif/esp_lcd_touch_st7123: ^1.0.0