帧率¶
1. 介绍¶
1.1 帧率定义¶
帧率指单位时间内屏幕显示的帧数,思澈方案采用2 秒内平均帧数作为统计标准,直接反映 UI 交互的流畅度(通常 60Hz 为理想流畅标准,对应每帧渲染耗时≤16.7ms)。
1.2 核心影响因素¶
帧率表现由两大环节共同决定,任一环节耗时过长均会导致卡顿:
页面渲染耗时:LVGL 图形库处理控件布局、图像绘制、数据计算的时间;
LCD 送数时间:CPU/GPU 将渲染完成的帧数据传输至 LCD 显示屏的时间。
2. 刷新周期协同机制¶
LVGL 刷新周期与 LCD TE 周期的协同是保证帧率稳定的基础,二者需合理配置以避免画面撕裂或资源浪费。
2.1 LVGL 刷新周期¶
配置方式:在config中设置,例如目标帧率 60Hz 时,配置周期为 16ms(1000ms/60≈16.7ms);

作用:决定图形库多久触发一次渲染任务,是 UI 更新的 “调度时钟”。
2.2 LCD TE 周期¶
TE 信号定义:LCD 完成一帧显示后发出的同步脉冲,标志着下一帧可开始传输数据,是避免画面撕裂的核心信号;
协同原则:
优先配置:LVGL 刷新周期与 TE 周期保持一致(如均为 16ms),确保渲染与显示节奏匹配;
兼容配置:若需统一驱动适配,可设置 LVGL 刷新周期小于 TE 周期(如 10ms),避免因渲染延迟错过 TE 同步点。
3. 帧率关键影响因素解析¶
3.1 控件与渲染效率¶
控件开销:依赖软件处理的控件(arc、label、chart)会显著增加渲染耗时,尤其 chart 包含大量小尺寸子控件时,递归遍历成本极高;
控件数量:LVGL 采用递归方式处理控件树,控件总数过多(如单页>50 个复杂控件)会导致递归耗时占比超 30%。
3.2 图像资源负载¶
图片体积过大:高分辨率、带透明度的图片会占用更多 GPU 算力;
旋转图片低效:针对图片旋转操作效率低下的问题,在 SRAM 资源充足的场景下,可配置专属的 SRAM 缓存区域(建议分配大小不小于60KB)用于旋转分块处理。渲染阶段检测到图片旋转指令时,会依据该专属 SRAM 的大小,将整张图片按行切分为若干数据块,逐块完成旋转计算与渲染输出,而非对整张图片一次性进行旋转处理,以此大幅提升图片旋转的渲染效率。

3.3 线程与数据操作¶
Flash 读写阻塞:UI 线程直接操作 Flash 会导致渲染任务被中断(单次读写耗时可达毫秒级);
4. 帧率优化实战方案¶
4.1 硬件加速与渲染优化¶
启用硬件加速:升级至Solution最新版本(≥ V2.3),arc、label 控件支持硬件加速后,渲染效率提升约 50%;
快照替换高耗控件:将复杂控件(如多子控件组合、动态图表)初始化后转为快照(snapshot),后续渲染直接使用图片,减少递归与计算开销。
4.2 页面与资源拆分¶
长页面动态加载: 使用
lvsf_multlist控件实现分页加载,仅渲染当前可视区域内容,避免一次性处理海量控件。参考示例:mainmenu_list.c、setting_main_gui.c;控件驻留机制优化: 使用
lvsf_multlist控件时,启用LV_MULTLIST_FLAG_RESIDENCY标志位,使已创建的页面控件在划出屏幕可视区域后仍保持驻留状态,而非直接销毁。此举可避免页面回滚至该位置时重复执行控件创建与销毁操作,有效节省控件生命周期管理的时间开销。
4.3 控件布局刷新¶
LVGL V8 及后续版本中,控件创建时直接获取的宽高(lv_obj_get_width/height)和位置(lv_obj_get_x/y)信息为无效值,需调用布局刷新接口后才能获取真实数据。原生接口lv_obj_update_layout会刷新当前屏幕(screen)下所有控件的尺寸与位置,全量刷新耗时较高;建议替换为精细化接口 ——lv_obj_refr_size(仅刷新目标控件尺寸)和lv_obj_refr_pos(仅刷新目标控件位置),可大幅降低布局计算的时间开销。
5. LCD推屏能力和理论帧率计算¶
送数时长,以QSPI为例:
QSPI 是4个数据线, 在RGB565模式下 一个像素点(16bit)数据需要
16/4个时钟周期送一帧全屏数据耗时(us) = 图形宽 * 图形高 * 每个像素需要的时钟周期 / QSPI速率
如16bit的410x494的屏,在48M的速率下:
t = 410 x 494 * 4 / 48 000 000 = 16.87(ms),在这种条件下,帧率就不能跑60hz了,会导致lcd自刷新时,数据还未送完出现撕裂
具体可参见 理论推屏帧率计算方法。
6. 调试方法¶
6.1 抓点工具sysview¶
使用方法参见文档Systemview工具抓点
6.2 调试指令¶
以下的finsh指令不带传参的都是发一次开启,再发一次关闭。
查看每个刷新周期耗时:
task_time发送一次仅打印每个周期task handle的耗时
发送两次则在一的基础上打印indev 以及refr 的耗时
发送四次则关闭打印
查看字体的log:
ft_log
查看每个页面的
msg handle(start/resume/pause/stop)耗时:app_sche_print_perf_tick 1
查看一级页面
msg handle(start/resume/pause/stop)耗时:tileview_fwk
调试打印时间的接口
毫秒级的可以直接使用
rt_tick_get微秒级使用
cpu_get_hw_us
统计某个行为的耗时,直接使用上面的接口计算该行为前后的时间差即可