English | 中文
esp_lvgl_adapter 为 ESP-IDF 工程提供统一的 LVGL 适配层,涵盖显示注册、防撕裂策略、LVGL 线程安全访问,以及文件系统/图片解码/FreeType 字体的可选集成。兼容 LVGL v8 与 v9。
- 统一的显示注册接口:支持 MIPI DSI / RGB / QSPI / SPI / I2C / I80 等多种显示接口
- 防撕裂策略:提供多种防撕裂模式
- 线程安全:提供
lock/unlockAPI,保证多线程环境下的安全访问 - 可选模块 (通过 Kconfig 开关控制):
- 文件系统桥接 (
esp_lv_fs) - 图片解码 (
esp_lv_decoder) - FreeType 矢量字体
- FPS 统计、Dummy Draw(不实际输出到显示器)
- 文件系统桥接 (
- 多屏支持:可同时管理多个显示设备
idf.py add-dependency "espressif/esp_lvgl_adapter"dependencies:
espressif/esp_lvgl_adapter: "*"- ESP-IDF:>= 5.5
- LVGL:8.x 或 9.x(自动适配版本)
- 可选依赖:根据启用的功能需要满足相应的组件依赖
idf.py set-target esp32s3 # 设置目标芯片(或 esp32、esp32c3、esp32p4 等)
idf.py build # 构建工程
idf.py flash monitor # 烧录并查看日志以下是一个最小化的使用示例,展示如何初始化适配器并注册显示设备:
#include "esp_lv_adapter.h" // 包含显示与输入适配接口
void app_main(void)
{
// 步骤 0: 使用 esp_lcd API 创建面板和面板 IO(此处省略具体实现)
esp_lcd_panel_handle_t panel = /* ... */;
esp_lcd_panel_io_handle_t panel_io = /* ... 或 NULL */;
// 步骤 1: 初始化适配器
esp_lv_adapter_config_t cfg = ESP_LV_ADAPTER_DEFAULT_CONFIG();
ESP_ERROR_CHECK(esp_lv_adapter_init(&cfg));
// 步骤 2: 注册显示设备(根据接口类型选择相应的默认配置宏)
esp_lv_adapter_display_config_t disp_cfg = ESP_LV_ADAPTER_DISPLAY_RGB_DEFAULT_CONFIG(
panel, // LCD 面板句柄
panel_io, // LCD 面板 IO 句柄(某些接口可为 NULL)
800, // 水平分辨率
480, // 垂直分辨率
ESP_LV_ADAPTER_ROTATE_0 // 旋转角度
);
lv_display_t *disp = esp_lv_adapter_register_display(&disp_cfg);
assert(disp != NULL);
// 步骤 3: (可选) 注册输入设备
// 使用 esp_lcd_touch API 创建触摸句柄(此处省略具体实现)
// esp_lcd_touch_handle_t touch_handle = /* ... */;
// esp_lv_adapter_touch_config_t touch_cfg = ESP_LV_ADAPTER_TOUCH_DEFAULT_CONFIG(disp, touch_handle);
// lv_indev_t *touch = esp_lv_adapter_register_touch(&touch_cfg);
// assert(touch != NULL);
// 步骤 4: 启动适配器任务
ESP_ERROR_CHECK(esp_lv_adapter_start());
// 步骤 5: 使用 LVGL API 绘制界面(需要先加锁)
if (esp_lv_adapter_lock(-1) == ESP_OK) {
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Hello LVGL!");
lv_obj_center(label);
esp_lv_adapter_unlock();
}
}本节将指导您在 ESP-IDF 项目中集成 LVGL 适配器。
在项目的 sdkconfig.defaults 中添加以下配置以获得最佳 LVGL 性能:
# FreeRTOS 时钟频率(提高定时器精度)
CONFIG_FREERTOS_HZ=1000
# LVGL 操作系统集成
CONFIG_LV_OS_FREERTOS=y
# 使用标准 C 库函数
CONFIG_LV_USE_CLIB_MALLOC=y
CONFIG_LV_USE_CLIB_STRING=y
CONFIG_LV_USE_CLIB_SPRINTF=y
# 显示刷新率(单位:毫秒,15ms ≈ 66 FPS)
CONFIG_LV_DEF_REFR_PERIOD=15
# 启用样式缓存以提高性能
CONFIG_LV_OBJ_STYLE_CACHE=y对于多核芯片,启用并行渲染:
# 使用 2 个绘制线程以提高性能
CONFIG_LV_DRAW_SW_DRAW_UNIT_CNT=2对于带有 PSRAM 的设备,优化缓存和 XIP 设置:
ESP32-S3:
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y
CONFIG_ESP32S3_DATA_CACHE_64KB=y
CONFIG_ESP32S3_DATA_CACHE_LINE_64B=yESP32-P4:
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
CONFIG_CACHE_L2_CACHE_256KB=y
CONFIG_CACHE_L2_CACHE_LINE_128B=y# 启用编译器优化
CONFIG_COMPILER_OPTIMIZATION_PERF=y注意:这些是推荐的基准配置。请根据您的具体需求和可用资源进行调整。
在开始使用前,请按以下流程做出决策:
- 选择接口类型:确定使用的显示接口(MIPI DSI / RGB / QSPI / SPI / I2C / I80)
- 选择默认配置宏:根据接口类型选择对应的
ESP_LV_ADAPTER_DISPLAY_XXX_DEFAULT_CONFIG宏 - 选择合适的防撕裂模式(仅 RGB/MIPI DSI 接口支持):
- 计算所需的帧缓冲数量 (
num_fbs) - 将
num_fbs传入 esp_lcd 面板配置
- 计算所需的帧缓冲数量 (
- 调节缓冲大小:根据内存与吞吐需求调整
buffer_height
根据您的显示接口选择对应的配置宏:
| 接口类型 | 默认配置宏 | 默认防撕裂模式 |
|---|---|---|
| MIPI DSI | ESP_LV_ADAPTER_DISPLAY_MIPI_DEFAULT_CONFIG(...) |
ESP_LV_ADAPTER_TEAR_AVOID_MODE_DEFAULT_MIPI_DSI |
| RGB | ESP_LV_ADAPTER_DISPLAY_RGB_DEFAULT_CONFIG(...) |
ESP_LV_ADAPTER_TEAR_AVOID_MODE_DEFAULT_RGB |
| SPI/I2C/I80/QSPI (带 PSRAM) | ESP_LV_ADAPTER_DISPLAY_SPI_WITH_PSRAM_DEFAULT_CONFIG(...) |
ESP_LV_ADAPTER_TEAR_AVOID_MODE_DEFAULT (即 NONE) |
| SPI/I2C/I80/QSPI (无 PSRAM) | ESP_LV_ADAPTER_DISPLAY_SPI_WITHOUT_PSRAM_DEFAULT_CONFIG(...) |
ESP_LV_ADAPTER_TEAR_AVOID_MODE_DEFAULT (即 NONE) |
| MONO (单色显示) | ESP_LV_ADAPTER_DISPLAY_SPI_MONO_DEFAULT_CONFIG(...) |
ESP_LV_ADAPTER_TEAR_AVOID_MODE_DEFAULT (即 NONE) |
注意:
- 仅 MIPI DSI 和 RGB 支持防撕裂模式
- SPI/I2C/I80/QSPI 等接口在适配器中统称为 "OTHER" 接口,仅支持
NONE模式 - MONO(单色显示)接口支持 I1 水平平铺 (HTILED) 和垂直平铺 (VTILED) 两种布局,且支持旋转
在 RGB/MIPI DSI 初始化前,需要计算所需的帧缓冲数量:
uint8_t num_fbs = esp_lv_adapter_get_required_frame_buffer_count(
ESP_LV_ADAPTER_TEAR_AVOID_MODE_DEFAULT_RGB, // 防撕裂模式
ESP_LV_ADAPTER_ROTATE_0 // 旋转角度
);
// 将 num_fbs 传入 esp_lcd 面板配置帧缓冲数量规则:
- 90°/270° 旋转 或 三缓冲模式:需要 3 个帧缓冲
- 双缓冲模式:需要 2 个帧缓冲
- 单缓冲模式:需要 1 个帧缓冲
根据您的应用场景选择合适的防撕裂模式:
| 防撕裂模式 | 适用场景 | 帧缓冲数 | 内存占用 | 支持接口 |
|---|---|---|---|---|
TRIPLE_PARTIAL |
旋转(90°/270°) 高分辨率流畅 UI |
3 | 高 | RGB / MIPI DSI |
TRIPLE_FULL |
整屏/大区域刷新 内存充足 |
3 | 高 | RGB / MIPI DSI |
DOUBLE_FULL |
大区域刷新 内存较紧 |
2 | 中 | RGB / MIPI DSI |
DOUBLE_DIRECT |
小区域更新 控件/局部变化 |
2 | 中 | RGB / MIPI DSI |
TE_SYNC |
SPI/I2C/I80/QSPI 接口 面板提供 TE 信号,通过垂直消隐同步消除撕裂 |
1 | 低 | SPI / I2C / I80 / QSPI |
NONE |
静态 UI 超低内存 |
1 | 低 | 所有接口 |
重要限制:
- RGB/MIPI DSI 在
TEAR_AVOID_MODE_NONE下不支持旋转(任何非 0 旋转会被拒绝) - OTHER (SPI/I2C/I80/QSPI) 接口支持
NONE和TE_SYNC模式;如需旋转,请在 LCD 初始化阶段配置面板方向(交换 XY/镜像),并相应调整触摸坐标映射 - MONO (单色显示) 接口支持软件旋转(0°/90°/180°/270°),通过 LVGL 进行像素级旋转处理
TE_SYNC模式要求面板提供 TE 输出信号,并将 TE 引脚连接到 ESP GPIO;使用ESP_LV_ADAPTER_DISPLAY_SPI_WITH_PSRAM_TE_DEFAULT_CONFIG宏进行配置。examples/display/gui/lvgl_common_demo会自动检测并在可用时使用 TE 同步
整帧显存大小 ≈ 水平分辨率 × 垂直分辨率 × 每像素字节数
示例(RGB565 格式,2 字节/像素):
- 800×480 分辨率:≈ 750 KB
- 三缓冲:≈ 2.2 MB
- 结论:通常需要 PSRAM 支持
不同接口的 buffer_height 默认值(详见 esp_lv_adapter_display.h):
| 接口类型 | 默认 buffer_height |
说明 |
|---|---|---|
| MIPI DSI | 50 | 中等条带高度 |
| RGB | 50 | 中等条带高度 |
| OTHER + PSRAM | ver_res (整屏高度) |
整屏高度分区,吞吐更高 |
| OTHER 无 PSRAM | 10 | 小条带以节省 RAM |
-
提高
buffer_height:- ✅ 提升吞吐量(减少 flush 次数、增大条带)
- ❌ 增加 RAM 占用
-
降低
buffer_height:- ✅ 节省 RAM
- ❌ 增加 flush 次数,可能降低性能
在 RGB/MIPI DSI 初始化阶段,需要提前计算并传入面板帧缓冲数量:
// 1. 选择防撕裂模式和旋转角度
esp_lv_adapter_tear_avoid_mode_t tear_avoid_mode = ESP_LV_ADAPTER_TEAR_AVOID_MODE_DEFAULT_MIPI_DSI;
esp_lv_adapter_rotation_t rotation = ESP_LV_ADAPTER_ROTATE_0;
// 2. 计算所需帧缓冲数量
uint8_t num_fbs = esp_lv_adapter_get_required_frame_buffer_count(tear_avoid_mode, rotation);
// 3. 将 num_fbs 传入 esp_lcd 面板配置
#if SOC_MIPI_DSI_SUPPORTED
esp_lcd_dpi_panel_config_t dpi_cfg = {
.num_fbs = num_fbs,
// ... 其他 MIPI DSI DPI 配置
};
#endif
#if SOC_LCDCAM_RGB_LCD_SUPPORTED
esp_lcd_rgb_panel_config_t rgb_cfg = {
.num_fbs = num_fbs,
// ... 其他 RGB 配置
};
#endif具体实现请参考示例工程和测试应用中的配置。
适配器的 LVGL 任务栈默认为 8KB,支持将其放入 PSRAM:
esp_lv_adapter_config_t cfg = ESP_LV_ADAPTER_DEFAULT_CONFIG();
cfg.stack_in_psram = true; // 尝试将任务栈放入 PSRAM
ESP_ERROR_CHECK(esp_lv_adapter_init(&cfg));说明:
- 默认栈大小:8KB(适合大多数应用)
- 若 PSRAM 不可用会自动回退到片内 RAM
- PSRAM 时延略高于片内 RAM,但对 UI 任务影响小
LVGL API 不是线程安全的,多线程访问时必须使用适配器锁:
if (esp_lv_adapter_lock(-1) == ESP_OK) {
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 50);
esp_lv_adapter_unlock();
}适配器提供了触摸设备注册的默认配置宏 ESP_LV_ADAPTER_TOUCH_DEFAULT_CONFIG,简化配置过程:
// 使用默认配置宏注册触摸设备
esp_lv_adapter_touch_config_t touch_cfg = ESP_LV_ADAPTER_TOUCH_DEFAULT_CONFIG(disp, touch_handle);
lv_indev_t *touch = esp_lv_adapter_register_touch(&touch_cfg);
assert(touch != NULL);参数说明:
disp:关联的 LVGL 显示设备touch_handle:通过esp_lcd_touchAPI 创建的触摸句柄- 默认缩放比例:x = 1.0, y = 1.0
需要启用 Kconfig 选项 ESP_LV_ADAPTER_ENABLE_KNOB。详见 esp_lv_adapter_input.h。
需要启用 Kconfig 选项 ESP_LV_ADAPTER_ENABLE_BUTTON。详见 esp_lv_adapter_input.h。
启用 ESP_LV_ADAPTER_ENABLE_FS 后,可将 esp_mmap_assets 生成的资源分区挂载为 LVGL 文件系统:
#include "esp_lv_fs.h"
#include "esp_mmap_assets.h"
// 1. 创建 mmap 资源句柄
mmap_assets_handle_t assets;
const mmap_assets_config_t mmap_cfg = {
.partition_label = "assets_A",
.max_files = MMAP_DRIVE_A_FILES,
.checksum = MMAP_DRIVE_A_CHECKSUM,
.flags = { .mmap_enable = true },
};
ESP_ERROR_CHECK(mmap_assets_new(&mmap_cfg, &assets));
// 2. 挂载为 LVGL 文件系统
esp_lv_fs_handle_t fs_handle;
const fs_cfg_t fs_cfg = {
.fs_letter = 'A', // 盘符(A 到 Z)
.fs_assets = assets,
.fs_nums = MMAP_DRIVE_A_FILES,
};
ESP_ERROR_CHECK(esp_lv_adapter_fs_mount(&fs_cfg, &fs_handle));
// 3. 在 LVGL 中使用文件路径,如 "A:image.png"
lv_obj_t *img = lv_img_create(lv_scr_act());
lv_img_set_src(img, "A:my_image.png");启用 ESP_LV_ADAPTER_ENABLE_DECODER 后,适配器会集成 esp_lv_decoder,支持直接使用 LVGL 图片控件加载各种格式的图片:
// 使用 LVGL 图片控件加载图片
lv_obj_t *img = lv_img_create(lv_scr_act());
lv_img_set_src(img, "I:red_png.png"); // I: 为图片解码器的盘符支持的格式:
- 标准格式:JPG、PNG、QOI
- 分片格式:SJPG、SPNG、SQOI(针对嵌入式优化)
- 硬件加速:JPEG、PJPG(如果芯片支持)
详细说明:请参考 components/display/tools/esp_lv_decoder/README.md
启用 ESP_LV_ADAPTER_ENABLE_FREETYPE 并在 LVGL 中开启 FreeType 后,可以从文件或内存加载矢量字体:
#include "esp_lv_adapter.h"
// 从文件加载字体
esp_lv_adapter_ft_font_handle_t fh;
esp_lv_adapter_ft_font_config_t cfg = {
.name = "F:my_font.ttf", // 字体文件路径(注意:mmap 资源格式,冒号后不带斜杠)
.size = 30, // 字号
.style = ESP_LV_ADAPTER_FT_FONT_STYLE_NORMAL,
};
ESP_ERROR_CHECK(esp_lv_adapter_ft_font_init(&cfg, &fh));
const lv_font_t *font30 = esp_lv_adapter_ft_font_get(fh);
// 使用字体
lv_obj_set_style_text_font(label, font30, 0);堆栈配置:
| LVGL 版本 | 必要配置 | 说明 |
|---|---|---|
| v8 | CONFIG_ESP_MAIN_TASK_STACK_SIZE=32768 |
字体初始化在调用线程执行 |
| v9 | CONFIG_LV_DRAW_THREAD_STACK_SIZE=32768 |
字体渲染在绘图线程执行 |
限制:
- LVGL v8:不支持 LVGL 虚拟文件系统(
lv_fs),需使用直接文件路径或内存缓冲区 - LVGL v9:支持虚拟文件系统路径(如
"F:font.ttf")
需要启用 ESP_LV_ADAPTER_ENABLE_FPS_STATS。
// 启用 FPS 统计
ESP_ERROR_CHECK(esp_lv_adapter_fps_stats_enable(disp, true));
// 获取当前 FPS
uint32_t fps;
if (esp_lv_adapter_get_fps(disp, &fps) == ESP_OK) {
printf("Current FPS: %lu\n", fps);
}Dummy Draw 模式绕过 LVGL 渲染,直接控制显示:
ESP_ERROR_CHECK(esp_lv_adapter_set_dummy_draw(disp, true));
ESP_ERROR_CHECK(esp_lv_adapter_dummy_draw_blit(disp, 0, 0, 800, 480, framebuffer, true));
ESP_ERROR_CHECK(esp_lv_adapter_set_dummy_draw(disp, false));完整示例请参考 examples/display/gui/lvgl_dummy_draw。
强制进行同步刷新:
esp_lv_adapter_refresh_now(disp);某些显示面板要求绘制区域的宽度和高度必须是特定值的倍数(例如 8 的倍数)。适配器提供了区域对齐回调功能,可以在刷新到硬件之前对绘制区域进行舍入对齐。
使用场景:
- 面板硬件要求绘制区域必须对齐到特定边界(如 8 像素对齐)
- 某些 DMA 传输需要对齐的缓冲区大小
- 优化硬件传输效率
示例代码:
// 定义对齐回调函数(将区域对齐到 8 的倍数)
void area_rounder_cb(lv_area_t *area, void *user_data)
{
// 获取对齐值(例如 8)
uint32_t align = *(uint32_t *)user_data;
// 向下对齐 x1 和 y1
area->x1 = (area->x1 / align) * align;
area->y1 = (area->y1 / align) * align;
// 向上对齐 x2 和 y2
area->x2 = ((area->x2 + align - 1) / align) * align;
area->y2 = ((area->y2 + align - 1) / align) * align;
}
// 注册对齐回调
uint32_t align_value = 8; // 对齐到 8 像素
ESP_ERROR_CHECK(esp_lv_adapter_set_area_rounder_cb(disp, area_rounder_cb, &align_value));
// 禁用对齐回调(传入 NULL)
ESP_ERROR_CHECK(esp_lv_adapter_set_area_rounder_cb(disp, NULL, NULL));注意事项:
- 回调函数会在每次刷新区域之前被调用
- 回调函数应该修改传入的
lv_area_t结构体以调整区域边界 - 传入
NULL作为回调函数可以禁用区域对齐功能 user_data参数可以用于传递对齐值或其他配置信息
在保持 UI 状态的同时安全地关闭显示以降低功耗。适配器提供了与 ESP-IDF Light Sleep 配合使用的睡眠机制。
基本流程:
// 进入睡眠
esp_lv_adapter_sleep_prepare(); // 暂停 worker,等待刷新完成
esp_lcd_panel_del(panel); // 删除硬件
esp_light_sleep_start(); // 进入 Light Sleep(CPU 暂停,外设保持状态)
// 从睡眠恢复(Light Sleep 唤醒后自动执行)
panel = /* 重新初始化 LCD 硬件 */;
esp_lv_adapter_sleep_recover(disp, panel, panel_io); // 重新绑定面板,恢复 worker配合 Light Sleep 使用:
- 进入睡眠前:调用
esp_lv_adapter_sleep_prepare()暂停适配器任务并等待当前刷新完成 - 删除硬件:调用
esp_lcd_panel_del()释放显示硬件资源 - 进入 Light Sleep:调用
esp_light_sleep_start(),系统将暂停 CPU 并保持外设状态 - 唤醒后恢复:重新初始化 LCD 硬件,然后调用
esp_lv_adapter_sleep_recover()恢复适配器运行
主要特性:
- UI 状态保留(无需重建控件)
- 触摸设备保持注册(需要时单独关闭电源)
- 多屏幕:为每个显示调用
sleep_recover() - 与 Light Sleep 无缝配合,实现低功耗待机
esp_lv_adapter_pause()/resume() 实现自定义流程,但请勿与 sleep_prepare() 混用
通过 idf.py menuconfig 可以配置以下选项:
| 配置项 | 说明 |
|---|---|
ESP_LV_ADAPTER_ENABLE_FS |
启用文件系统桥接 (esp_lv_fs) |
ESP_LV_ADAPTER_ENABLE_DECODER |
启用图片解码 (esp_lv_decoder) |
ESP_LV_ADAPTER_ENABLE_FREETYPE |
启用 FreeType 矢量字体支持 |
ESP_LV_ADAPTER_ENABLE_FPS_STATS |
启用 FPS 统计功能 |
ESP_LV_ADAPTER_ENABLE_BUTTON |
启用按键导航输入 |
ESP_LV_ADAPTER_ENABLE_KNOB |
启用旋钮/编码器输入 |
默认任务栈大小:
- LVGL 适配器任务栈:8KB
| 接口类型 | 支持的防撕裂模式 |
|---|---|
| RGB / MIPI DSI | NONE, DOUBLE_FULL, TRIPLE_FULL, DOUBLE_DIRECT, TRIPLE_PARTIAL |
| OTHER (SPI/I2C/I80/QSPI) | NONE、TE_SYNC |
-
RGB/MIPI DSI:
- 在
TEAR_AVOID_MODE_NONE下不支持旋转(任何非 0 旋转会被拒绝)
- 在
-
OTHER (SPI/I2C/I80/QSPI):
- 适配器不对 90°/270° 进行旋转处理
- 如需旋转,请在 LCD 初始化阶段配置面板方向(交换 XY/镜像)
- 同时需要相应调整触摸坐标映射
-
MONO (单色显示):
- 完全支持旋转(0°/90°/180°/270°)
- 旋转由 LVGL 在软件层面处理
- 支持 I1 水平平铺 (HTILED) 和垂直平铺 (VTILED) 两种布局
- 无需额外配置,直接通过
rotation参数设置
-
模式映射:
DOUBLE_FULL/TRIPLE_FULL→ FULL 渲染模式DOUBLE_DIRECT→ DIRECT 渲染模式- 其余(含
TRIPLE_PARTIAL)→ PARTIAL 渲染模式
-
LVGL 绘制缓冲数量:
TRIPLE_PARTIAL:1 块TRIPLE_FULL/DOUBLE_*:2 块- FULL/DIRECT 模式默认:2 块
- 其他:1 块
-
OTHER + NONE:
- 不申请面板帧缓冲
- 仅使用 LVGL 绘制缓冲的条带方式发送数据
- 启用 PPA 加速时,建议设置
LV_DRAW_SW_DRAW_UNIT_CNT == 1 - 旋转操作优先使用 PPA;否则使用 CPU 拷贝路径(带缓存局部性的块拷贝)
- 效果与预期:
- PPA 可显著降低 CPU 占用
- 通常不会带来明显的 FPS 提升
关闭 UI 时的推荐资源释放顺序:
// 1. 注销输入设备
esp_lv_adapter_unregister_touch(touch);
// esp_lv_adapter_unregister_encoder(encoder);
// esp_lv_adapter_unregister_navigation_buttons(buttons);
// 2. 注销显示设备
esp_lv_adapter_unregister_display(disp);
// 3. 卸载文件系统(如果使用)
esp_lv_adapter_fs_unmount(fs_handle);
// 释放 mmap 资源
mmap_assets_del(assets);
// 4. 反初始化适配器
// 注意:如果启用了 FreeType,字体资源会自动清理
esp_lv_adapter_deinit();- ESP-IDF:>= 5.5
- LVGL:>= 8, < 10(支持 v8 和 v9)
如果您在 ESP32-P4 上使用 ESP_LV_ADAPTER_TEAR_AVOID_MODE_TRIPLE_PARTIAL 模式并启用屏幕旋转时遇到画面卡死问题,需要应用以下补丁:
适用版本:ESP-IDF release/v5.5 (commit 62beeae461bd3692c2028f96a93c84f11291e155)
补丁文件:0001-bugfix-lcd-Fixed-PPA-freeze.patch
应用方法:
在 ESP-IDF 仓库根目录下执行:
cd $IDF_PATH
git apply /path/to/esp_lvgl_adapter/0001-bugfix-lcd-Fixed-PPA-freeze.patch问题说明:
- 该补丁修复了 ESP32-P4 在
ESP_LV_ADAPTER_TEAR_AVOID_MODE_TRIPLE_PARTIAL模式下使能旋转时,PPA 硬件加速导致画面卡死的问题 - 仅影响同时满足以下条件的场景:
- 使用 ESP32-P4 芯片
- 使用
TRIPLE_PARTIAL防撕裂模式 - 启用了屏幕旋转(90°/270°)
- 其他配置组合或芯片不需要此补丁
验证补丁是否已应用:
检查 components/esp_driver_ppa/src/ppa_srm.c 文件中是否包含以下代码:
PPA.sr_byte_order.sr_macro_bk_ro_bypass = 1;| 示例 | 路径 | 说明 |
|---|---|---|
| 通用演示 | examples/display/gui/lvgl_common_demo |
统一的 LVGL 演示,支持多种接口 |
| 多屏示例 | examples/display/gui/lvgl_multi_screen |
多显示器管理示例 |
| 解码演示 | examples/display/gui/lvgl_decode_image |
图片解码功能演示 |
| 字体演示 | examples/display/gui/lvgl_freetype_font |
FreeType 字体加载与使用 |
| Dummy Draw | examples/display/gui/lvgl_dummy_draw |
Dummy Draw 切换 |
解决方法:
- 确认 LVGL 配置中已启用 FreeType(
CONFIG_LV_USE_FREETYPE=y) - LVGL v8:设置
CONFIG_ESP_MAIN_TASK_STACK_SIZE=32768 - LVGL v9:设置
CONFIG_LV_DRAW_THREAD_STACK_SIZE=32768
可能原因:
- 防撕裂模式选择不当
- 帧缓冲数量不正确
- 旋转配置不当
解决方法:
- 根据应用场景选择合适的防撕裂模式
- 使用
esp_lv_adapter_get_required_frame_buffer_count()计算正确的帧缓冲数
可能原因:
- Kconfig 选项未启用
- 组件依赖缺失
- 资源分区未正确烧录
解决方法:
- 检查相应的 Kconfig 开关
- 确认
esp_mmap_assets等依赖组件已添加 - 验证资源分区是否正确打包并烧录到 Flash
可能原因:
- 在多线程环境中未加锁访问 LVGL API
解决方法:
// 所有 LVGL API 调用都必须加锁保护
if (esp_lv_adapter_lock(-1) == ESP_OK) {
// LVGL API 调用
esp_lv_adapter_unlock();
}| 术语 | 说明 |
|---|---|
| 面板帧缓冲 | 由显示面板驱动持有的硬件帧缓冲区 |
| LVGL 绘制缓冲 | LVGL 用于渲染条带或整帧后再刷新到面板的 RAM 区域 |
| 分区刷新 | 仅更新屏幕的部分区域(脏区域)而非整屏刷新 |
| 直写(Direct) | LVGL 直接渲染到面板帧缓冲,减少内存拷贝;适合小区域刷新 |
| PPA | Pixel Processing Accelerator(像素处理加速器),用于硬件加速旋转/缩放/内存拷贝等操作 |
| 防撕裂 | 通过多缓冲等技术避免屏幕更新时出现撕裂现象 |
Apache-2.0
相关链接: