lvgl gui development

    资源受限 MCU 上的 LVGL 界面开发:三款量产产品的实战经验

    我们如何在低成本 MCU 上交付 LVGL 图形界面——内存预算、帧率调优,以及何时该选 LVGL 而非 TouchGFX,源自三款已交付产品的实践总结。

    ·XTELL 工程团队

    为什么在小 MCU 上用 LVGL

    当一款产品需要彩色屏幕,但物料清单(BOM)成本撑不起一颗应用处理器时,图形栈就成了项目中最具决定性的工程决策之一。根据我们在手持设备、仪器仪表和车载产品上的经验,LVGL 已经成为低成本微控制器的默认选择:它开源、用 C 语言编写、不需要 GPU,而且在不同芯片系列之间移植只需适度的工作量。这一组合之所以重要,是因为成本导向的产品在开发过程中经常更换芯片——出现了更便宜的管脚兼容型号,或者供应商给出了更好的条件,GUI 代码就必须跟着迁移。绑定单一厂商的框架会让这种迁移非常痛苦。

    我们已在杰理 AC79xx 系列上交付过 LVGL:手持游戏机上的 AC7911BB 和 AC7912AB 主控,以及智能秤主板上的 AC7925A。同时,我们也在基于 STM32 的车载仪表上交付过 TouchGFX。本文提炼了这些项目在真正资源受限的硬件上构建 LVGL 界面的经验:如何在画出第一个控件之前就做好内存预算,如何在没有整屏大小帧缓冲的情况下保持动画流畅,以及当 LVGL 和 TouchGFX 都可选时,如何诚实地做出选择。

    内存预算的纪律,先于设计

    我们在 LVGL 项目中见过最常见的失败模式,就是把内存当作事后才考虑的问题。设计师做出漂亮的界面,开发人员照着实现,直到联调阶段才发现堆内存两屏就耗尽了。到了那时,每一种修复都是妥协。我们的规则很简单:GUI 的内存预算要在第一个界面设计之前就白纸黑字写下来,并且像对待功耗预算一样严肃。

    在 AC7911BB 和 AC7912AB 的手持项目中——一款手持游戏机,包含菜单界面、电子宠物、氛围灯逻辑、充电管理和船只模拟游戏——GUI 必须与游戏逻辑、音频和无线协议栈共存于同一颗芯片。我们的办法是在架构层面分离关注点:LVGL 负责界面层,SDL2 承载跨平台游戏逻辑,CMake 管理双目标的构建。把 GUI 框架和游戏引擎放在不同层,意味着每一层都可以独立地做预算、做性能分析、做优化,而不是去争抢同一个堆。

    以下几条实践在我们交付的多个 LVGL 项目中被证明行之有效:

    • 尽量在启动时静态分配 GUI 内存。界面切换时的动态分配是内存碎片和内存耗尽崩溃的藏身之处。按预算给 LVGL 划一块固定内存池,最坏情况在第一天就一目了然。
    • 绘制缓冲按屏幕条带而不是整帧来配。LVGL 支持局部渲染,按我们的经验,缓冲只占屏幕的一小部分,往往就是设计能装下还是装不下的分水岭。这只是个配置选择,并不牺牲视觉质量。
    • 每张图片资源入库前都要登记在册。在手持游戏机项目中,我们维护了完整的动画资源层——宠物蛋、角色、零食和背景资源——全部系统化管理,资源总占用永远可知。不在清单里的资源,不许出货。
    • 对字体集毫不留情地做减法。每种字体变体和字号都是一块 Flash 和 RAM。我们给每个产品固定一小组字号和字重,多语言产品只保留它需要的字形区间——不多一笔。
    • 大尺寸静态资源优先用索引色或压缩格式。全彩位图(背景、装饰图)通常是 GUI 内存最大的单项消耗,也是最容易在无可见损失下瘦身的一项。

    智能秤主板项目从另一个角度印证了同样的纪律。AC7925A 跑 LVGL 界面,AC792 SDK 驱动称重传感器,AI 服务器提供智能交互,微信小程序负责远程管理。四个子系统共享一颗芯片,GUI 预算从一开始就和传感器采样、网络、AI 接口缓冲一起谈判确定。当 GUI 团队确切知道自己有多少内存可用时,界面设计就变成了一个有边界的创作问题,而不是开放式的风险。

    帧率与动画:为你手里的硬件而设计

    在资源受限的 MCU 上实现流畅动画,靠的不是裸性能,而是调度纪律。LVGL 只重绘变化的部分,按我们的经验,那些感觉流畅的产品,设计师从一开始就理解了局部更新。每个动画元素都应该小、有边界、重绘成本低。全屏转场要省着用;真正带来动感的是小幅移动的控件、进度指示和状态变化。

    手持游戏机项目是最典型的例子。挑战是在一块小小的手持屏幕上实现流畅的游戏动画和丰富的交互体验——电子宠物动画、氛围灯效、船只模拟游戏,都得让人觉得活灵活现。我们的方法是系统化的动画资源管理:把动画序列拆成离散、可复用的资源,每个资源事先定好尺寸和预算,于是动画系统就变成了一个成本已知的数据问题,而不是开放式的渲染负担。宠物蛋、角色、零食、背景各层的复用资源,让内容不断增长的同时总占用依然可预测。

    同样重要的是硬件迭代。游戏机硬件从 V1.3 一路迭代到 V2,每个版本都给出了显示管线实际承载能力的实测反馈。按我们的经验,关于显示带宽的理论计算,替代不了在真实面板上跑真实动画集。多版本迭代让我们能用实测确认帧节奏,并把资源复杂度调到与硬件匹配——而不是反过来。

    第三个教训来自智能船只模拟与导航系统。那里 SDL2 驱动船只动力学仿真界面,LVGL 提供嵌入式 GUI,PID 控制负责精确航向。挑战是在嵌入式平台上同时做到实时船只动力学仿真和精确航向控制,还要在低功耗和实时响应之间找平衡。给 GUI 工作的启示是:界面层绝不能饿死控制环。我们把 LVGL 的刷新工作严格限定在边界内,让导航控制的时序保持确定性——这条原则适用于任何屏幕与时间关键任务共享芯片的产品,从电机控制到传感器采样。

    尽早在真实硬件上实测真实管线。只有经得起真实面板考验的动画预算,才是真正算数的预算。

    还有一条值得点名的实践:先在桌面端把界面原型跑起来。因为我们的手持软件栈把 LVGL 和 SDL2 结合在一个跨平台框架里,界面逻辑在目标硬件稳定之前很久就能在 PC 上充分验证。动画时序、资源加载、状态机都在桌面构建中验证完毕,于是 MCU 上的 bring-up 只剩下性能调优,不再是逻辑调试。CMake 让双目标构建变得可管理,这笔投入回报了许多倍。

    LVGL vs TouchGFX:两边都交付过之后的选择指南

    我们时常被问到该选哪个框架,诚实的回答是:我们两个都交付——AC7911BB、AC7912AB 和 AC7925A 上用 LVGL,基于 STM32 的电助力车仪表上用 TouchGFX。两个框架我们都交付过量产界面,下面是我们的选择思路。

    当可移植性和成本弹性重要时,选 LVGL

    LVGL 是我们做成本导向产品、以及芯片尚未冻结的任何项目的默认选择。它是真正可移植的 C 代码,没有厂商锁定,意味着换芯片时 GUI 的投入不会打水漂。在杰理 AC79xx 项目上这一点是决定性的:界面代码与芯片厂商的 SDK 解耦,团队可以把 GUI 当作独立的一层来思考。当产品路线图横跨多个芯片系列,或者团队本来就工作在基于 CMake、带桌面仿真的跨平台流程里,LVGL 也是自然之选。

    LVGL 的开发生态在开发中是实实在在的优势,不只是理念上的加分。社区控件、示例和工具缩短了常见模式的实现路径;而且源码开放,渲染管线里偶尔出现的深层 bug 真的可以定位和修复,而不是只能绕过去。

    当芯片已定为 STM32 且工作流契合时,选 TouchGFX

    电助力车仪表跑在 STM32 上用 TouchGFX,对这个产品来说是正确的选择。挑战是在有限的车载显示分辨率上做到清晰的信息显示加流畅动画——开机序列、挡位指示、指南针。TouchGFX 与 STM32Cube 生态的深度集成,意味着显示驱动、DMA 配置、帧缓冲设置都是成熟路径,而不是集成项目。TouchGFX Designer 的工作流契合产品需求:深色主题 UI、序列帧和 MP4 风格动画、系统化的图标集,在写一行目标代码之前就用可交互原型做了视觉迭代。

    按我们的经验,当芯片选型已定且不会再变、团队已深度投入 STM32 工具链、产品能从设计师主导的视觉迭代工作流中受益时,TouchGFX 就值回它的位置。授权和工具成本是真实存在的,但在稳定的 STM32 平台上,集成速度通常足以抵消它们。

    决策清单

    • MCU 选型定了吗?如果芯片还可能换,LVGL 的可移植性是更稳妥的赌注。
    • 团队已经深度使用 STM32Cube 吗?TouchGFX 会回报这份投入;LVGL 则保持中立。
    • 谁来做视觉迭代?设计师主导、带可交互原型的工作流偏向 TouchGFX Designer;工程师主导的团队通常能很快在 LVGL 上进入高效状态。
    • 动画风格是什么?序列帧和视频风格动画天然适合 TouchGFX 仪表;LVGL 擅长控件动画和局部更新,但需要纪律化的资源管理——我们的手持项目已经证明了这一点。
    • 长期维护的故事是什么?开源的 LVGL 意味着工具链不依赖某个厂商的路线图;TouchGFX 则是在押注 STM32 平台不会动。

    没有哪个选择在所有情况下都更好。真正的错误是凭熟悉度或市场宣传做选择,而不是依据产品的实际约束。我们见过在 STM32 上用 LVGL 磕磕绊绊的项目——换 TouchGFX 本可以更快集成;也见过 TouchGFX 项目为后期的芯片变更扭曲变形——换 LVGL 本可以从容吸收。让框架去匹配产品,而不是反过来。

    资源受限 MCU 上 LVGL 的实战清单

    从上面三款产品提炼出的清单,是我们每个 LVGL 项目启动时都会过一遍的——也是我们嵌入式开发服务实践的一部分:

    • 在设计任何界面之前写下 GUI 内存预算:静态分配目标、绘制缓冲尺寸、资源上限。
    • 在架构上把 GUI 层与应用逻辑分离,让每一层都能独立做预算和性能分析。
    • 给所有图片和动画资源登记造册;每个资源都有已知的尺寸和存在的理由。
    • 尽早统一字体,只收录产品需要的字形区间。
    • 围绕局部更新设计动画:小、有边界、重绘成本低的元素。
    • 把 GUI 刷新工作限定在边界内,不让它饿死传感器采样、电机控制、导航环路等时间关键任务。
    • 在目标硬件稳定之前,用跨平台构建在桌面端先验证界面逻辑。
    • 在真实面板和真实芯片上验证帧节奏,覆盖多个硬件版本——算出来的带宽不是测出来的带宽。
    • 为增长规划资源管线:系统化的命名、版本管理、构建集成,让资源集在内容增长时依然可管理。
    • 在项目启动时明确地重新审视 LVGL 与 TouchGFX 的选择,依据产品的实际约束,而不是习惯。

    结语

    在资源受限的 MCU 上交付 LVGL,不是英雄式的优化表演,而是一场纪律修炼。设计之前先做内存预算,系统化管理动画资源,在架构上把 GUI 层与时间关键任务隔离,尽早、频繁地在真实硬件上验证。手持游戏机、智能秤主板、船只导航系统各自考验了这套纪律的不同侧面:在小屏幕上做丰富动画、四个子系统共享一颗芯片、GUI 绝不能打扰实时控制环。而同样的方法在三者身上都站得住。

    而当产品的约束指向别处——固定的 STM32 平台、设计师主导的工作流、序列帧动画——我们同样能从容地交付 TouchGFX,电助力车仪表就是证明。框架是为产品服务的。如果你的团队正在为成本敏感型 MCU 权衡图形界面方案,这个决策,以及它背后的内存预算,正是有经验的合作伙伴体现价值的地方。

    需要专业服务?

    联系我们获取定制化解决方案和报价