嵌入式技术论坛
直播中

五斤麻辣油

8年用户 1271经验值
擅长:电源/新能源
私信 关注
[经验]

如何将LVGL显示库移植到GD32F427V开发板上去呢

前言

LVGL是一个开源的轻量级图形显示库,非常适合资源比较少的单片机进行移植,上一次使用SPI驱动了一块TFTLCD屏幕,这一次就想着将LVGL移植上来,可以显示一些好看的界面。

本文实现了如下功能:

1、移植基于RT-Thread OS(使用RT_Thread OS移植起来十分的方便,都不需要自己去github下载源码了);
2、开发工具基于RT-Thread Stduio;
3、实现了LVGL功能移植,并使用label(标签)显示字符串;
4、如果没有使用RT-Thread OS,使用其他的系统或者是裸机,本文还是有一定的参考价值。

开发流程

环境准备

1、准备一个可以正常驱动LCD或者其他显示屏幕的工程,其中需要用到画点函数,画点函数是LVGL能够正常工作的基础,如果没有这个函数,需要先实现一个。 使用GD32F427V-START驱动TFT LCD的过程可以参考我之前发的帖子(本文最上部分);

2.、RT-Thread Studio开发环境,如果使用标准版RT-Thread OS,其他开发环境也是一样的操作,但是配置方面需要使用RT-Thread 提供的ENV工具;如果没有使用RT-Thread OS,使用其他的系统或者是裸机,本文还是有一定的参考价值;

移植过程

添加LVGL包

如下图,添加LVGL,如果使用ENV,则按照ENV的方式添加;

1.png

如果使用逻辑,需要在github上下载,电脑安装git,然后输入命令:

git clone --recursive https://github.com/lvgl/lvgl.git

创建显示文件

如下图,将这两个文件移植到application目录下,并更新名字,不然会导致编译错误。

注:还有四个文件根据实际情况选择是否需要复制到application,和文件系统以及触摸屏有关,我所使用的LCD屏幕不带触摸功能,所以没有移植,如果带有触摸功能,可以将最后两个文件一并移植到application文件夹下备用,关于触摸文件的修改,本文不做说明。

2.png

更新显示文件

修改头文件包含以及头文件内容

1、针对app_port_disp.c文件,修改头文件包含

4.png

2、针对app_port_disp.h文件,修改如下部分

5.png

移植(重要部分)

现在开始最重要的部分了,这部分是lvgl移植的核心,需要和我们的驱动文件配合起来。具体方式见下面:

1、修改显示屏的长和宽

我所使用的显示屏是320X240的,所以做如下修改。
如下图:

6.png

2、lv_port_disp_init函数修改

定位到该函数,初始化buffer,官方提供了三种方式,并详细描述了每方式的区别,本文使用第一种方式,最为简单,我们将buffr扩大了一些,其实默认也是可以的。

屏蔽不需要的其他两种方式。

如下图:

7.png

3、disp_init函数修改

定位到disp_init,这里面添加驱动函数的初始化函数即可。
修改如下:

其中,lcd_init是我的LCD屏幕的驱动函数;

lcd_set_region是我的驱动函数中设置屏幕长宽的函数,这里根据自己的驱动函数实现逻辑添加即可,对于我的驱动代码,lcd_set_region是必须要加的,不然屏幕显示不正确。

/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
 /*You code here*/
 /* Initialize lcd */
 extern void lcd_init(void);
 lcd_init();
 extern void lcd_set_region(uint16_t x_start,uint16_t y_start,uint16_t x_end,uint16_t y_end);
 lcd_set_region(0,0,MY_DISP_HOR_RES - 1,MY_DISP_VER_RES - 1);
}

4、更新disp_flush函数

该函数是LVGL显示的核心函数,需要将我们自己的驱动代码写到这里,主要是画一个实心矩形的驱动代码,官方提供了一个接口,我们可以直接在两个for循环内部加上我们的画点函数,或者是自己实现一个画实心矩形的逻辑。我修改的代码如下。

其中,

LCD_CS_CLR与LCD_CS_SET是我的LCD特有的操作,不一定每个驱动代码都会这样写;
lcd_draw_point是我的画点函数,color_p是颜色变量,一般的颜色都是16位的,所以直接转换成了uint16即可,颜色的位数可以进行配置,后面再说。

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    if(disp_flush_enabled) {
        /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/

        int32_t x;
        int32_t y;

        LCD_CS_CLR;
        for(y = area->y1; y <= area->y2; y++) {
            for(x = area->x1; x <= area->x2; x++) {
                /*Put a pixel to the display. For example:*/
                /*put_px(x, y, *color_p)*/
                extern void lcd_draw_point(uint16_t x,uint16_t y,uint16_t data);
                lcd_draw_point(x, y, (uint16_t)color_p->full);
                color_p++;
            }
        }
        LCD_CS_SET;
    }

    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

到目前为止,基本上以及算是移植完成了显示部分了,但是现在还是不能使用,因为还没有进行配置,接下来描述这部分。

RT-Thread配置

如果没有使用RT-Thread OS可以忽略这步骤,后面的步骤(lv_conf.h文件中)也可以对这部分内容进行配置。

打开RT-Thread配置页面,配置lvgl相关参数,配置想很少,根据实际情况配置。

第一项配置优先级;
第二项配置LVGL使用RT-Thread任务的栈空间;
第三项配置,用于配置屏幕刷新速率,单位是ms。默认是5。其实没必要,因为SPI总线的刷新速度跟不上,对于GD32F427V,SPI最快也要二分频,连接到了APB1总线,所以最高频率为25MHz。这里设置20或者30都是可以的,本来刷新速率也跟不上。

8.png

lv_conf.h文件创建

lv_conf.h文件是用于配置LVGL中的一些功能是否使能的。模板中已经提供了,我们只需要复制过来,更新一下名字即可。

9.png

1、使能该文件

90.png

2、设置配置

默认配置就能够使用了,但是很多选择项都是打开的,很占用资源,可以对其中一些不使用的显示模块进行禁用,本文就不做过多说明。

注: 在编译的时候还是会报一些警告或者是编译错误,直接将lv_conf.h中报错的宏定义禁掉就可以了,因为很多都是重定义,在其他地方已经定义过了,这里无需再次定义,然后在此编译就不会报错了。

举例如下:

91.png

关于宏LV_DPI_DEF的计算公式如下:

DPI = 根号下(长边像素的平方+短边像素的平方)/英寸。
对于我的LCD,2.2寸,320X240,所以计算公式为
DPI = 根号下(320320 + 240 240) / 2.2 ≈ 182.

到目前为止,整个移植过程都结束了,接下来就是写测试用例来测试移植是否成功了。

测试代码

如果用的是RT-Thread OS,官方已经提供了测试代码,如下,并且会自动参与编译,我们就无须手动创建了,没有使用RT-Thread需要手动创建一个文件,本文不做说明:

92.png

官方已经帮我们创建好了显示任务,我们不需要再次创建,只需要往里面添加显示内容即可。

禁掉其中无用的内容。

只需要修改lvgl_thread_entry文件。

禁掉lv_port_indev_init以及lv_user_gui_init;
lv_user_gui_init起止可以不用禁掉,在里面写我们的代码,但是不知道为什么我这边总是编译不通过,所以就禁掉了,然后添加了函数
Gui_LvglEntry,这个函数需要我们自己实现。

static void lvgl_thread_entry(void *parameter)
{
#if LV_USE_LOG
    lv_log_register_print_cb(lv_rt_log);
#endif /* LV_USE_LOG */
    lv_init();
    lv_port_disp_init();
//    lv_port_indev_init();
//    lv_user_gui_init();

    extern void Gui_LvglEntry(void);
    Gui_LvglEntry();

    /* handle the tasks of LVGL */
    while(1)
    {
        lv_task_handler();
        rt_thread_mdelay(PKG_LVGL_DISP_REFR_PERIOD);
    }
}

实现Gui_LvglEntry

在application里面新建一个文件app_gui.c,然后新建一个函数Gui_lvgl_Test,内容如下:

该函数我实现了显示不同颜色的字符串;见效果展示。

/*
 * @hehung
 * 2022-12-13
 *  转载请注明出处
 * */

#include "lvgl.h"

static void Gui_lvgl_Test(void);

/* My GUI entry */
void Gui_LvglEntry(void)
{
    Gui_lvgl_Test();
}

/* Lvgl test for porting to GD32F427V  */
static void Gui_lvgl_Test(void)
{
    lv_obj_t * label;

    /*Create a label below the slider*/
    label = lv_label_create(lv_scr_act());
    lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);     /*Break the long lines*/
    lv_label_set_recolor(label, true);                      /*Enable re-coloring by commands in the text*/
    lv_label_set_text(label, "#0000ff GD32F427V-START#\n"
                             "#ff00ff aijishu.com#\n "
                             "#ff0000 Lvgl Porting Test#\n"
                             "         --hehung");
    lv_obj_set_width(label, 150);  /*Set smaller width to make the lines wrap*/
    lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
}

至此,整个LVGL移植过程结束。下面试验证。

验证

效果见下方。

试了一下刷新,速度还是比较慢,后期还需要优化,使用DMA应该会快一些。

93.png

94.png

原作者:hehung

更多回帖

发帖
×
20
完善资料,
赚取积分