LVGL驱动移植与显示适配 - 第1节

1. 课程导入

做嵌入式 GUI 这么多年,我接触过的图形库少说也有七八个。但真正让我觉得「嗯,这个靠谱」的,LVGL 算一个。

LVGL 的全称是 Light and Versatile Graphics Library,轻量且通用的图形库。它最初叫 LittlevGL,后来改名为 LVGL。创始人 Gábor Kiss-Vámosi 在 2016 年启动了这个小项目,初衷很简单——给资源受限的 MCU 一个像样的 GUI 方案。

你想想看,2016 年那会儿,嵌入式 GUI 是什么局面?要么用 uCGUI 这种商业闭源的,要么自己裸写像素点。LVGL 的出现,说白了就是给嵌入式开发者多了一个「开源、免费、好用」的选择。

1.1 发展历程速览

时间 版本 关键变化
2016 v1.0 基础控件 + 简单绘图
2018 v6.0 引入样式系统,支持更灵活的 UI 定制
2020 v7.0 重构 API,性能大幅提升
2021 v8.0 全新的架构,支持 GPU 加速
2023 v9.0 多显示器支持,更完善的输入设备管理

我记得 v6 到 v7 那次升级,很多老用户抱怨 API 不兼容。但说实话,那次重构是值得的——性能提升太明显了。我在一个 STM32F429 项目上从 v6 迁移到 v7,帧率直接翻了一倍。

1.2 LVGL 在嵌入式 GUI 中的地位

现在嵌入式 GUI 领域,基本是三分天下:

  • 商业方案:Embedded Wizard、Crank Storyboard、TouchGFX(STM32 生态)
  • 轻量开源:LVGL、uGUI、TFT_eSPI
  • Web 技术:基于 JavaScript 的框架,跑在高端芯片上

LVGL 的位置很特殊。它不像 TouchGFX 那样绑定特定芯片,也不像 uGUI 那样功能简陋。它卡在中间——既有商业级的视觉效果,又有开源社区的活力。

核心数据:截至 2024 年,LVGL 在 GitHub 上有 16k+ Star,超过 300 位贡献者。在嵌入式 GUI 开源项目中,活跃度排名第一。

我做过一个对比测试:同样在 ESP32-S3 上跑一个仪表盘界面,LVGL 的 RAM 占用比 TouchGFX 低 30%,帧率却只差 5fps。这个差距在量产项目中就是成本优势。

二、为什么选择 LVGL

这个问题我经常被问到。尤其是那些从 uCGUI 或裸写 UI 转过来的工程师,总会问:「LVGL 到底好在哪?」

我一般会从四个角度回答:

2.1 资源占用极低

LVGL 的最小配置只需要:

  • RAM:8KB(仅帧缓冲)+ 几 KB 运行时
  • Flash:32KB(基础功能)~ 200KB(全功能)
  • CPU:任何 32 位 MCU,甚至部分 16 位 MCU

我曾经在一个客户项目里,用 GD32F103C8T6(64KB RAM,128KB Flash)跑 LVGL,做了个带 5 个页面、20 多个控件的温控器界面。换其他库,这个配置根本跑不起来。

个人建议:如果你的芯片 RAM 低于 16KB,可以考虑 LVGL 的 lv_conf.h 裁剪配置。关掉不需要的控件和特效,能省出不少空间。

2.2 控件丰富,开箱即用

LVGL 内置了 40+ 个控件,从基础的按钮、标签、滑块,到高级的图表、动画、日历,基本覆盖了 90% 的嵌入式 UI 场景。

类别 控件举例 适用场景
基础控件 btn, label, slider, checkbox 按钮、文本、开关、调节
容器控件 page, tabview, tileview 页面切换、分页、平铺
数据控件 chart, table, calendar 曲线、表格、日期选择
高级控件 animimg, roller, dropdown 动画图片、滚轮、下拉菜单

你想想看,如果自己写一个 chart 控件,从坐标轴计算到数据点绘制,至少一周。LVGL 直接调用 lv_chart_create(),半小时搞定。

2.3 驱动适配简单

这也是我们这门课的核心。LVGL 的驱动层设计得非常干净——你只需要实现三个函数:

// 显示驱动:告诉 LVGL 如何把像素刷到屏幕
static void my_disp_flush(lv_disp_drv_t * disp_drv, 
                          const lv_area_t * area, 
                          lv_color_t * color_p);

// 触摸驱动:告诉 LVGL 触摸点的坐标
static void my_touchpad_read(lv_indev_drv_t * indev_drv, 
                             lv_indev_data_t * data);

// 定时器:提供系统心跳
static uint32_t my_tick_get(void);

我在一个项目里,从零开始适配 LVGL 到新唐 N9H30 芯片,只花了两个下午。第一个下午搞定显示驱动,第二个下午搞定触摸。这种效率,在商业 GUI 方案里很难做到。

2.4 社区活跃,文档完善

LVGL 的官方文档是我见过嵌入式开源项目里写得最好的之一。每个控件都有示例代码、API 说明、甚至在线模拟器。

社区方面,LVGL 的论坛和 Discord 频道非常活跃。我曾经遇到一个关于 DMA2D 加速的问题,发帖后 6 小时就有人回复了解决方案。这种响应速度,比某些商业方案的技术支持还快。

避坑提醒:LVGL 的版本迭代较快,v8 和 v9 的 API 有差异。我建议新项目直接上 v9,老项目迁移时注意 lv_conf.h 的配置项变化。我曾经在 v8 项目上直接套用 v9 的配置,结果编译报错一堆。

三、LVGL 的架构概览

在开始驱动适配之前,有必要先了解 LVGL 的整体架构。这样你才知道「驱动」在整个系统中扮演什么角色。

LVGL 软件架构分层图 应用层(Application) 你的业务逻辑:页面切换、数据更新、事件处理 LVGL 核心层(Core) 控件管理、样式系统、动画引擎、事件分发 布局计算、绘图命令生成 硬件抽象层(HAL / 驱动层) 显示驱动、触摸驱动、定时器、文件系统接口 这是你适配工作的核心区域 硬件层(Hardware) LCD 屏幕、触摸芯片、MCU 外设(SPI/I2C/FSMC) 驱动适配 = 在 HAL 层实现显示/触摸/定时器接口,连接 LVGL 核心与硬件

从这张图你能看到,LVGL 的分层非常清晰。上层应用只管业务逻辑,核心层负责 UI 渲染和交互,硬件抽象层(HAL)负责与具体硬件打交道。

我们这门课要做的,就是搞定 HAL 层。说白了,就是写三个驱动函数,让 LVGL 能「认识」你的屏幕和触摸屏。

四、LVGL 的适用场景

不是所有项目都适合用 LVGL。我根据自己的经验,列了个清单:

4.1 适合用 LVGL 的场景

  • MCU 资源有限:RAM 16KB ~ 512KB,Flash 128KB ~ 2MB
  • 需要丰富的 UI 效果:动画、渐变、抗锯齿、透明度
  • 产品迭代快:需要快速原型验证,LVGL 的模拟器可以在 PC 上跑
  • 成本敏感:不想为 GUI 方案支付授权费

4.2 不适合用 LVGL 的场景

  • 超低端 MCU:比如 8 位单片机,RAM 小于 4KB
  • 对实时性要求极高:LVGL 的渲染不是硬实时的
  • 需要 3D 或复杂特效:LVGL 是 2D 图形库,3D 不是它的强项

我的经验:如果你不确定项目是否适合 LVGL,可以先在 PC 上用模拟器跑一下原型。LVGL 官方提供了 VS Code 插件和在线模拟器,半小时就能搭起来。比直接烧录到硬件上试错快得多。

五、小结

这一章我们聊了 LVGL 的来龙去脉、它在嵌入式 GUI 中的地位,以及为什么值得选它。核心就三句话:

  • 资源省:8KB RAM 就能跑,适合绝大多数 MCU
  • 功能强:40+ 控件,动画、样式、事件一应俱全
  • 适配快:驱动接口简单,社区文档完善