1. 环境准备与源码获取
第一次接触IMX6ULL和LVGL的朋友可能会觉得有点懵,其实只要跟着步骤走,移植过程并不复杂。我去年在做一个工业HMI项目时就用这套组合,实测下来稳定性很不错。先说说需要准备的东西:
开发环境方面,你需要:
- 一台运行Linux的主机(Ubuntu 20.04 LTS是我用的版本)
- 安装好arm-linux-gnueabihf交叉编译工具链
- IMX6ULL开发板(我用的野火i.MX6ULL开发板)
- 一根Micro USB线用于调试
获取源码这块有个小技巧:建议把所有相关仓库都放在同一级目录。我习惯在~/Projects下建个lvgl_imx6ull目录,这样管理起来方便。具体要克隆的仓库包括:
git clone --branch v8.3 https://github.com/lvgl/lvgl.git git clone --branch v8.3 https://github.com/lvgl/lv_drivers.git git clone https://github.com/lvgl/lv_port_linux_frame_buffer.git git clone --branch v8.3 https://github.com/lvgl/lv_demos.git注意我特意指定了v8.3版本,因为新版本可能会有API变动。第一次移植建议用稳定版,等跑通后再考虑升级。
2. 项目目录结构与配置
把代码都下载好后,我们需要整理下目录结构。我建议这样组织:
~/Linux/ui/ ├── lvgl/ # 核心库 ├── lv_drivers/ # 驱动 ├── lv_demos/ # 示例程序 └── lv_port/ # 自己创建的目录,放移植文件关键配置文件的处理:
- 把
lv_port_linux_frame_buffer里的main.c和Makefile复制到lv_port目录 - 复制
lv_drivers/lv_drv_conf_template.h到lv_port,重命名为lv_drv_conf.h - 复制
lvgl/lv_conf_template.h到lv_port,重命名为lv_conf.h
这里有个坑要注意:Windows用户如果用WSL,记得把文件换行符转换成LF格式,否则编译会出奇怪错误。我当初就被这个问题卡了半天。
3. Makefile深度适配
原生的Makefile需要针对IMX6ULL做调整,主要修改点:
# 修改交叉编译工具链 CC = arm-linux-gnueabihf-gcc # 添加IMX6ULL特有的编译选项 CFLAGS += -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard # 解决C99标准问题 %.o: %.c @$(CC) $(CFLAGS) -c $< -std=c99 -o $@遇到-Wshift-negative-value报错时,可以在CFLAGS里加上-Wno-shift-negative-value屏蔽这个警告。这个警告在ARM架构下可以忽略,不影响实际运行。
4. 驱动配置文件精调
lv_drv_conf.h需要重点配置三个部分:
/* 启用配置文件 */ #define LV_DRV_CONF_INCLUDE_SIMPLE 1 /* 帧缓冲设备设置 */ #define USE_FBDEV 1 #define FBDEV_PATH "/dev/fb0" /* 输入设备配置 */ #define USE_EVDEV 1 #define EVDEV_NAME "/dev/input/event1"实际项目中,event编号可能不同。可以通过cat /proc/bus/input/devices查看具体的设备节点。我遇到过触摸屏对应event编号变化的情况,建议写个自动检测脚本。
5. LVGL核心参数配置
lv_conf.h的配置直接影响性能,根据IMX6ULL的硬件特性建议这样设:
/* 基础显示设置 */ #define LV_HOR_RES_MAX 800 #define LV_VER_RES_MAX 480 /* 内存配置 */ #define LV_MEM_SIZE (512U * 1024U) // 根据实际内存调整 #define LV_MEM_CUSTOM 1 /* 优化选项 */ #define LV_DISP_DEF_REFR_PERIOD 30 // 刷新周期(ms) #define LV_INDEV_DEF_REFR_PERIOD 30如果出现画面撕裂,可以尝试启用双缓冲:
#define LV_USE_DOUBLE_BUFFER 16. 主程序改造实战
main.c需要适配具体硬件,主要修改点:
// 设置显示分辨率 static struct fb_var_screeninfo var_info = { .xres = 800, .yres = 480, .bits_per_pixel = 32 }; // 注释掉鼠标相关代码(如果没有外接鼠标) // indev_drv.type = LV_INDEV_TYPE_POINTER; // indev_drv.read_cb = evdev_read; // lv_indev_drv_register(&indev_drv);建议在初始化完成后添加硬件检测逻辑:
if(access("/dev/fb0", F_OK) == -1) { perror("Frame buffer device not found"); exit(EXIT_FAILURE); }7. 编译与调试技巧
编译时建议先清理再构建:
make clean && make -j4遇到链接错误时,可以尝试添加这些库:
LDLIBS += -lm -lpthread -lrt调试时我发现一个实用技巧:通过SSH连接开发板后,执行:
export FB_MULTI_BUFFER=2 ./your_app这样可以启用多缓冲,减少画面闪烁。
8. 性能优化实战
IMX6ULL跑LVGL想要流畅,这几个优化点很关键:
- 帧缓冲配置: 在
/etc/default/psplash中设置:
FRAMEBUFFER=/dev/fb0 CONSOLE_ENABLED=0- CPU频率锁定:
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor- 内存分配策略: 在
lv_conf.h中启用自定义内存管理:
#define LV_MEM_CUSTOM 1 void * my_malloc(size_t size) { return malloc(size); }我在项目中发现,启用硬件加速后性能提升明显:
#define LV_USE_GPU_NXP_PXP 1 #define LV_USE_GPU_NXP_PXP_AUTO_INIT 19. 进阶开发建议
成功运行基础Demo后,可以尝试这些进阶操作:
- 多语言支持:
git clone https://github.com/lvgl/lv_i18n.git在lv_conf.h中启用:
#define LV_USE_I18N 1- 文件系统集成:
#define LV_USE_FS_POSIX 1 #define LV_FS_POSIX_PATH "/mnt/sd"- 自定义主题:
lv_theme_t * theme = lv_theme_default_init( lv_disp_get_default(), lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), LV_THEME_DEFAULT_DARK, &lv_font_montserrat_14 ); lv_disp_set_theme(lv_disp_get_default(), theme);最后提醒下,IMX6ULL的GPIO速度较慢,如果要用作输入设备,建议加上软件去抖:
#define LV_INDEV_DEF_READ_PERIOD 50 // 读取间隔(ms)