# ESP32-S3 HL Audio

ESP32-S3 HL Audio 是基于小智固件框架适配的圆屏语音交互板级工程。当前默认板级目标为 `esp32s3_hl_audio`，核心代码集中在 `main/boards/esp32s3_hl_audio/`。

本仓库当前状态面向以下硬件组合：

| 模块 | 当前配置 |
| :--- | :--- |
| 主控 | ESP32-S3 |
| 显示 | 2.1 寸 GC9B72 BOE 360x360 QSPI 圆屏 |
| 触摸 | CST816S，接入 LVGL 指针输入设备 |
| 音频 | ES8311 codec，I2C0 配置寄存器，I2S0 双工输入输出 |
| 电源 | AXP2101 PMU，I2C0 纯轮询读取电量、充电和放电状态 |
| 配网 | Wi-Fi 热点网页配网 |
| 资源 | 默认资源分区，包含 `mjpeg`、`setting`、`font`、`baji` 等素材 |

## 当前配置

当前 `sdkconfig` 的关键配置如下：

| 配置项 | 值 |
| :--- | :--- |
| 目标芯片 | `CONFIG_IDF_TARGET="esp32s3"` |
| 板级类型 | `CONFIG_BOARD_TYPE_ESP32S3_HL_AUDIO=y` |
| Flash | `CONFIG_ESPTOOLPY_FLASHSIZE="16MB"` |
| PSRAM | `CONFIG_SPIRAM=y`，`CONFIG_SPIRAM_SPEED=80` |
| 语言 | `CONFIG_LANGUAGE_ZH_CN=y` |
| 唤醒词 | `CONFIG_USE_AFE_WAKE_WORD=y` |
| 音频处理 | `CONFIG_USE_AUDIO_PROCESSOR=y` |
| 配网方式 | `CONFIG_USE_HOTSPOT_WIFI_PROVISIONING=y` |
| 默认资源 | `CONFIG_FLASH_DEFAULT_ASSETS=y` |
| OTA 地址 | `https://api.tenclass.net/xiaozhi/ota/` |

## 代码结构

| 路径 | 作用 |
| :--- | :--- |
| `main/CMakeLists.txt` | 根据 `CONFIG_BOARD_TYPE_ESP32S3_HL_AUDIO` 选择 `esp32s3_hl_audio` 板级目录，并按配置接入音频处理、资源等模块。 |
| `main/boards/esp32s3_hl_audio/config.h` | 当前板子的屏幕、音频、触摸、背光、按键和总线引脚定义。 |
| `main/boards/esp32s3_hl_audio/esp32s3_hl_audio.cc` | 板级主实现，继承 `WifiBoard`，负责初始化省电、I2C、PMU、QSPI 屏、触摸、按键，并向应用层暴露音频、显示、背光、电池接口。 |
| `main/boards/esp32s3_hl_audio/pmu_axp2101.cc` | AXP2101 电源管理实现，包含电池参数写入、充电配置、状态轮询和看门狗喂狗。 |
| `components/esp_lcd_st77916_1.8in/` | 本地 QSPI 圆屏组件，统一维护 1.8 寸 ST77916 与 2.1 寸 GC9B72 初始化表。 |
| `main/audio/` | 音频服务、codec、解复用和音频处理链路。 |
| `main/display/` | LVGL 显示、主题、表情、图片和 GIF/JPEG 支持。 |
| `main/protocols/` | MQTT/WebSocket 协议实现。 |
| `main/ota.cc`、`main/assets.cc` | 固件 OTA 与资源更新。 |
| `sdcard_assets/` | 当前随工程维护的外部素材目录。 |

## 板级初始化流程

`Esp32S3HlAudio` 构造函数按以下顺序初始化硬件和服务：

1. `InitializePowerSaveTimer()`：空闲 60 秒后降低背光并进入显示省电模式；当前已禁用长时间空闲后的深睡关机。
2. `InitializeCodecI2c()`：初始化 I2C0，ES8311、CST816S 和 AXP2101 共用此总线。
3. `InitializePowerManager()`：初始化 AXP2101 电源管理，轮询电池、电源和充电状态。
4. `InitializeQspiBus()`：初始化 SPI2 QSPI 显示总线。
5. `InitializeLcdDisplay()`：按 `BOARD_PANEL_2_1IN` 选择 GC9B72 或 ST77916 初始化表，并创建 `SpiLcdDisplay`。
6. `InitializeTouch()`：初始化 CST816S 并注册到 LVGL。
7. `InitializeButtons()`：BOOT 按键在启动期进入配网模式，运行期切换对话状态。

应用层通过以下板级接口访问硬件能力：

- `GetAudioCodec()`：返回 ES8311 音频 codec。
- `GetDisplay()`：返回 LVGL LCD 显示对象。
- `GetBacklight()`：返回 PWM 背光控制对象。
- `GetBatteryLevel()`：返回电量、充电和放电状态。
- `SetPowerSaveLevel()`：唤醒省电定时器，再交给 `WifiBoard` 处理系统省电级别。

## 关键引脚

### 显示与背光

| 信号 | GPIO |
| :--- | :--- |
| QSPI PCLK | `GPIO_NUM_12` |
| QSPI D0 | `GPIO_NUM_7` |
| QSPI D1 | `GPIO_NUM_8` |
| QSPI D2 | `GPIO_NUM_9` |
| QSPI D3 | `GPIO_NUM_10` |
| LCD CS | `GPIO_NUM_11` |
| LCD RST | `GPIO_NUM_14` |
| 背光 | `GPIO_NUM_18` |

### 音频与 I2C

| 信号 | GPIO |
| :--- | :--- |
| I2S MCLK | `GPIO_NUM_40` |
| I2S WS | `GPIO_NUM_48` |
| I2S BCLK | `GPIO_NUM_38` |
| I2S DIN | `GPIO_NUM_47` |
| I2S DOUT | `GPIO_NUM_39` |
| PA CTRL | `GPIO_NUM_21` |
| I2C SDA | `GPIO_NUM_16` |
| I2C SCL | `GPIO_NUM_15` |

### 触摸与按键

| 信号 | GPIO |
| :--- | :--- |
| CST816S INT | `GPIO_NUM_17` |
| CST816S RST | `GPIO_NUM_6` |
| BOOT 按键 | `GPIO_NUM_0` |

## 屏幕型号切换

当前硬件默认为 2.1 寸 GC9B72 BOE 圆屏：

```c
#define BOARD_PANEL_2_1IN        1
```

如需切回 1.8 寸 ST77916 BOE 圆屏，在 `main/boards/esp32s3_hl_audio/config.h` 中改为：

```c
#define BOARD_PANEL_2_1IN        0
```

两种屏的 QSPI、背光和触摸引脚一致，仅初始化表不同。组件说明见 `components/esp_lcd_st77916_1.8in/README.md`。

## 省电行为

当前省电逻辑只负责熄屏和恢复显示：

- 空闲 60 秒后调用 `SetPowerSaveMode(true)`，并把背光降到 1。
- 设备被唤醒后调用 `SetPowerSaveMode(false)`，并恢复背光亮度。
- 长时间空闲后的 `OnShutdownRequest` 深睡关机逻辑已移除，不会再自动进入 `esp_deep_sleep_start()`。

充电状态会影响省电定时器：

- 充电中：暂停省电定时器。
- 放电中：启用省电定时器。

## 配网与运行状态

当前启用 Wi-Fi 热点网页配网，不再默认进入 ESP Blufi 蓝牙配网。设备进入配网模式时，屏幕会提示连接热点和浏览器访问地址。

BOOT 按键行为：

- 启动阶段点击：进入 Wi-Fi 配网模式。
- 正常运行阶段点击：切换对话状态。

## 构建

构建环境从 `.vscode/settings.json` 的 `idf.currentSetup` 读取：

```powershell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;
$OutputEncoding = [System.Text.Encoding]::UTF8;
$settings = Get-Content -Encoding UTF8 .vscode/settings.json | ConvertFrom-Json;
$idfPath = $settings.'idf.currentSetup'.TrimEnd('/','\');
cmd /c "`"$idfPath\export.bat`" && idf.py build"
```

构建成功标志为输出包含：

```text
Project build complete
```

如果 `export.bat` 提示找不到 Python 虚拟环境，可临时使用本机已知可用环境：

```powershell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;
$OutputEncoding = [System.Text.Encoding]::UTF8;
$env:IDF_TOOLS_PATH = 'C:\Espressif';
$env:IDF_PYTHON_ENV_PATH = 'C:\Espressif\python_env\idf5.5_py3.11_env';
cmd /c "`"C:\Espressif\frameworks\esp-idf-v5.5.4\export.bat`" && idf.py build"
```

## 烧录

确认串口后执行：

```powershell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;
$OutputEncoding = [System.Text.Encoding]::UTF8;
$settings = Get-Content -Encoding UTF8 .vscode/settings.json | ConvertFrom-Json;
$idfPath = $settings.'idf.currentSetup'.TrimEnd('/','\');
$port = $settings.'idf.portWin';
cmd /c "`"$idfPath\export.bat`" && idf.py -p $port flash monitor"
```

如果串口被 monitor 或其它工具占用，先关闭占用进程后再烧录。

## 资源

`sdcard_assets/` 当前包含：

- `mjpeg`
- `setting`
- `font`
- `baji`
- `VERSION`

当前未移植时钟界面素材。资源更新逻辑由 `main/assets.cc` 处理，固件升级逻辑由 `main/ota.cc` 处理。

## 维护注意事项

- 修改 `main`、显示、触摸、音频、电源、CMake、Kconfig 或工程配置后，需要执行 `idf.py build` 验证。
- 修改纯文档时，可不触发固件构建，但需要确认路径、配置项和行为说明准确。
- 不要删除 `sdkconfig`，它记录当前工程动态配置状态。
- `components/esp_lcd_st77916_1.8in/` 是当前圆屏驱动组件，新增或调整圆屏初始化表时优先在该组件内处理。
- `components/eezui` 如存在，不要手工修改，应通过 EEZ Studio 重新导出。
- 日志、注释和界面文本保持简体中文，源码中的中文直接写原始字符，不写成转义字符串。
