Skip to content

ESP32-S3-RLCD LVGL v9 示例拆解

09_LVGL_V9_Test 演示同一块 ESP32-S3-RLCD 屏幕在 LVGL v9 下的移植方式。业务现象仍是两张图片轮播,重点是理解 v9 的显示注册 API 与 v8 的差异。

LVGL v9 仍然遵循同一个大原则:

LVGL 管 UI 和绘制
项目代码管屏幕硬件刷新
flush callback 是两者之间的桥

变化主要在 API 命名和 display 对象模型。v8 常见写法是 lv_disp_drv_tlv_disp_draw_buf_tlv_disp_drv_register();v9 更强调 lv_display_t

LVGL v8:
lv_disp_draw_buf_init()
lv_disp_drv_init()
lv_disp_drv_register()
LVGL v9:
lv_display_create()
lv_display_set_flush_cb()
lv_display_set_buffers()

因此这篇更适合和 LVGL v8 示例 对照阅读。

源码阅读入口:

02_ESP-IDF/09_LVGL_V9_Test/main/main.cpp
02_ESP-IDF/09_LVGL_V9_Test/components/app_bsp/lvgl_bsp.cpp
02_ESP-IDF/09_LVGL_V9_Test/components/port_bsp/display_bsp.cpp
02_ESP-IDF/09_LVGL_V9_Test/components/user_app/user_app.cpp
02_ESP-IDF/09_LVGL_V9_Test/components/ui_bsp/generated/

关键配置和 v8 基本一致:

项目配置
屏幕对象DisplayPort RlcdPort(12, 11, 5, 40, 41, 400, 300)
MOSIGPIO12
SCKGPIO11
DCGPIO5
CSGPIO40
RSTGPIO41
分辨率400 x 300
SPI hostSPI3_HOST
SPI clock10 MHz
LVGL 版本^9.4.0
LVGL buffer全屏双缓冲,PSRAM
app_main()
-> UserApp_AppInit()
-> RlcdPort.RLCD_Init()
-> Lvgl_PortInit(400, 300, Lvgl_FlushCallback)
-> lv_init()
-> 分配 display buffer
-> lv_display_create(width, height)
-> lv_display_set_flush_cb()
-> lv_display_set_buffers()
-> 启动 tick timer
-> 创建 LVGL task
-> Lvgl_lock(-1)
-> UserApp_UiInit()
-> setup_ui()
-> Lvgl_unlock()
-> UserApp_TaskInit()
-> Lvgl_LoopTask()

刷新链路:

LVGL v9 display 触发刷新
-> Lvgl_FlushCallback(lv_display_t *, area, color_map)
-> RGB565 阈值转黑白
-> RlcdPort.RLCD_SetPixel()
-> RlcdPort.RLCD_Display()
-> lv_display_flush_ready()
函数/方法所在文件作用初学者需要理解的点
app_main()main/main.cpp串起屏幕、LVGL、UI、任务。与 v8 主流程几乎一致。
Lvgl_PortInit()components/app_bsp/lvgl_bsp.cpp初始化 LVGL v9 display。v9 的重点在 display API。
lv_display_create()LVGL v9 API创建显示对象。v9 不再沿用 v8 的 lv_disp_drv_register() 主写法。
lv_display_set_flush_cb()LVGL v9 API注册刷新回调。callback 仍然是硬件适配核心。
lv_display_set_buffers()LVGL v9 API设置显示缓冲。buffer 模式会影响内存和刷新性能。
Lvgl_FlushCallback()main/main.cpp把 LVGL 像素写到 RLCD。仍然要做 RGB565 到黑白转换。
lv_display_flush_ready()LVGL v9 API通知 LVGL 刷新完成。v9 名称不同,作用类似 v8。
setup_ui()components/ui_bsp/generated/创建生成 UI。UI 生成代码和显示驱动应分开看。
Lvgl_LoopTask()components/user_app/user_app.cpp两张图片轮播。demo 业务不等于 LVGL porting。

v9 的显示对象创建更直接:

lv_display_create(width, height)
lv_display_set_flush_cb(display, callback)
lv_display_set_buffers(display, buf1, buf2, size, mode)

这比 v8 的 lv_disp_drv_t 结构体写法更集中。初学迁移时要特别注意:网上很多老教程基于 LVGL v8,复制到 v9 工程会遇到 API 名称不匹配。

flush callback 的业务没有变。它仍然负责:

遍历 LVGL 给出的 area
-> 读取 color_map
-> 阈值转黑/白
-> 写入 RLCD 缓冲
-> 整屏刷新
-> 通知 LVGL 完成

所以 v9 学习重点不是“UI 轮播”,而是“同一块硬件屏幕在 v9 API 下怎么接入”。

运行后,屏幕和 v8 demo 类似,显示两张图片并周期切换。若 v8 正常而 v9 不正常,优先检查 LVGL v9 的 display 初始化和 flush ready API 是否使用正确。

现象可能原因排查方式
复制 v8 代码编译失败LVGL v9 API 名称和对象模型变化。使用 lv_display_* API。
屏幕不刷新flush callback 未注册或未调用 ready。检查 lv_display_set_flush_cb()lv_display_flush_ready()
UI 对象创建正常但无显示LVGL 层和屏幕层未打通。在 flush callback 加日志确认是否进入。
黑白效果不理想阈值转换简单。优化图片资源或阈值策略。
刷新卡顿全屏刷新和 PSRAM buffer 成本较高。减少动画,降低刷新频率。

如果项目从 LVGL v8 升级到 v9,建议先只替换 LvglPort

保持 DisplayPort 不变
保持 AppUI 业务尽量不变
只改 LVGL 初始化、display 注册、flush ready API

这样能降低迁移风险。底层屏幕硬件驱动和上层 UI 业务如果边界清晰,LVGL 版本升级就不会牵动整个应用。