嵌入式 Linux 下的 LVGL 移植

[复制链接]
发表于 2026-10-4 15:12:30 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

LVGL(Light and Versatile Graphics Library)是轻量开源嵌入式图形库,提供丰富控件,只需少量内存与算力,就能在资源受限的硬件上做出体面的界面。本文记录把 LVGL 移植到嵌入式 Linux 的完整过程:准备源码、搭工程、改 lv_conf.h 与 lv_drv_conf.h、重写 main.c 注册显示与输入驱动、改 Makefile,最后交叉编译烧板。

一、环境准备

  • 编程环境:Windows 11 + VS Code
  • 编译环境:Ubuntu 18.04 交叉编译
  • 测试平台:正点原子 i.MX6ULL
  • 显示屏:5 寸 RGB 800×480

到 LVGL 的 GitHub 主页分别下载三个仓库:lvgl、lv_drivers、lv_port_linux_frame_buffer。这里采用已发布版本:lvgl v8.3.11、lv_drivers v8.3.0。lv_port_linux_frame_buffer 是官方提供的 Linux framebuffer 移植模板,等于半套现成工程,省事很多。

二、创建工程目录

  1. 新建 lvgl_demo 文件夹。
  2. 把 lvgl、lv_drivers 复制进去。
  3. 把 lv_port_linux_frame_buffer 里的 main.c 和 Makefile 复制进 lvgl_demo。
  4. 把 lvgl 里的 lv_conf_template.h 复制出来改名 lv_conf.h。
  5. 把 lv_drivers 里的 lv_drv_conf_template.h 复制出来改名 lv_drv_conf.h。

三、修改 lv_drv_conf.h

  • 把 #if 0 改成 #if 1,让配置块生效。
  • 把 USE_FBDEV 的值改为 1,使能 framebuffer 设备,这是 Linux 下直接写显存的显示后端。
  • 把 USE_EVDEV 的值改为 1,指定触摸输入设备路径。输入事件号可以先 cat /dev/input/eventX,再触摸屏观察有没有内容输出来确认 X 是几。

四、修改 lv_conf.h

  • 同样把 #if 0 改成 #if 1。
  • 按实际环境适当调大内存相关配置,8.3 版本里是 LV_MEM_SIZE 一类参数。
  • 可改刷新周期,默认 30ms。
  • 设置 Tick:使用 LV_TICK_CUSTOM 加自定义时间源。
  • 使能 widgets demo,方便验证移植是否成功。

五、main.c 的核心改动

#include "lvgl/lvgl.h"
#include "lvgl/demos/lv_demos.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/evdev.h"

#define DISP_BUF_SIZE (800 * 480)

int main(void)
{
    lv_init();

    /* Linux framebuffer device init */
    fbdev_init();

    /* A small buffer for LittlevGL to draw the screen's content */
    static lv_color_t buf[DISP_BUF_SIZE];

    /* Initialize a descriptor for the buffer */
    static lv_disp_draw_buf_t disp_buf;
    lv_disp_draw_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE);

    /* Initialize and register a display driver */
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.draw_buf = &disp_buf;
    disp_drv.flush_cb = fbdev_flush;
    disp_drv.hor_res = 800;
    disp_drv.ver_res = 480;
    lv_disp_drv_register(&disp_drv);

    /* Linux input device init */
    evdev_init();

    /* Initialize and register a display input driver */
    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);

    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = evdev_read;
    lv_indev_t *my_indev = lv_indev_drv_register(&indev_drv);

    /* Create a Demo */
    lv_demo_widgets();

    /* Handle LVGL tasks */
    while (1) {
        lv_timer_handler();
        usleep(5000);
    }

    return 0;
}

/* Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR` */
uint32_t custom_tick_get(void)
{
    static uint64_t start_ms = 0;
    if (start_ms == 0) {
        struct timeval tv_start;
        gettimeofday(&tv_start, NULL);
        start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
    }

    struct timeval tv_now;
    gettimeofday(&tv_now, NULL);
    uint64_t now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;

    return (uint32_t)(now_ms - start_ms);
}

几个必改的字段:disp_drv.flush_cb 必须是 fbdev_flush;横竖分辨率要和你实际屏一致,填错会导致画面拉伸;Tick 用自定义时间源实现,否则 LVGL 的任务调度会失去心跳。主循环里调 lv_timer_handler 加 usleep 让出 CPU,不要写死循环空转。

六、Makefile 调整

  • 指定编译器:编译前会设环境变量,为避免重复定义报错,此处注释掉 Makefile 里的编译器设置,使用环境默认值。
  • 引入 lv_drivers.mk:把 lv_drivers 的 mk 加进编译目标;同时注释掉鼠标样式源文件,嵌入式环境没有鼠标时会报缺失。
  • 改构建目标名称:按项目需要改成自己的产物名。
  • 可选编译选项调整:若报 unrecognized command line option '-Wshift-negative-value' 这类未识别选项错,直接把这个检查项删掉即可——它只是在做左移负值的静态检查,和移植本身无关。

七、验证要点

  • 先 x86 本机跑一遍,确认 widgets demo 能起来,再切交叉编译。
  • 交叉编译后用 file 确认产物是 ARM 架构再下载。
  • 屏幕上出现 demo 界面、点触摸有响应,才算移植完整;只有画面没触摸,多半是 evdev 事件号填错。

qidao123.com企服评测-应用市场 编辑提示

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表