290 lines
10 KiB
Markdown
290 lines
10 KiB
Markdown
# 项目对比分析报告
|
||
|
||
## 1. 项目概述
|
||
|
||
本次分析对比了两个基于 ESP32 平台的 LCD 驱动项目,重点分析 d zbj 项目在适配 LVGL 时遇到的问题:
|
||
|
||
| 项目名称 | 路径 | 主要功能 |
|
||
|---------|------|----------|
|
||
| d zbj 项目 | `/Users/rdzleo/Desktop/dzbj` | 完整的嵌入式应用,包含 LCD 显示、触摸等功能 |
|
||
| QSPI LCD 驱动版本 | `/Users/rdzleo/Desktop/qspi_lcd_驱动版本` | 专注于 LCD 驱动和触摸功能的实现,LVGL 适配成功 |
|
||
|
||
## 2. 项目结构对比
|
||
|
||
### 2.1 d zbj 项目结构
|
||
|
||
```
|
||
dzbj/
|
||
├── main/
|
||
│ ├── axis/ # 轴控制相关代码
|
||
│ ├── ble/ # BLE 蓝牙功能
|
||
│ ├── fatfs/ # 文件系统功能
|
||
│ ├── gpio/ # GPIO 控制
|
||
│ ├── lcd/ # LCD 驱动实现
|
||
│ ├── pages/ # 页面管理
|
||
│ ├── temp/ # 温度检测
|
||
│ ├── ui/ # UI 界面(SquareLine Studio 生成)
|
||
│ ├── wifi/ # WiFi 功能
|
||
│ └── main.c # 主函数
|
||
├── build/ # 构建输出
|
||
└── CMakeLists.txt # 构建配置
|
||
```
|
||
|
||
### 2.2 QSPI LCD 驱动版本结构
|
||
|
||
```
|
||
qspi_lcd_驱动版本/
|
||
├── main/
|
||
│ ├── display_touch_manager.h # 显示和触摸管理接口
|
||
│ ├── lcd_touch_driver.h # LCD 触摸驱动接口
|
||
│ └── main.c # 主函数
|
||
├── components/
|
||
│ └── lvgl/ # LVGL 组件
|
||
└── CMakeLists.txt # 构建配置
|
||
```
|
||
|
||
## 3. LCD 驱动实现对比
|
||
|
||
### 3.1 d zbj 项目 LCD 实现
|
||
|
||
**核心文件**:`/Users/rdzleo/Desktop/dzbj/main/lcd/lcd.c`
|
||
|
||
**实现特点**:
|
||
- 使用 QSPI 接口驱动 ST77916 LCD 控制器
|
||
- 直接调用 ESP-IDF 提供的 LCD 相关 API
|
||
- 分步骤初始化:SPI 总线 → LCD IO → LCD 面板 → 重置和初始化面板
|
||
- 支持触摸功能(CST816S 触摸控制器)
|
||
- 配置了双缓冲和 DMA 传输
|
||
|
||
**关键代码**:
|
||
```c
|
||
void lcd_init(){
|
||
const spi_bus_config_t buscfg = ST77916_PANEL_BUS_QSPI_CONFIG(...);
|
||
spi_bus_initialize(SPI_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
||
const esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(...);
|
||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(...));
|
||
const st77916_vendor_config_t vendor_config = {
|
||
.flags = {
|
||
.use_qspi_interface = 1,
|
||
},
|
||
};
|
||
const esp_lcd_panel_dev_config_t panel_config = {...};
|
||
ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(...));
|
||
esp_lcd_panel_reset(panel_handle);
|
||
esp_lcd_panel_init(panel_handle);
|
||
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||
}
|
||
```
|
||
|
||
### 3.2 QSPI LCD 驱动版本实现
|
||
|
||
**核心文件**:通过 `display_manager_init()` 函数实现
|
||
|
||
**实现特点**:
|
||
- 使用显示管理器和触摸管理器的抽象层
|
||
- 封装了 LCD 初始化的细节
|
||
- 提供统一的接口函数
|
||
- 结构更清晰,职责更明确
|
||
|
||
**关键代码**:
|
||
```c
|
||
void app_main(void) {
|
||
// 初始化显示管理器
|
||
esp_err_t ret = display_manager_init();
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "显示管理器初始化失败: %s", esp_err_to_name(ret));
|
||
return;
|
||
}
|
||
|
||
// 获取显示驱动
|
||
lv_disp_t *display = display_manager_get_display();
|
||
if (display == NULL) {
|
||
ESP_LOGE(TAG, "获取显示驱动失败");
|
||
return;
|
||
}
|
||
|
||
// 初始化触摸管理器
|
||
ret = touch_manager_init(display);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "触摸管理器初始化失败: %s", esp_err_to_name(ret));
|
||
return;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.3 驱动实现对比分析
|
||
|
||
| 对比项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||
|--------|-----------|-------------------|
|
||
| 接口方式 | 直接调用 ESP-IDF API | 使用抽象层管理器 |
|
||
| 代码复杂度 | 相对复杂,包含更多细节 | 更简洁,封装了细节 |
|
||
| 可维护性 | 模块化但分散 | 集中管理,更易维护 |
|
||
| 灵活性 | 高度灵活,可自定义各环节 | 标准化流程,灵活性稍低 |
|
||
| 初始化流程 | 线性初始化各组件 | 分层初始化,结构更清晰 |
|
||
| 错误处理 | 基本错误检查 | 详细的错误处理和日志 |
|
||
|
||
## 4. 初始化流程对比
|
||
|
||
### 4.1 d zbj 项目初始化流程
|
||
|
||
**核心文件**:`/Users/rdzleo/Desktop/dzbj/main/main.c`
|
||
|
||
**初始化顺序**:
|
||
1. `i2c_init()` - 初始化 I2C 总线
|
||
2. `nvs_init()` - 初始化 NVS 存储
|
||
3. `lcd_init()` - 初始化 LCD 面板
|
||
4. `touch_init()` - 初始化触摸控制器
|
||
5. `lvgl_lcd_init()` - 初始化 LVGL 显示
|
||
6. `fatfs_init()` - 初始化文件系统
|
||
7. `pwm_init()` - 初始化 PWM 背光
|
||
8. `app_test_display()` - 显示测试屏幕
|
||
|
||
### 4.2 QSPI LCD 驱动版本初始化流程
|
||
|
||
**核心文件**:`/Users/rdzleo/Desktop/qspi_lcd_驱动版本/main/main.c`
|
||
|
||
**初始化顺序**:
|
||
1. `display_manager_init()` - 初始化显示管理器
|
||
2. `display_manager_get_display()` - 获取显示驱动
|
||
3. 创建 LVGL 任务
|
||
4. 等待 LVGL 任务启动
|
||
5. `ui_init()` - 初始化 SquareLine Studio UI
|
||
6. 等待 LVGL 完成初始渲染
|
||
7. `touch_manager_init(display)` - 初始化触摸管理器
|
||
8. 控制 LCD 开关状态
|
||
|
||
## 5. 技术选型对比
|
||
|
||
### 5.1 硬件平台
|
||
|
||
- **d zbj 项目**:ESP32-S3 系列
|
||
- **QSPI LCD 驱动版本**:ESP32-S3 系列
|
||
|
||
### 5.2 LCD 控制器
|
||
|
||
- **d zbj 项目**:ST77916S
|
||
- **QSPI LCD 驱动版本**:ST77916S
|
||
|
||
### 7.3 通信接口
|
||
|
||
- **d zbj 项目**:QSPI(LCD)、I2C(触摸)
|
||
- **QSPI LCD 驱动版本**:QSPI(LCD)、I2C(触摸)
|
||
|
||
### 7.4 软件框架
|
||
|
||
- **d zbj 项目**:ESP-IDF + LVGL + SquareLine Studio
|
||
- **QSPI LCD 驱动版本**:ESP-IDF + LVGL + SquareLine Studio
|
||
|
||
### 7.5 SDK 配置对比
|
||
|
||
| 配置项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||
|--------|-----------|-------------------|
|
||
| ESP-IDF 版本 | 5.4.2 | 最新稳定版 |
|
||
| 编译器 | xtensa-esp32s3-elf-gcc | xtensa-esp32s3-elf-gcc |
|
||
| 构建系统 | CMake | CMake |
|
||
| 目标芯片 | esp32s3 | esp32s3 |
|
||
|
||
### 7.6 LVGL 配置对比
|
||
|
||
| 配置项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||
|--------|-----------|-------------------|
|
||
| LVGL 版本 | 8.3.11 | 8.3.11 |
|
||
| 颜色深度 | 16位 (CONFIG_LV_COLOR_DEPTH_16=y) | 16位 (CONFIG_LV_COLOR_DEPTH_16=y) |
|
||
| 字节交换 | 启用 (CONFIG_LV_COLOR_16_SWAP=y) | 启用 (CONFIG_LV_COLOR_16_SWAP=y) |
|
||
| 内存大小 | 64KB (CONFIG_LV_MEM_SIZE_KILOBYTES=64) | 32KB (CONFIG_LV_MEM_SIZE_KILOBYTES=32) |
|
||
| 显示缓冲 | 双缓冲,支持 DMA | 双缓冲,支持 DMA |
|
||
| 任务优先级 | 4 | 4 |
|
||
| 任务堆栈大小 | 8192 | 8192 |
|
||
|
||
### 7.7 显示缓冲区配置对比
|
||
|
||
| 配置项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||
|--------|-----------|-------------------|
|
||
| 缓冲区大小计算 | `LCD_WID*LCD_HIGH/5` | `EXAMPLE_LCD_H_RES * EXAMPLE_LVGL_DRAW_BUF_LINES` (360*30) |
|
||
| 内存分配方式 | ESP-IDF 标准内存分配 | `spi_bus_dma_memory_alloc` 专门为 SPI DMA 分配 |
|
||
| 双缓冲 | 启用 | 启用 |
|
||
| DMA 支持 | 启用 | 启用 |
|
||
| 刷新机制 | LVGL 标准刷新 | 自定义回调 `example_notify_lvgl_flush_ready` |
|
||
|
||
### 7.8 UI 文件对比
|
||
|
||
| 对比项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||
|--------|-----------|-------------------|
|
||
| SquareLine Studio 版本 | 相同版本 | 相同版本 |
|
||
| UI 导出格式 | 压缩的 PNG 格式 | 压缩的 PNG 格式 |
|
||
| 屏幕数量 | 包含多个屏幕(Home、Set、Img) | 包含多个屏幕(Home、Set、Img) |
|
||
| 图片资源 | 包含相同的图片资源 | 包含相同的图片资源 |
|
||
| 组件结构 | 完全相同的组件结构 | 完全相同的组件结构 |
|
||
| 事件处理 | 相同的事件处理机制 | 相同的事件处理机制 |
|
||
|
||
### 7.9 关键差异分析
|
||
|
||
1. **内存分配方式**:
|
||
- qspi_lcd_驱动版本使用 `spi_bus_dma_memory_alloc` 专门为 SPI DMA 传输分配内存
|
||
- d zbj 项目使用标准内存分配,可能不是最优的 DMA 内存
|
||
|
||
2. **显示缓冲区配置**:
|
||
- qspi_lcd_驱动版本使用固定的 30 行作为缓冲区大小
|
||
- d zbj 项目使用 `LCD_WID*LCD_HIGH/5` 计算缓冲区大小
|
||
|
||
3. **初始化流程**:
|
||
- qspi_lcd_驱动版本使用管理器模式,分层初始化,包含详细的错误处理
|
||
- d zbj 项目使用线性初始化流程,错误处理相对简单
|
||
|
||
4. **刷新回调**:
|
||
- qspi_lcd_驱动版本实现了自定义的 `example_notify_lvgl_flush_ready` 回调
|
||
- d zbj 项目使用 LVGL 标准刷新机制
|
||
|
||
### 7.10 花屏问题分析
|
||
|
||
基于以上对比,导致 d zbj 项目花屏的可能原因包括:
|
||
|
||
1. **内存分配问题**:
|
||
- 未使用 `spi_bus_dma_memory_alloc` 分配适合 DMA 传输的内存
|
||
- 可能导致 DMA 传输数据错误,引起花屏
|
||
|
||
2. **显示缓冲区配置**:
|
||
- `LCD_WID*LCD_HIGH/5` 计算出的缓冲区大小可能不合适
|
||
- 缓冲区过小可能导致显示不完整,过大可能导致内存不足
|
||
|
||
3. **初始化流程问题**:
|
||
- 初始化顺序可能影响硬件状态
|
||
- 缺少必要的初始化步骤或延迟
|
||
|
||
4. **刷新机制问题**:
|
||
- 缺少自定义的刷新就绪回调
|
||
- 可能导致 LVGL 与硬件刷新不同步
|
||
|
||
## 7. 解决方案
|
||
|
||
### 7.1 具体措施
|
||
|
||
1. **优化内存分配**:
|
||
- 使用 `spi_bus_dma_memory_alloc` 专门为 SPI DMA 传输分配内存
|
||
- 确保内存对齐和连续性,提高 DMA 传输效率
|
||
|
||
2. **调整缓冲区配置**:
|
||
- 参考 QSPI LCD 驱动版本,使用固定行数的缓冲区大小(如 30 行)
|
||
- 确保缓冲区大小合理,避免内存不足或浪费
|
||
|
||
3. **改进刷新机制**:
|
||
- 实现自定义的 `notify_lvgl_flush_ready` 回调
|
||
- 确保 LVGL 与硬件刷新同步,减少显示异常
|
||
|
||
4. **优化初始化流程**:
|
||
- 参考 QSPI LCD 驱动版本的管理器模式
|
||
- 确保初始化顺序正确,添加必要的延迟
|
||
- 增加详细的错误处理和日志输出
|
||
|
||
## 8. 结论
|
||
|
||
通过对两个项目的详细对比分析,我们发现导致 d zbj 项目花屏的主要原因是:
|
||
|
||
1. **内存分配方式不当**:未使用专门的 `spi_bus_dma_memory_alloc` 函数分配适合 DMA 传输的内存
|
||
2. **显示缓冲区配置不合理**:缓冲区大小计算方式可能导致内存使用不当
|
||
3. **刷新机制不同步**:缺少自定义的刷新就绪回调,可能导致 LVGL 与硬件刷新不同步
|
||
4. **初始化流程差异**:初始化顺序和错误处理的差异可能影响硬件状态
|
||
|
||
采用 QSPI LCD 驱动版本的实现方式,特别是内存分配、缓冲区配置和刷新机制的优化,可以有效解决 d zbj 项目的花屏问题,提高 LVGL 适配的稳定性和可靠性。
|
||
|