Add support for LCD Wiki ES3C35P board configuration and files (#2112)
* Add support for LCD Wiki ES3C35P (3.5" ESP32-S3) board * fix: update variant counts in test for new ES3C35P board --------- Co-authored-by: Eivs <eivs@Eivss-MacBook-Pro.local>
This commit is contained in:
@@ -868,6 +868,11 @@ elseif(CONFIG_BOARD_TYPE_AI_VOX3)
|
||||
set(BUILTIN_TEXT_FONT font_noto_sans_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_material_symbols_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION noto-color-emoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_LCDWIKI_ES3C35P)
|
||||
set(BOARD_TYPE "lcdwiki-es3c35p")
|
||||
set(BUILTIN_TEXT_FONT font_noto_sans_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_material_symbols_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION noto-color-emoji_128)
|
||||
endif()
|
||||
|
||||
if(MANUFACTURER)
|
||||
|
||||
@@ -585,6 +585,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_AI_VOX3
|
||||
bool "NULLLAB-AI-VOX3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LCDWIKI_ES3C35P
|
||||
bool "LCD Wiki ES3C35P (3.5寸 ESP32-S3)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
endchoice
|
||||
|
||||
choice XIAOZHI_NETWORK_TYPE
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
# LCD Wiki ES3C35P
|
||||
|
||||
3.5 寸 ESP32-S3 智能显示模块
|
||||
|
||||
资料文档: [https://www.lcdwiki.com/zh/3.5inch_ESP32-S3_Display](https://www.lcdwiki.com/zh/3.5inch_ESP32-S3_Display)
|
||||
|
||||
## 产品规格
|
||||
|
||||
| 项目 | 参数 |
|
||||
|------|------|
|
||||
| SKU | ES3C35P (带喇叭) / ES3C35P-NS (无喇叭) |
|
||||
| 主控芯片 | ESP32-S3 Xtensa LX7 双核 240MHz |
|
||||
| 存储 | 16MB QSPI Flash + 8MB OPI PSRAM (N16R8) |
|
||||
| 无线 | Wi-Fi 2.4GHz 802.11b/g/n, 蓝牙 5.0 BLE |
|
||||
| 工作电压 | 5V (USB Type-C 供电) |
|
||||
| 电池 | 支持 3.7V 锂电池, TP4054 充电管理 |
|
||||
|
||||
### 显示屏
|
||||
|
||||
| 项目 | 参数 |
|
||||
|------|------|
|
||||
| 屏幕类型 | 3.5" IPS TFT |
|
||||
| 分辨率 | 320×480 像素 |
|
||||
| 色彩 | 65K RGB565 |
|
||||
| 驱动 IC | ST77922 TDDI (触显一体) |
|
||||
| 显示接口 | QSPI (接 ESP32-S3) |
|
||||
| 触摸屏 | 电容触摸 (全贴合), I2C 0x55 |
|
||||
| 背光 | PWM 控制, 亮度 300 cd/m² |
|
||||
|
||||
### 音频
|
||||
|
||||
| 项目 | 参数 |
|
||||
|------|------|
|
||||
| 编解码芯片 | ES8311 |
|
||||
| 功放 | FM8002E |
|
||||
| 麦克风 | MEMS 麦克风 (LMA2718B381) |
|
||||
| 音频接口 | I2S (双工: 输入+输出) |
|
||||
| 采样率 | 输入/输出 24000Hz |
|
||||
|
||||
### 外设
|
||||
|
||||
| 项目 | 型号/接口 |
|
||||
|------|-----------|
|
||||
| RGB LED | WS2812B ×1 (IO40) |
|
||||
| MicroSD | SDIO 4-bit |
|
||||
| 充电管理 | TP4054, 电池 ADC (IO8) |
|
||||
| 按键 | BOOT (IO0), RESET (EN) |
|
||||
|
||||
## 完整引脚分配
|
||||
|
||||
| GPIO | 功能 | 说明 |
|
||||
|------|------|------|
|
||||
| IO0 | BOOT 按键 | 开机按下=下载模式, 运行中=切换对话 |
|
||||
| IO1 | PA 使能 | 低电平使能功放 |
|
||||
| IO2 | SD D2 | SDIO DATA2 |
|
||||
| IO3 | SD D3 | SDIO DATA3 |
|
||||
| IO4 | SD CMD | SDIO 命令 |
|
||||
| IO5 | SD CLK | SDIO 时钟 |
|
||||
| IO6 | SD D0 | SDIO DATA0 |
|
||||
| IO7 | SD D1 | SDIO DATA1 |
|
||||
| IO8 | 电池 ADC | 电压检测 |
|
||||
| IO9 | LCD D3 | QSPI 数据 D3 |
|
||||
| IO10 | LCD CS | QSPI 片选 (低有效) |
|
||||
| IO11 | LCD D0 | QSPI 数据 D0 |
|
||||
| IO12 | LCD CLK | QSPI 时钟 |
|
||||
| IO13 | LCD D1 | QSPI 数据 D1 |
|
||||
| IO14 | LCD D2 | QSPI 数据 D2 |
|
||||
| IO15 | I2S DOUT | 音频输出 |
|
||||
| IO16 | I2S DIN | 音频输入 (MEMS 麦克风) |
|
||||
| IO17 | I2S MCLK | I2S 主时钟 |
|
||||
| IO18 | I2S BCLK | I2S 位时钟 |
|
||||
| IO21 | I2S WS | I2S 左右声道 |
|
||||
| IO38 | I2C SDA | 音频+触摸共用 |
|
||||
| IO39 | I2C SCL | 音频+触摸共用 |
|
||||
| IO40 | RGB LED | WS2812B 单线 |
|
||||
| IO41 | 背光 | PWM 高电平点亮 |
|
||||
| IO43 | UART RXD0 | 串口/普通 IO |
|
||||
| IO44 | UART TXD0 | 串口/普通 IO |
|
||||
| IO45 | GPIO45 | 扩展 IO |
|
||||
| IO46 | GPIO46 | 扩展 IO |
|
||||
| IO47 | 触摸 INT | 触摸中断 (低有效) |
|
||||
| IO48 | 触摸 RST | 触摸复位 (低复位) |
|
||||
| EN | LCD RST | 与 ESP32-S3 共用 |
|
||||
|
||||
### 显示 QSPI 引脚组
|
||||
|
||||
```
|
||||
CS = IO10 D0 = IO11
|
||||
CLK = IO12 D1 = IO13
|
||||
D2 = IO14
|
||||
D3 = IO9
|
||||
```
|
||||
|
||||
### I2C 设备地址
|
||||
|
||||
| 设备 | 地址 | 总线 |
|
||||
|------|------|------|
|
||||
| ES8311 音频 | ES8311_CODEC_DEFAULT_ADDR | I2C0 |
|
||||
| ST77922 触摸 | 0x55 | I2C0 (共享) |
|
||||
|
||||
## 编译
|
||||
|
||||
```bash
|
||||
# 一键编译打包 (推荐)
|
||||
python scripts/release.py lcdwiki-es3c35p
|
||||
|
||||
# 或手动编译
|
||||
idf.py set-target esp32s3
|
||||
idf.py menuconfig
|
||||
# Xiaozhi Assistant -> Board Type -> LCD Wiki ES3C35P (3.5寸 ESP32-S3)
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
## 关键配置说明
|
||||
|
||||
### 显示 ST77922 QSPI
|
||||
|
||||
| 配置项 | 值 | 原因 |
|
||||
|--------|-----|------|
|
||||
| `DISPLAY_WIDTH/HEIGHT` | 320×480 | 原生竖屏分辨率 |
|
||||
| `DISPLAY_RGB_ORDER` | BGR | 面板实际色彩顺序 |
|
||||
| `SPI_DMA_CH_AUTO` + `max_transfer_sz` | 51KB | SPI 总线 DMA,缓冲在 SRAM 避免 PSRAM 中转 |
|
||||
| `buff_dma=1, buff_spiram=0` | SRAM DMA | SRAM 可直接 DMA 访问,无需中转缓冲 |
|
||||
| `buffer_size` | width×80 (51KB) | 部分刷新缓冲 |
|
||||
| `st77922_rounder_cb` | x 坐标 4 对齐 | ST77922 硬件要求,否则花屏 |
|
||||
|
||||
### 触摸 ST77922 内置
|
||||
|
||||
| 配置项 | 值 |
|
||||
|--------|-----|
|
||||
| I2C 地址 | 0x55 |
|
||||
| 寄存器位宽 | 16 位 |
|
||||
| 单点数据 | 7 字节 |
|
||||
| 读取方式 | 必须一次性读 `7 × max_points` 字节清空缓冲 |
|
||||
|
||||
### 音频 ES8311
|
||||
|
||||
| 配置项 | 值 |
|
||||
|--------|-----|
|
||||
| PA 引脚 | IO1 |
|
||||
| PA 极性 | 低电平使能 (`pa_inverted=true`) |
|
||||
| I2C 总线 | I2C0 (与触摸共享 IO38/39) |
|
||||
| 采样率 | 24000Hz 输入/输出 |
|
||||
|
||||
## 已知限制
|
||||
|
||||
1. **ST77922 不支持 `swap_xy`** — 只能使用原生 320×480 竖屏
|
||||
2. **ST77922 要求 x 坐标 4 对齐** — 已通过 rounder_cb 自动处理
|
||||
3. **触摸无 DMA/中断** — 使用轮询方式读取,约 30fps
|
||||
4. **LVGL 缓冲在 SRAM** — 占用约 51KB,剩余 ~180KB 给其他模块
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
main/boards/lcdwiki-es3c35p/
|
||||
config.h — 引脚/硬件配置宏
|
||||
config.json — 构建目标 (esp32s3, 16MB Flash)
|
||||
lcdwiki-es3c35p.cc — 板级初始化 (QSPI 显示 + I2C 触摸 + ES8311 音频 + LED)
|
||||
README.md — 本文档
|
||||
```
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_17
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_18
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_16
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_15
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_1
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_38
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_39
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_40
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_10
|
||||
#define DISPLAY_CLK_PIN GPIO_NUM_12
|
||||
#define DISPLAY_DATA0_PIN GPIO_NUM_11
|
||||
#define DISPLAY_DATA1_PIN GPIO_NUM_13
|
||||
#define DISPLAY_DATA2_PIN GPIO_NUM_14
|
||||
#define DISPLAY_DATA3_PIN GPIO_NUM_9
|
||||
|
||||
#define DISPLAY_RST_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_41
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#define DISPLAY_WIDTH 320
|
||||
#define DISPLAY_HEIGHT 480
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_RGB_ORDER LCD_RGB_ELEMENT_ORDER_BGR
|
||||
#define DISPLAY_INVERT_COLOR false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
#define DISPLAY_BUFFER_LINES 80
|
||||
#define DISPLAY_BUFFER_SIZE (DISPLAY_WIDTH * DISPLAY_BUFFER_LINES)
|
||||
|
||||
#define TOUCH_RST_PIN GPIO_NUM_48
|
||||
#define TOUCH_INT_PIN GPIO_NUM_47
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "lcdwiki-es3c35p",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/16m.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "mcp_server.h"
|
||||
#include "led/single_led.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_common.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_st77922.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "LCDWikiES3C35P"
|
||||
|
||||
// ---- ST77922 touch controller (I2C addr 0x55, FT6336G-compatible) ----
|
||||
#define TOUCH_I2C_ADDR 0x55
|
||||
#define TOUCH_REG_INFO 0x0010
|
||||
#define TOUCH_REG_MAX_TOUCHES 0x0009
|
||||
#define TOUCH_REG_POINT0 0x0014
|
||||
|
||||
static i2c_master_dev_handle_t touch_dev_handle = NULL;
|
||||
static uint8_t touch_max_points = 1;
|
||||
|
||||
static esp_err_t touch_i2c_read(uint16_t reg, uint8_t *data, size_t len) {
|
||||
if (touch_dev_handle == NULL) return ESP_FAIL;
|
||||
uint8_t wbuf[2] = { (uint8_t)(reg >> 8), (uint8_t)(reg & 0xFF) };
|
||||
return i2c_master_transmit_receive(touch_dev_handle, wbuf, 2, data, len, pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
static void touchpad_read(lv_indev_t *, lv_indev_data_t *data) {
|
||||
static int16_t last_x = 0, last_y = 0;
|
||||
data->point.x = last_x;
|
||||
data->point.y = last_y;
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
|
||||
if (touch_dev_handle == NULL) return;
|
||||
uint8_t info;
|
||||
if (touch_i2c_read(TOUCH_REG_INFO, &info, 1) != ESP_OK) return;
|
||||
if (info & 0x08) {
|
||||
uint8_t buf[7 * 5];
|
||||
if (touch_i2c_read(TOUCH_REG_POINT0, buf, 7 * touch_max_points) == ESP_OK) {
|
||||
for (int i = 0; i < touch_max_points; i++) {
|
||||
if (buf[i * 7] & 0x80) {
|
||||
int16_t x = ((buf[i * 7] & 0x3F) << 8) | buf[i * 7 + 1];
|
||||
int16_t y = ((buf[i * 7 + 2] & 0x3F) << 8) | buf[i * 7 + 3];
|
||||
// Ignore jitter < 4px to reduce unwanted scroll on tap
|
||||
int16_t dx = x - last_x, dy = y - last_y;
|
||||
if (dx > 3 || dx < -3 || dy > 3 || dy < -3) {
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
}
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- ST77922 init commands ----
|
||||
static const st77922_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||
{0xF1, (uint8_t []){0x00}, 1, 0},
|
||||
{0x60, (uint8_t []){0x00, 0x00, 0x00}, 3, 0},
|
||||
{0x65, (uint8_t []){0x80}, 1, 0},
|
||||
{0x79, (uint8_t []){0x06}, 1, 0},
|
||||
{0x7B, (uint8_t []){0x00, 0x08, 0x08}, 3, 0},
|
||||
{0x80, (uint8_t []){0x55, 0x62, 0x2F, 0x17, 0xF0, 0x52, 0x70, 0xD2, 0x52, 0x62, 0xEA}, 11, 0},
|
||||
{0x81, (uint8_t []){0x26, 0x52, 0x72, 0x27}, 4, 0},
|
||||
{0x84, (uint8_t []){0x92, 0x25}, 2, 0},
|
||||
{0x87, (uint8_t []){0x10, 0x10, 0x58, 0x00, 0x02, 0x3A}, 6, 0},
|
||||
{0x88, (uint8_t []){0x00, 0x00, 0x2C, 0x10, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x06}, 15, 0},
|
||||
{0x89, (uint8_t []){0x00, 0x00, 0x00}, 3, 0},
|
||||
{0x8A, (uint8_t []){0x13, 0x00, 0x2C, 0x00, 0x00, 0x2C, 0x10, 0x10, 0x00, 0x3E, 0x19}, 11, 0},
|
||||
{0x8B, (uint8_t []){0x15, 0xB1, 0xB1, 0x44, 0x96, 0x2C, 0x10, 0x97, 0x8E}, 9, 0},
|
||||
{0x8C, (uint8_t []){0x1D, 0xB1, 0xB1, 0x44, 0x96, 0x2C, 0x10, 0x50, 0x0F, 0x01, 0xC5, 0x12, 0x09}, 13, 0},
|
||||
{0x8D, (uint8_t []){0x0C}, 1, 0},
|
||||
{0x8E, (uint8_t []){0x33, 0x01, 0x0C, 0x13, 0x01, 0x01}, 6, 0},
|
||||
{0xB3, (uint8_t []){0x00, 0x30}, 2, 0},
|
||||
{0xF1, (uint8_t []){0x00}, 1, 0},
|
||||
{0x71, (uint8_t []){0xD0}, 1, 0},
|
||||
{0x66, (uint8_t []){0x02, 0x3F}, 2, 0},
|
||||
{0xBE, (uint8_t []){0x26, 0x00, 0x9D}, 3, 0},
|
||||
{0x70, (uint8_t []){0x01, 0xA0, 0x11, 0x40, 0xE0, 0x00, 0x11, 0x69, 0x11, 0x00, 0x00, 0x1A}, 12, 0},
|
||||
{0x90, (uint8_t []){0x04, 0x04, 0x55, 0x74, 0x00, 0x40, 0x43, 0x27, 0x27}, 9, 0},
|
||||
{0x91, (uint8_t []){0x04, 0x04, 0x55, 0x75, 0x00, 0x40, 0x42, 0x27, 0x27}, 9, 0},
|
||||
{0x92, (uint8_t []){0x04, 0x44, 0x55, 0xC0, 0x06, 0x00, 0x07, 0x05, 0x90, 0x27}, 10, 0},
|
||||
{0x93, (uint8_t []){0x04, 0x43, 0x11, 0x00, 0x00, 0x00, 0x00, 0x05, 0x90, 0x27}, 10, 0},
|
||||
{0x94, (uint8_t []){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 6, 0},
|
||||
{0x95, (uint8_t []){0x96, 0x16, 0x00, 0x00, 0xFF}, 5, 0},
|
||||
{0x96, (uint8_t []){0x44, 0x53, 0x03, 0x12, 0x23, 0x24, 0x06, 0x05, 0x94, 0x27, 0x00, 0x44}, 12, 0},
|
||||
{0x97, (uint8_t []){0x44, 0x53, 0x47, 0x56, 0x20, 0x20, 0x02, 0x01, 0x94, 0x27, 0x00, 0x44}, 12, 0},
|
||||
{0xBA, (uint8_t []){0x55, 0x94, 0x2D, 0x94, 0x27}, 5, 0},
|
||||
{0x9A, (uint8_t []){0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00}, 7, 0},
|
||||
{0x9B, (uint8_t []){0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00}, 7, 0},
|
||||
{0x9C, (uint8_t []){0x5C, 0x12, 0x00, 0x00, 0x10, 0x12, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00}, 13, 0},
|
||||
{0x9D, (uint8_t []){0x8A, 0x51, 0x00, 0x00, 0x00, 0x80, 0x1E, 0x01}, 8, 0},
|
||||
{0x9E, (uint8_t []){0x51, 0x00, 0x00, 0x00, 0x80, 0x1E, 0x01}, 7, 0},
|
||||
{0xB4, (uint8_t []){0x1D, 0x1C, 0x1E, 0x0B, 0x14, 0x02, 0x13, 0x09, 0x1E, 0x00, 0x1E, 0x10}, 12, 0},
|
||||
{0xB5, (uint8_t []){0x1D, 0x1C, 0x1E, 0x0A, 0x15, 0x03, 0x11, 0x08, 0x1E, 0x01, 0x1E, 0x12}, 12, 0},
|
||||
{0xB6, (uint8_t []){0x77, 0x77, 0x00, 0x0A, 0xFF, 0x0A, 0xFF}, 7, 0},
|
||||
{0x86, (uint8_t []){0xCD, 0x04, 0xB1, 0x02, 0x58, 0x12, 0x58, 0x0C, 0x13, 0x01, 0xA5, 0x00, 0xA5, 0xA5}, 14, 0},
|
||||
{0xB7, (uint8_t []){0x07, 0x0A, 0x0E, 0x06, 0x05, 0x03, 0x2B, 0x03, 0x03, 0x42, 0x07, 0x10, 0x10, 0x2E, 0x3F, 0x0D}, 16, 0},
|
||||
{0xB8, (uint8_t []){0x07, 0x0A, 0x0D, 0x05, 0x05, 0x02, 0x2B, 0x02, 0x03, 0x42, 0x06, 0x10, 0x0F, 0x2E, 0x3F, 0x0D}, 16, 0},
|
||||
{0xB9, (uint8_t []){0x23, 0x23}, 2, 0},
|
||||
{0xBF, (uint8_t []){0x10, 0x14, 0x14, 0x0B, 0x0B, 0x0B}, 6, 0},
|
||||
{0xF2, (uint8_t []){0x00}, 1, 0},
|
||||
{0x73, (uint8_t []){0x04, 0xDA, 0x12, 0x54, 0x47}, 5, 0},
|
||||
{0x77, (uint8_t []){0x6B, 0x5B, 0xFD, 0xC3, 0xC5}, 5, 0},
|
||||
{0x7A, (uint8_t []){0x15, 0x27}, 2, 0},
|
||||
{0x7B, (uint8_t []){0x04, 0x57}, 2, 0},
|
||||
{0x7E, (uint8_t []){0x01, 0x0E}, 2, 0},
|
||||
{0xBF, (uint8_t []){0x36}, 1, 0},
|
||||
{0xE3, (uint8_t []){0x40, 0x40}, 2, 0},
|
||||
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||
{0xD0, (uint8_t []){0x00}, 1, 0},
|
||||
{0x2A, (uint8_t []){0x00, 0x00, 0x01, 0x3F}, 4, 0},
|
||||
{0x2B, (uint8_t []){0x00, 0x00, 0x01, 0xDF}, 4, 0},
|
||||
{0x21, (uint8_t []){0x00}, 0, 0},
|
||||
{0x11, (uint8_t []){0x00}, 0, 120},
|
||||
{0x29, (uint8_t []){0x00}, 0, 0},
|
||||
{0x2C, (uint8_t []){0x00}, 0, 0},
|
||||
{0x3A, (uint8_t []){0x01}, 1, 0},
|
||||
{0x36, (uint8_t []){0x00}, 1, 0},
|
||||
{0x35, (uint8_t []){0x01}, 1, 20},
|
||||
};
|
||||
|
||||
// ---- Display class with ST77922 4-pixel alignment ----
|
||||
static void st77922_rounder_cb(lv_event_t *e)
|
||||
{
|
||||
lv_area_t *area = (lv_area_t *)lv_event_get_param(e);
|
||||
area->x1 = (area->x1 >> 2) << 2;
|
||||
area->x2 = ((area->x2 >> 2) << 2) + 3;
|
||||
}
|
||||
|
||||
class ST77922_Display : public LcdDisplay {
|
||||
private:
|
||||
void LvglInit() {
|
||||
lv_init();
|
||||
lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
port_cfg.task_priority = 1;
|
||||
port_cfg.task_affinity = 1;
|
||||
lvgl_port_init(&port_cfg);
|
||||
|
||||
const lvgl_port_display_cfg_t display_cfg = {
|
||||
.io_handle = panel_io_,
|
||||
.panel_handle = panel_,
|
||||
.control_handle = nullptr,
|
||||
.buffer_size = static_cast<uint32_t>(DISPLAY_BUFFER_SIZE),
|
||||
.double_buffer = false,
|
||||
.trans_size = 0,
|
||||
.hres = static_cast<uint32_t>(DISPLAY_WIDTH),
|
||||
.vres = static_cast<uint32_t>(DISPLAY_HEIGHT),
|
||||
.monochrome = false,
|
||||
.rotation = {
|
||||
.swap_xy = false,
|
||||
.mirror_x = false,
|
||||
.mirror_y = false,
|
||||
},
|
||||
.color_format = LV_COLOR_FORMAT_RGB565,
|
||||
.flags = {
|
||||
.buff_dma = 1,
|
||||
.buff_spiram = 0,
|
||||
.sw_rotate = 0,
|
||||
.swap_bytes = 1,
|
||||
.full_refresh = 0,
|
||||
.direct_mode = 0,
|
||||
},
|
||||
};
|
||||
display_ = lvgl_port_add_disp(&display_cfg);
|
||||
if (display_ != nullptr) {
|
||||
lv_display_add_event_cb(display_, st77922_rounder_cb, LV_EVENT_INVALIDATE_AREA, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
ST77922_Display(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel,
|
||||
int width, int height, int offset_x, int offset_y,
|
||||
bool mirror_x, bool mirror_y, bool swap_xy)
|
||||
: LcdDisplay(panel_io, panel, width, height) {
|
||||
LvglInit();
|
||||
if (offset_x != 0 || offset_y != 0) {
|
||||
lv_display_set_offset(display_, offset_x, offset_y);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class LCDWikiES3C35P_Board : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
ST77922_Display* display_;
|
||||
|
||||
void InitializeI2c() {
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.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,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = { .enable_internal_pullup = 1 },
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeQspiBus() {
|
||||
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = DISPLAY_CLK_PIN;
|
||||
buscfg.data0_io_num = DISPLAY_DATA0_PIN;
|
||||
buscfg.data1_io_num = DISPLAY_DATA1_PIN;
|
||||
buscfg.data2_io_num = DISPLAY_DATA2_PIN;
|
||||
buscfg.data3_io_num = DISPLAY_DATA3_PIN;
|
||||
buscfg.max_transfer_sz = DISPLAY_BUFFER_SIZE * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
ESP_LOGI(TAG, "Install QSPI panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = ST77922_PANEL_IO_QSPI_CONFIG(DISPLAY_CS_PIN, NULL, NULL);
|
||||
io_config.pclk_hz = 80 * 1000 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
ESP_LOGI(TAG, "Install ST77922 LCD driver");
|
||||
st77922_vendor_config_t vendor_config = {
|
||||
.init_cmds = lcd_init_cmds,
|
||||
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(st77922_lcd_init_cmd_t),
|
||||
.flags = { .use_qspi_interface = 1 },
|
||||
};
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = DISPLAY_RST_PIN;
|
||||
panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = (void *)&vendor_config;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st77922(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true));
|
||||
|
||||
display_ = new ST77922_Display(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y,
|
||||
DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeTouch() {
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = TOUCH_I2C_ADDR,
|
||||
.scl_speed_hz = 400000,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_, &dev_cfg, &touch_dev_handle));
|
||||
|
||||
gpio_config_t rst_cfg = { .pin_bit_mask = (1ULL << TOUCH_RST_PIN), .mode = GPIO_MODE_OUTPUT };
|
||||
gpio_config(&rst_cfg);
|
||||
gpio_set_level(TOUCH_RST_PIN, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(TOUCH_RST_PIN, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// Read max supported touch points
|
||||
uint8_t max_pts;
|
||||
if (touch_i2c_read(TOUCH_REG_MAX_TOUCHES, &max_pts, 1) == ESP_OK && max_pts > 0 && max_pts <= 5) {
|
||||
touch_max_points = max_pts;
|
||||
}
|
||||
ESP_LOGI(TAG, "Touch max points: %d", touch_max_points);
|
||||
|
||||
lv_indev_t *indev = lv_indev_create();
|
||||
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(indev, touchpad_read);
|
||||
lv_indev_set_disp(indev, lv_display_get_default());
|
||||
ESP_LOGI(TAG, "Touch initialized successfully");
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"End this conversation and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
LCDWikiES3C35P_Board() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
InitializeQspiBus();
|
||||
InitializeLcdDisplay();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(i2c_bus_, I2C_NUM_0,
|
||||
AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR, true, true);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override { return display_; }
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
virtual Led* GetLed() override {
|
||||
static SingleLed led(BUILTIN_LED_GPIO);
|
||||
return &led;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(LCDWikiES3C35P_Board);
|
||||
@@ -53,6 +53,7 @@ dependencies:
|
||||
version: ^1.0.1
|
||||
rules:
|
||||
- if: target not in [esp32]
|
||||
espressif/esp_lcd_st77922: ^2.0.2
|
||||
espressif/esp_lcd_touch_ft5x06: ~1
|
||||
espressif/esp_lcd_touch_gt911: ^1
|
||||
espressif/esp_lcd_touch_gt1151: ^1
|
||||
|
||||
@@ -24,8 +24,8 @@ class VersionTests(unittest.TestCase):
|
||||
def test_current_matrix_counts_and_uniqueness(self):
|
||||
idf5 = release._collect_variants(idf_version=(5, 5, 4))
|
||||
idf6 = release._collect_variants(idf_version=(6, 0, 1))
|
||||
self.assertEqual(len(idf5), 171)
|
||||
self.assertEqual(len(idf6), 157)
|
||||
self.assertEqual(len(idf5), 172)
|
||||
self.assertEqual(len(idf6), 158)
|
||||
for variants in (idf5, idf6):
|
||||
names = [variant["full_name"] for variant in variants]
|
||||
self.assertEqual(len(names), len(set(names)))
|
||||
|
||||
Reference in New Issue
Block a user