LVGL v8.2移植到IMX6ULL开发板

文章目录

LVGL简介

LVGL最初是由匈牙利人Gabor Kiss-Vamosi所创建的,目前的更新到了稳定版本V8.3,本文档所移植的版本是V8.2。LVGL的官方文档和Github源码链接如下:

LVGL - Light and Versatile Embedded Graphics Library

LVGL in Github

LVGL是"Light and Versatile Graphics Library"的简称(早年又称之为"LittleVGL",后改名为此),叫做”轻量级多功能图形界面库“,是一种适用于大多数嵌入式设备的图形化界面库。与QT类似,LVGL借用了面向对象的编程思想,但使用的编程语言是C,这使得LVGL编程易于理解与上手。

移植LVGL的硬件条件

大多数嵌入式主板都可以支持LVGL(包括单片机、Arduino、以及Linux开发板等),但是处理器的位数必须是16位及以上

移植准备

1. 源码下载

本文档针对LVGL 8.2版本在Linux IMX6ULL开发板上移植LVGL需要下载的源码如下:

  • lvgl:https://github.com/lvgl/lvgl.git
  • lv_drivers:https://github.com/lvgl/lv_drivers.git
  • lv_port_linux_frame_buffer:https://github.com/lvgl/lv_port_linux_frame_buffer.git

lvgl:包含了LVGL基本的源码,以及官方给出的LVGL demo;

lv_drivers:包含了大多数设备的显示控制器和触摸驱动程序,主要用来指定显示屏使用哪一种驱动框架(包括FB、DRM等驱动程序框架);

lv_port_linux_frame_buffer主函数文件所在的目录,整个工程的主文件夹,lvgl和lv_drivers都应放在此目录下。

可以在具有代理服务器的情况下克隆上述三个仓库的源码:

git clone -b release/v8.2 https://github.com/lvgl/lv_port_linux_frame_buffer.git

git clone -b release/v8.2 https://github.com/lvgl/lvgl.git

git clone -b release/v8.2 https://github.com/lvgl/lv_drivers.git

  1. 驱动加载
    在使用本文档的教程之前,请确保IMX6ULL已加载FB或DRM驱动。

移植过程
源码修改

先将下载好的源码文件夹lvgl和lv_drivers放在lv_port_linux_frame_buffer的路径下;

shallwing@9d57f9229b66:~/lv_port_linux_frame_buffer$ ls
LICENSE  lv_conf.h  lv_drivers/  lv_drv_conf.h  lvgl/  main.c  Makefile  mouse_cursor_icon.c  README.md

下面将对源码中的Makefile、lv_conf.h、main.c、lv_drv_conf.h等文件进行修改,以达到让编译后的程序成功在IMX6ULL上运行的目标。

  1. 修改lv_conf.h
    打开lv_conf.h,先看到第15行,检查文件是否使能:
/* clang-format off */
#if 1 /*Set it to "1" to enable content*/

使能该文件,应该将#if后面的0改为1。

之后看到第27行,将宏LV_COLOR_DEPTH设置为16:

/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 16

这里的宏LV_COLOR_DEPTH表示的是显示屏的颜色深度,由于我们使用的LCD屏幕是RGB565格式的(即表示RGB三个颜色通道分别用5bytes、6bytes、5bytes的空间来存储),所以色深应该设置为16(bytes)。

然后看到48至67行的代码片段:

/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/
#define LV_MEM_CUSTOM 1
#if LV_MEM_CUSTOM == 0
    /*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
    #define LV_MEM_SIZE (2 * 1024U * 1024U)          /*[bytes]*/

    /*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
    #define LV_MEM_ADR 0     /*0: unused*/
    /*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/
    #if LV_MEM_ADR == 0
        //#define LV_MEM_POOL_INCLUDE your_alloc_library  /* Uncomment if using an external allocator*/
        //#define LV_MEM_POOL_ALLOC   your_alloc          /* Uncomment if using an external allocator*/
    #endif

#else       /*LV_MEM_CUSTOM*/
    #define LV_MEM_CUSTOM_INCLUDE <stdlib.h>   /*Header for the dynamic memory function*/
    #define LV_MEM_CUSTOM_ALLOC   malloc
    #define LV_MEM_CUSTOM_FREE    free
    #define LV_MEM_CUSTOM_REALLOC realloc
#endif     /*LV_MEM_CUSTOM*/

这一段代码是用来进行显存配置的,将LV_MEM_CUSTOM设置为1,则表示使能显存分配。在开启显存分配之后,系统便可以给LCD屏分配运行显存。

看到第80行至84行的代码:

/*Default display refresh period. LVG will redraw changed areas with this period time*/
#define LV_DISP_DEF_REFR_PERIOD 10      /*[ms]*/

/*Input device read period in milliseconds*/
#define LV_INDEV_DEF_READ_PERIOD 10     /*[ms]*/

这里设置的是屏幕的刷新时间,单位是毫秒(ms)。我们将其中的30ms改为10ms。

看到86至92行的代码:

/*Use a custom tick source that tells the elapsed time in milliseconds.
 *It removes the need to manually update the tick with `lv_tick_inc()`)*/
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM
    #define LV_TICK_CUSTOM_INCLUDE <stdint.h>         /*Header for the system time function*/
    #define LV_TICK_CUSTOM_SYS_TIME_EXPR (custom_tick_get())    /*Expression evaluating to current system time in ms*/
#endif   /*LV_TICK_CUSTOM*/

这里设置的是心跳时间,在主函数文件main.c中有一个custom_tick_get的函数,用于之后的事件响应编程和定时任务编程,若此功能没有使能,则点击屏幕上的组件将没有响应。

看到第671行,为了看到移植的效果,我们先使能官方的demo,来检测是否移植成功:

/*Show some widget. It might be required to increase `LV_MEM_SIZE` */
#define LV_USE_DEMO_WIDGETS        1
#if LV_USE_DEMO_WIDGETS
#define LV_DEMO_WIDGETS_SLIDESHOW  0
#endif

  1. 修改lv_drv_conf.h
    此文件用于配置显示屏所使用的底层驱动,我们使用DRM驱动框架来点亮LCD屏,所以对于此文件的修改,一律是屏蔽FBDEV而使能DRM。

看到第11行,先使能此文件,将“#if 0”改为“#if 1”:

/* clang-format off */
#if 1 /*Set it to "1" to enable the content*/

看到第318行,屏蔽FBDEV的驱动,将宏USE_FBDEV改为0:

/*-----------------------------------------
 *  Linux frame buffer device (/dev/fbx)
 *-----------------------------------------*/
#ifndef USE_FBDEV
#  define USE_FBDEV           0
#endif

#if USE_FBDEV
#  define FBDEV_PATH          "/dev/fb0"
#endif

然后看到337行,使能DRM驱动,将USE_DRM改为1:

/*-----------------------------------------
 *  DRM/KMS device (/dev/dri/cardX)
 *-----------------------------------------*/
#ifndef USE_DRM
#  define USE_DRM           1
#endif

#if USE_DRM
#  define DRM_CARD          "/dev/dri/card0"
#  define DRM_CONNECTOR_ID  -1	/* -1 for the first connected one */
#endif

看到第441行,使能鼠标或者触摸板作为evdev界面,将USE_EVDEV设置为1:

#ifndef USE_EVDEV
#  define USE_EVDEV           1
#endif

#ifndef USE_BSD_EVDEV
#  define USE_BSD_EVDEV       0
#endif

#if USE_EVDEV || USE_BSD_EVDEV
#  define EVDEV_NAME   "/dev/input/event1"        /*You can use the "evtest" Linux tool to get the list of devices and test them*/
#  define EVDEV_SWAP_AXES         0               /*Swap the x and y axes of the touchscreen*/

#  define EVDEV_CALIBRATE         1               /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/

#  if EVDEV_CALIBRATE
#    define EVDEV_HOR_MIN         0               /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX*/
#    define EVDEV_HOR_MAX      800               /*"evtest" Linux tool can help to get the correct calibraion values>*/
#    define EVDEV_VER_MIN         0
#    define EVDEV_VER_MAX      480
#  endif  /*EVDEV_CALIBRATE*/
#endif  /*USE_EVDEV*/

除此之外,还需要指定evdev设备节点的路径,一般来说,evdev输入设备节点的路径在/dev/input下,对应于event文件,然而/dev/input下有可能有多个event文件,此时我们可以用hexdump命令来检测:

hexdump event1

运行上面的命令之后,再点击LCD屏一下,如果发现终端输出了一大堆十六进制数,则说明LCD的evdev的输入设备节点是它,否则,就换一个event文件进行测试。然后,需要就自己显示屏的分辨率来设置其中的EVDEV_HOR_MAX和EVDEV_VER_MAX,我们的LCD显示屏分辨率是800*480,所以两个宏分别设置为800和480。

evdev是输入设备的配置,只有使能了evdev,触摸屏幕才会有反应

3. 修改main.c文件

在main.c文件里面,我们主要修改其中包含的头文件、使用的驱动类型,以及demo函数等。

先看到文件开头包含的头文件,修改其中包含的驱动头文件,将第3行的"fbdev.h"改为"drm.h":

#include "lvgl/lvgl.h"
#include "lvgl/demos/lv_demos.h"
#include "lv_drivers/display/drm.h"
#include "lv_drivers/indev/evdev.h"
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>

随后,看到第10行,修改显示缓冲区的大小,即800*480,分辨率的大小:

#define DISP_BUF_SIZE (800 * 480)

看到第18行,修改驱动设备的初始化函数,将fbdev_init()改为drm_init():

/*Linux frame buffer device init*/
drm_init();

看到第27至34行的代码部分,这一段是初始化和设置显示驱动的部分:

/*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);

照着我们的实际情况,进行修改与适配,由于LCD屏使用DRM驱动框架,所以将其中的flush_cb由fbdev_flush改为drm_flush,将其中的hor_res改为800,ver_res改为480,其他不改变。

看到代码的第46至50行,我们不使用鼠标作为LCD显示屏的输入设备,所以mouse部分将它注释掉:

#if 0
    /*Set a cursor for the mouse*/
    LV_IMG_DECLARE(mouse_cursor_icon)
    lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
    lv_img_set_src(cursor_obj, &mouse_cursor_icon);           /*Set the image source*/
    lv_indev_set_cursor(mouse_indev, cursor_obj);             /*Connect the image  object to the driver*/
#endif

看到第54行,这里面告诉了我们搭建整个LVGL应用程序的函数为lv_demo_widgets,通过查看main.c的头文件就可以知道,这个函数在“lvgl/demos/widgets/lv_demo_widgets.c”中定义。

/*Create a Demo*/
lv_demo_widgets();
4. 修改Makefile文件

打开主文件夹下的Makefile文件,对其进行修改。

看到第4行,将CC编译器修改为自己的交叉编译器,修改如下:

CC = /opt/buildroot/cortexA7/bin/arm-buildroot-linux-gnueabihf-gcc

注释掉第20行,使其不能编译鼠标输入设备的源码:

# CSRCS +=$(LVGL_DIR)/mouse_cursor_icon.c 

源码编译

源码修改完成之后,直接运行下面的命令进行编译:

make -j48

源码编译中会产生错误:

/home/shallwing/lv_port_linux_frame_buffer/lv_drivers/display/drm.c:28:10: 致命错误:drm_fourcc.h:No such file or directory
   28 | #include <drm_fourcc.h>
      |          ^~~~~~~~~~~~~~
编译中断。
make: *** [Makefile:35: /home/shallwing/lv_port_linux_frame_buffer/lv_drivers/display/drm.o] Error 1

这种错误的原因是没有找到/opt/buildroot下的头文件drm_fourcc.h,通过在/opt/buildroot下用find命令查找此文件,可以得到它的路径为:

./cortexA7/arm-buildroot-linux-gnueabihf/sysroot/usr/include/drm/drm_fourcc.h

所以文件”lv_drivers/display/drm.c“中应该改为:

#include <drm/drm_fourcc.h>

接着再次编译,又报出了"undefined reference"的错误:

drm.c:(.text+0x6c): undefined reference to `drmIoctl'
/opt/buildroot/cortexA7/lib/gcc/arm-buildroot-linux-gnueabihf/9.4.0/../../../..

这是因为系统在编译源码的时候,不会自动加载drm相关的链接器,需要我们自己加载,我们只需要在主Makefile中添加即可,在第8行和第9行之间添加:

LDFLAGS += -ldrm

接下来编译,虽然不会报错,但是会抛出“隐式声明函数custom_tick_get”或变量未使用的警告,这对后面的结果演示影响不大。在编译完成之后,源码主目录下会出现可执行文件demo,这便是最终生成的应用程序,我们接下来通过TFTP把它传到IMX6ULL开发板来进行效果演示。

效果演示

在IMX6ULL上运行demo之后,如果LCD屏出现下面的显示,则说明移植成功:

LVGL官方demo演示

此时IMX6ULL的串口终端还会打印配置信息,这也说明移植成功了:

root@igkboard:~# ./demo 
drm: Found plane_id: 31 connector_id: 35 crtc_id: 33
drm: 800x480 (0mm X 0mm) pixel format RG16
DRM subsystem and buffer mapped successfully

参考文档:
IMX6ULL移植LVGL

@[TOC](这里写自定义目录标题)

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

2014-01-07 2014-01-09 2014-01-11 2014-01-13 2014-01-15 2014-01-17 2014-01-19 2014-01-21 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.3.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值