esp-iot-solution LVGL Common Demo 实战:一套代码驱动 MIPI DSI / RGB / QSPI / SPI 四类 LCD 并跑通官方 Benchmark
【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution
导读:
lvgl_common_demo是 esp-iot-solution 仓库中基于esp_lvgl_adapter组件与 LVGL 9 的"统一显示"参考示例,仅需一份代码即可在 MIPI DSI、RGB、QSPI、SPI 四类 LCD 接口上运行 LVGL 官方 Benchmark(基准测试)。本文以该示例的 README.md 为骨架,结合hw_init、example_lvgl_init等源码实现,完整讲解硬件选型、menuconfig 配置、编译烧录、八步初始化流程、FPS 监控与撕裂规避原理,帮助你在自己的开发板上快速跑通 LVGL 性能评估。
示例定位与适用场景
lvgl_common_demo展示的是如何使用esp_lvgl_adapter组件与 LVGL 协同工作,在不同 LCD 接口上运行 LVGL 官方 benchmark demo,是"以统一方式把 LVGL 接入不同类型显示屏"的参考实现(见 README.md)。
它最典型的用途包括:
- 评估不同 LCD 接口的显示性能(DSI / RGB / QSPI / SPI 横向对比渲染能力);
- 验证硬件连接与驱动配置是否正确;
- 对 LVGL 渲染能力做基准测试(Benchmark);
- 学习基于
esp_lvgl_adapter的 LVGL 应用标准工程结构。
该示例支持以下芯片与接口组合(见 README 首部表格):
| Supported Targets | ESP32-P4 | ESP32-S3 | ESP32-S31 | ESP32-C3 |
|---|
核心特性一览
- 统一 LCD 接口支持:单套代码即可驱动 MIPI DSI、RGB、QSPI、SPI 四种 LCD 面板;
- LVGL benchmark demo:运行标准 LVGL 基准测试,量化渲染性能;
- 多输入方式:同时支持触摸屏与旋转编码器(旋钮)输入;
- FPS 监控:可选帧率统计,便于性能分析;
- 显示旋转:可配置屏幕方向(0°/90°/180°/270°);
- 防撕裂(Tear Avoidance):内置撕裂规避机制。
硬件准备与推荐组合
硬件需求
根据 README.md,你需要:
- 一块 ESP32-P4、ESP32-S3、ESP32-S31 或 ESP32-C3 开发板;
- 一块带以下任一接口的 LCD 面板:
- MIPI DSI:面向高分辨率屏(如 1024x600);
- RGB:并行 RGB 接口(如 800x480);
- QSPI:四线 SPI 屏(如 360x360、400x400);
- SPI:标准 SPI 屏(如 240x240、320x240);
- (可选)触摸屏或旋转编码器作为输入;
- 一条用于供电与烧录的 USB 线。
推荐硬件组合
| Chip | LCD Interface | Development Board |
|---|---|---|
| ESP32-P4 | MIPI DSI | ESP32-P4-Function-EV-Board |
| ESP32-S3 | RGB | ESP32-S3-LCD-EV-Board |
| ESP32-S3 | QSPI | ESP-VoCat |
| ESP32-S3 | SPI | ESP32-S3-BOX-3 |
| ESP32-S31 | RGB | 参考你的开发板文档 |
| ESP32-C3 | SPI | ESP32-C3-LCDkit |
上表中开发板的官方资料链接请查阅 README.md 原文(各开发板的硬件手册由乐鑫官方维护)。
硬件连接要点
LCD 与触摸屏的具体接线取决于你的硬件配置。本示例使用hw_init组件提供针对不同板卡的硬件抽象(详见 hw_init 目录)。常见接口的接线特征如下(见 README.md):
- MIPI DSI:使用专用 MIPI 差分线(D0+/-、D1+/-、CLK+/-);
- RGB:并行数据线(RGB565 为 16 根数据线 + HSYNC/VSYNC/DE/PCLK);
- QSPI:4 根数据线(IO0-IO3 + CLK + CS);
- SPI:标准 SPI 引脚(MOSI/MISO/CLK + CS + DC)。
输入设备方面:触摸屏通常走 I2C 或 SPI;旋转编码器使用 3 个 GPIO(A、B 相与按键)。具体 GPIO 映射请参考开发板原理图或hw_init组件配置。
工程结构与依赖关系
目录结构
examples/display/gui/lvgl_common_demo/ ├── main/ │ ├── CMakeLists.txt │ ├── idf_component.yml # 组件依赖声明 │ └── main.c # 主应用逻辑 ├── CMakeLists.txt # 项目级 CMake ├── README.md ├── partitions.csv # 自定义分区表 ├── sdkconfig.defaults # 默认配置 ├── sdkconfig.defaults.esp32c3 ├── sdkconfig.defaults.esp32p4 ├── sdkconfig.defaults.esp32s3 └── sdkconfig.defaults.esp32s31 # 各芯片专属配置组件依赖(idf_component.yml)
main/idf_component.yml 声明了关键依赖:
dependencies: idf: version: ">=5.5.0" lvgl/lvgl: version: "^9" public: true espressif/esp_lvgl_adapter: version: "*" override_path: "../../../../../components/display/tools/esp_lvgl_adapter" public: true example_lvgl_init: version: "*" override_path: "../../common/example_lvgl_init" hw_init: version: "*" override_path: "../../common/hw_init"要点解读:
- IDF 版本要求 ≥ 5.5.0;
- LVGL 采用9.x版本;
esp_lvgl_adapter通过override_path直接指向仓库内组件源码 components/display/tools/esp_lvgl_adapter,保证示例与仓库最新实现同步;example_lvgl_init与hw_init是gui/common目录下的共享参考组件,被本示例及其他 GUI 示例复用。
其中hw_init组件内部又分为lcd/(lcd_init_mipi_dsi.c、lcd_init_rgb.c、lcd_init_qspi.c、lcd_init_spi_with_psram.c、lcd_init_spi_without_psram.c)、input/(touch_init.c、knob_init.c)与helpers/(旋转辅助工具),覆盖了五类 LCD 接口与两类输入设备的初始化。
menuconfig 配置详解
运行idf.py menuconfig后,进入Example Configuration菜单即可配置示例(见 README.md)。
LCD 接口选择
LCD Interface Type:在 MIPI DSI、RGB、QSPI、SPI 之间选择。该选项定义于 common/hw_init/Kconfig.projbuild,其默认值随芯片自动切换:
| 接口选项 | 分辨率 | 输入设备 | 适用芯片 |
|---|---|---|---|
| MIPI DSI Interface | 1024x600 | Touch | 仅 ESP32-P4 |
| QSPI Interface | 360x360 | Touch | 非 ESP32-C3(需 PSRAM) |
| RGB Interface | 800x480 | Touch | ESP32-S3 / ESP32-P4 / ESP32-S31(需 PSRAM) |
| SPI Interface with PSRAM | 320x240 | Touch | 非 ESP32-C3 |
| SPI Interface without PSRAM | 240x240 | Encoder/Knob | 全部(适合资源受限芯片) |
选中接口后,分辨率与输入设备类型由hw_init.h中的宏自动确定(见 common/hw_init/hw_init.h),例如:
#if CONFIG_EXAMPLE_LCD_INTERFACE_MIPI_DSI #define HW_LCD_H_RES 1024 #define HW_LCD_V_RES 600 #define HW_USE_TOUCH 1 #define HW_USE_ENCODER 0 #elif CONFIG_EXAMPLE_LCD_INTERFACE_RGB #define HW_LCD_H_RES 800 #define HW_LCD_V_RES 480 ... #endif注意:如果未选中任何接口,编译时会在 hw_init.c 触发
#error "No LCD interface selected! Please select one in menuconfig.";若接口不支持触摸却也没启用编码器,则会报#error "No input device configured!"。
显示设置
Display Rotation:选择屏幕方向 0°/90°/180°/270°(顺时针)。该选项同样由 Kconfig.projbuild 定义,默认 0 度。旋转会同时作用于 LCD 面板与触摸控制器,使 LVGL 坐标与屏幕方向保持一致——这也是example_lvgl_init中get_configured_rotation()所读取的内容(见 example_lvgl_init.c):
static esp_lv_adapter_rotation_t get_configured_rotation(void) { #if CONFIG_EXAMPLE_DISPLAY_ROTATION_0 return ESP_LV_ADAPTER_ROTATE_0; #elif CONFIG_EXAMPLE_DISPLAY_ROTATION_90 return ESP_LV_ADAPTER_ROTATE_90; #elif CONFIG_EXAMPLE_DISPLAY_ROTATION_180 return ESP_LV_ADAPTER_ROTATE_180; #elif CONFIG_EXAMPLE_DISPLAY_ROTATION_270 return ESP_LV_ADAPTER_ROTATE_270; #else return ESP_LV_ADAPTER_ROTATE_0; #endif }LCD 分辨率与时序参数则在hw_init中配置。
输入设备
- 选择触摸或编码器输入;
- 触摸控制器需配置 I2C/SPI 参数(并核对 I2C 地址)。
性能选项
Enable FPS Statistics:开启后将在日志中周期性打印帧率(对应CONFIG_ESP_LVGL_ADAPTER_ENABLE_FPS_STATS)。
sdkconfig.defaults 中的关键调优
仓库为示例预设了一组面向性能的默认配置(见 sdkconfig.defaults):
CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_FREERTOS_HZ=1000 CONFIG_LV_USE_CLIB_MALLOC=y CONFIG_LV_USE_CLIB_STRING=y CONFIG_LV_USE_CLIB_SPRINTF=y CONFIG_LV_DEF_REFR_PERIOD=15 CONFIG_LV_DPI_DEF=60 CONFIG_LV_OS_FREERTOS=y CONFIG_LV_DRAW_LAYER_SIMPLE_BUF_SIZE=48000 CONFIG_LV_DRAW_THREAD_PRIO=4 CONFIG_LV_DRAW_SW_SHADOW_CACHE_SIZE=4 CONFIG_LV_GRADIENT_MAX_STOPS=4 CONFIG_LV_OBJ_STYLE_CACHE=y CONFIG_LV_USE_SYSMON=y CONFIG_LV_USE_PERF_MONITOR=y CONFIG_LV_USE_DEMO_BENCHMARK=y CONFIG_ESP_LVGL_ADAPTER_ENABLE_FPS_STATS=y其中值得关注的是:编译器启用性能优化、CONFIG_LV_OS_FREERTOS=y(LVGL 由 FreeRTOS 承载)、刷新周期 15ms、启用 benchmark demo 与 FPS 统计。各芯片专属的sdkconfig.defaults.esp32p4/esp32s3/esp32s31/esp32c3则按芯片能力进一步差异化配置。
编译、烧录与运行
构建命令
- 先设置目标芯片(见 README.md):
idf.py set-target esp32p4 # 或 idf.py set-target esp32s3 # 或 idf.py set-target esp32s31 # 或 idf.py set-target esp32c3- 编译、烧录并打开串口监视器:
idf.py -p PORT build flash monitor(退出串口监视器请按Ctrl-]。)
首次构建会花较长时间,因为构建系统需要从组件仓库下载组件到
managed_components目录。完整的 ESP-IDF 环境搭建步骤参考官方 Getting Started Guide(链接见 README 原文)。此外,若构建报错,可尝试idf.py fullclean后重新构建。
预期输出
烧录成功后,LCD 将显示 LVGL benchmark demo——包含多种动画与 UI 元素以压力测试渲染性能。串口控制台会打印初始化日志(README.md):
I (xxx) main: Selected LCD interface: MIPI DSI I (xxx) main: Initializing LCD: 1024x600 I (xxx) main: Starting LVGL benchmark demo若开启了 FPS 统计,将周期性看到帧率报告:
I (xxx) main: Current FPS: 45Benchmark 会自动循环切换不同测试场景,展示形状、图片、文本与动画。示例的app_main本身非常精简(main/main.c):
void app_main(void) { example_lvgl_ctx_t ctx; ESP_ERROR_CHECK(example_lvgl_init(&ctx)); ESP_LOGI(TAG, "Starting LVGL benchmark demo"); if (esp_lv_adapter_lock(-1) == ESP_OK) { lv_demo_benchmark(); esp_lv_adapter_unlock(); } }可见:初始化全部由example_lvgl_init()完成,主任务通过esp_lv_adapter_lock()获取 LVGL 互斥锁后调用lv_demo_benchmark()启动基准测试,运行完毕释放锁——这正是适配器提供的线程安全调用模式。
八步初始化流程(源码级拆解)
example_lvgl_init()的注释明确说明该文件采用"平铺、逐步"风格编写,旨在成为新项目的复制粘贴起点(见 example_lvgl_init.c)。完整序列如下(对应头文件中的步骤说明 example_lvgl_init.h):
- 读取旋转配置:从 Kconfig(
CONFIG_EXAMPLE_DISPLAY_ROTATION_*)解析出esp_lv_adapter_rotation_t存入ctx->rotation; - 选择撕裂规避模式:按接口类型确定
ctx->tear_mode:- MIPI DSI →
ESP_LV_ADAPTER_TEAR_AVOID_MODE_DEFAULT_MIPI_DSI; - RGB →
ESP_LV_ADAPTER_TEAR_AVOID_MODE_DEFAULT_RGB; - SPI/QSPI → 通过
hw_lcd_get_te_gpio()检测面板是否提供 TE 引脚:有则启用ESP_LV_ADAPTER_TEAR_AVOID_MODE_TE_SYNC并打印TE sync enabled on GPIO x,无则回退默认模式;
- MIPI DSI →
- 初始化 LCD 面板:
hw_lcd_init(&ctx->panel, &ctx->panel_io, ctx->tear_mode, ctx->rotation); - 初始化 LVGL 适配器:
esp_lv_adapter_init(&adapter_cfg),使用默认配置宏ESP_LV_ADAPTER_DEFAULT_CONFIG(); - 注册显示设备:
esp_lv_adapter_register_display(&display_cfg)。关键点在于按接口选择不同的默认配置宏(example_lvgl_init.c):- MIPI DSI →
ESP_LV_ADAPTER_DISPLAY_MIPI_DEFAULT_CONFIG(panel, panel_io, h, v, rotation) - RGB →
ESP_LV_ADAPTER_DISPLAY_RGB_DEFAULT_CONFIG(...) - SPI(无 PSRAM)→
ESP_LV_ADAPTER_DISPLAY_SPI_WITHOUT_PSRAM_DEFAULT_CONFIG(...) - QSPI / SPI(有 PSRAM)→ 有 TE 时用
..._SPI_WITH_PSRAM_TE_DEFAULT_CONFIG(..., te_gpio, bus_freq, data_lines, bits_per_pixel),无 TE 时用普通版本;
- MIPI DSI →
- 初始化输入设备:
HW_USE_TOUCH时走hw_touch_init()+esp_lv_adapter_register_touch();HW_USE_ENCODER && CONFIG_ESP_LVGL_ADAPTER_ENABLE_KNOB时用hw_knob_get_config()/hw_knob_get_button()填充编码器配置后esp_lv_adapter_register_encoder()(example_lvgl_init.c); - 启动 LVGL 工作任务:
esp_lv_adapter_start(); - (可选)启动 FPS 监控:仅当
CONFIG_ESP_LVGL_ADAPTER_ENABLE_FPS_STATS开启时,先调用esp_lv_adapter_fps_stats_enable(ctx->disp, true),再创建fps_monitor_task,每 1000ms 通过esp_lv_adapter_get_fps(disp, &fps)读取并打印帧率(example_lvgl_init.c)。
所有初始化结果统一封装进example_lvgl_ctx_t结构体(example_lvgl_init.h),包含显示句柄、触摸/编码器输入设备句柄、面板句柄、旋转与撕裂规避模式等字段;不适用的字段置 NULL。
fps_monitor_task与esp_lv_adapter_get_fps()等接口的底层实现,可进一步在 esp_lvgl_adapter 组件 中查阅(include/esp_lv_adapter.h声明、src/adapter/esp_lv_adapter.c实现),组件的 benchmark 测试例程 test_esp_lvgl_adapter_fps.c 也展示了 FPS 统计接口的典型用法。
示例展示的关键能力
根据 README.md,本示例集中演示了五方面能力:
- 统一 LCD API:同一代码库驱动多种 LCD 接口类型;
- LVGL 集成:规范的 LVGL 初始化与任务管理;
- 输入处理:触摸与编码器输入设备的注册;
- 性能监控:基于适配器特性的可选 FPS 统计;
- 线程安全:基于互斥锁(mutex)保护 LVGL API 调用。
故障排查(Troubleshooting)
以下是 README.md 给出的常见问题与排查思路:
屏幕无显示:
- 检查 LCD 供电与背光连接;
- 在 menuconfig 中核对 GPIO 引脚映射;
- 确认选择了正确的 LCD 接口类型;
- 核对面板的 LCD 初始化时序。
触摸/编码器无响应:
- 检查 I2C/GPIO 连接;
- 在 menuconfig 中启用输入设备;
- 核对触摸控制器的 I2C 地址。
构建错误:
- 确保 ESP-IDF 版本为 5.5.0 或更高;
- 执行
idf.py fullclean后重新构建; - 确认所有 managed components 均已正确下载。
技术问题可前往仓库 Issues 反馈(链接见 README 原文)。
延伸阅读
- 组件源码:components/display/tools/esp_lvgl_adapter(含中英文 README、benchmark 测试用例)
- 共享初始化参考组件:examples/display/gui/common/example_lvgl_init
- 硬件抽象组件:examples/display/gui/common/hw_init
- 同目录下其他 GUI 示例(如
lvgl_multi_screen、lvgl_light_sleep_demo、lvgl_freetype_font等)复用同一套example_lvgl_init/hw_init基础设施,可作为下一步改造与扩展的参考。
若你正在评估某款屏幕的渲染性能,或准备基于esp_lvgl_adapter从零搭建自己的 GUI 工程,lvgl_common_demo是理想的起点:先跑通 Benchmark,再以example_lvgl_init.c为模板逐步替换成自己的应用逻辑即可。
【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考