手把手教你移植 LVGL 到嵌入式 Linux

LVGL(Light and Versatile Graphics Library)是一个轻量化的、开源的、在嵌入式系统中广泛使用的图形库,它提供了一套丰富的控件和组件,只需要少量的内存和计算资源,使得在资源受限的设备上创建高端的图形界面成为可能。本文记录如何将 LVGL 移植到嵌入式 Linux 系统中。

  • 编程环境:Windows11 VS Code
  • 编译环境:Ubuntu18.04 交叉编译
  • 测试平台:正点原子 i.MX6ULL
  • 显示屏:5inch RGB 800×480

准备

打开 LVGL 的 Github 主页github.com/lvgl,分别下载 lvgllv_driverslv_port_linux_frame_buffer 仓库源码,lvgl 和 lv_drivers 我这里选择下载当前最新的已发布版本:

创建工程

  1. 创建 lvgl_demo 文件夹;
  2. 将 lvgl、lv_drivers 复制到 lvgl_demo 中;
  3. 将 lv_port_linux_frame_buffer 仓库中的 main.c 文件和 makefile 文件复制到 lvgl_demo 中;
  4. 将 lvgl 中的 lv_conf_template.h 文件复制到 lvgl_demo 中并且改名为 lv_conf.h;
  5. 将 lv_drivers 中的 lv_drv_conf_template.h 文件复制到 lvgl_demo 中并且改名为 lv_drv_conf.h;
  6. 创建好的工程目录如图所示:

修改配置

修改 lv_drv_conf.h

  • #if 0 改成 #if 1
  • USE_FBDEV 的值改为 1,使能 frame buffer 设备:
  • USE_EVDEV 的值改为 1,配置触控输入设备的文件路径:

修改 lv_conf.h

  • #if 0 改成 #if 1
  • 根据实际情况适当扩大内存:
  • 这里可以修改刷新频率,默认为 30ms:
  • 配置 Tick:
  • 使能 widgets demo:

修改 main.c

  • 修改后的 main.c 文件如下所示:
c 复制代码
#include "lvgl/lvgl.h"
#include "lvgl/demos/lv_demos.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/evdev.h"
#include <unistd.h>
#include <time.h>
#include <sys/time.h>

#define DISP_BUF_SIZE (800 * 480)

int main(void)
{
    lv_init();

    /*Linux frame buffer 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);      /*Basic initialization*/

    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;
    now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;

    uint32_t time_ms = now_ms - start_ms;
    return time_ms;
}

修改 Makefile

  • 指定编译器,因为我在编译前会设置编译器环境变量,为避免错误,此处注释掉该配置,使用环境下默认编译器:
  • 添加 lv_drivers.mk,注释掉鼠标样式源文件:
  • 修改了下构建目标名称:
  • 若编译过程中出现未识别的编译选项,如报 error: unrecognized command line option '-Wshift-negative-value' 类似错误,可删除 -Wshift-negative-value 选项,该选项的作用是检查左移操作(<<)中可能出现的负数:

编译运行

  • 首先设置交叉编译链的环境变量,执行 make 命令:
  • 编译成功后在工程目录生成一个可执行文件 lvgl_demo,将其复制到 IMX6U 开发板上;
  • 我这里使用 NFS 挂载的方式,将 lvgl_demo 复制到 NFS 工作目录:
  • 启动 IMX6U,查看 IP,挂载 NFS:
  • 切换到 /mnt/ 目录下,运行 lvgl_demo
  • 运行成功:

更多内容

相关推荐
xuanzdhc2 小时前
Linux 基础IO
linux·运维·服务器
愚润求学2 小时前
【Linux】网络基础
linux·运维·网络
bantinghy3 小时前
Linux进程单例模式运行
linux·服务器·单例模式
小和尚同志4 小时前
29.4k!使用 1Panel 来管理你的服务器吧
linux·运维
帽儿山的枪手4 小时前
为什么Linux需要3种NAT地址转换?一探究竟
linux·网络协议·安全
shadon1789 天前
回答 如何通过inode client的SSLVPN登录之后,访问需要通过域名才能打开的服务
linux
小米里的大麦9 天前
014 Linux 2.6内核进程调度队列(了解)
linux·运维·驱动开发
算法练习生9 天前
Linux文件元信息完全指南:权限、链接与时间属性
linux·运维·服务器
忘了ʷºᵇₐ9 天前
Linux系统能ping通ip但无法ping通域名的解决方法
linux·服务器·tcp/ip
浩浩测试一下9 天前
渗透测试指南(CS&&MSF):Windows 与 Linux 系统中的日志与文件痕迹清理
linux·运维·windows·安全·web安全·网络安全·系统安全