LVGL 通用移植指南 (MCU & Linux)
本指南总结了将 LVGL 移植到任何嵌入式系统(无论是裸机 MCU 还是运行 Linux 的 SoC)的通用流程。
1. 核心源码集成
无论是什么平台,第一步都是将 LVGL 源码加入工程。
- 获取源码: 从 GitHub 克隆或下载特定版本的 LVGL。
- 添加路径: 确保编译器能够搜索到
lvgl.h所在的根目录。 - 编译配置:
- Linux/Makefile: 包含
lvgl.mk。 - MCU/IDE: 手动将
src目录下所有源文件加入编译列表,并添加头文件包含路径。
- Linux/Makefile: 包含
2. 配置文件 (lv_conf.h)
这是 LVGL 的“大脑”,决定了库的功能和行为。
- 创建文件: 复制
lv_conf_template.h并更名为lv_conf.h。 - 基本配置:
- 将
#if 0修改为#if 1。 - 颜色深度: 设置
LV_COLOR_DEPTH(通常 MCU 为 16,Linux 为 32)。 - 内存管理:
- MCU: 设置
LV_MEM_SIZE分配静态堆。 - Linux/OS: 建议设置
LV_MEM_CUSTOM 1直接使用系统的malloc/free。
- MCU: 设置
- 将
- Tick 接口:
- LVGL 需要一个毫秒级的计时器来处理动画和刷新。
- 方式 A (推荐): 开启
LV_TICK_CUSTOM 1并提供一个获取系统时间的函数。 - 方式 B: 在硬件中断(如 SysTick)中手动调用
lv_tick_inc(1)。
3. 显示驱动移植 (Display Interface)
LVGL 不直接操作硬件,它通过你提供的回调函数进行绘图。
- 初始化硬件: 初始化 LCD 控制器、SPI/I2C 总线或映射 Framebuffer。
- 注册驱动:
- 定义
lv_disp_draw_buf_t并分配显存缓冲区(可以是单缓冲或双缓冲)。 - 定义
lv_disp_drv_t结构体。 - 实现
flush_cb回调函数: 这是核心,LVGL 会传入坐标和像素数据,你需要将其拷贝到屏幕上。 - 调用
lv_disp_drv_register()。
- 定义
4. 输入设备移植 (Input Interface)
- 初始化硬件: 初始化触摸芯片、按键 GPIO 或打开 evdev 设备。
- 注册驱动:
- 定义
lv_indev_drv_t结构体。 - 设置设备类型(
LV_INDEV_TYPE_POINTER触摸/鼠标,或LV_INDEV_TYPE_KEYPAD按键)。 - 实现
read_cb回调函数: LVGL 会定期调用此函数,你需要返回当前坐标和按键状态(按下或释放)。 - 调用
lv_indev_drv_register()。
- 定义
5. 主循环与任务处理
LVGL 是非阻塞的任务系统,需要你在主循环中不断轮询。
int main() {
lv_init(); // 1. 初始化内核
hal_init(); // 2. 初始化你的显示和输入驱动
ui_init(); // 3. 创建你的 UI 界面
while(1) {
lv_timer_handler(); // 4. 处理定时器、刷新屏幕、读取输入
usleep(5000); // 5. 适当延时 (MCU 使用 Delay)
}
}
6. MCU 与 Linux 的主要区别
| 特性 | MCU (裸机/RTOS) | Linux (SoC) |
|---|---|---|
| 显存 | 通常在内部 RAM 或外部 SDRAM | 通过 /dev/fb0 进行内存映射 (mmap) |
| 输入 | SPI/I2C 读取触摸 IC 寄存器 | 读取 /dev/input/eventX 标准接口 |
| 内存 | 静态数组分配 | 动态内存分配 (malloc) |
| 文件系统 | FatFS / LittleFS | 标准 POSIX (fopen/fread) |
| 多线程 | 需注意临界区保护 | 需注意互斥锁 (Mutex) |
7. 移植清单 (Checklist)
-
lv_conf.h是否已启用并配置了颜色深度? -
lv_tick_inc或LV_TICK_CUSTOM是否正常工作? -
flush_cb是否能将像素正确显示在屏幕上? -
read_cb是否能正确上报坐标? -
主循环是否在持续调用
lv_timer_handler()?