# 项目对比分析报告 ## 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 适配的稳定性和可靠性。