LVGL移植

目录

LVGL

LVGL移植(无操作系统)

LVGL移植(带操作系统)

LVGL移植(外部SRAM)

LVGL移植(内存管理算法)

LVGL移植(DMA2D)

LVGL移植(配置文件介绍)


LVGL

LVGL是一个轻量、多功能的开源图形库。

官网:https://lvgl.io

移植要求:

        16、32或64位微控制器或处理器

        时钟速度>64MHz

        RAM:4KB+150字节/小部件(约48KB的UI与几个屏幕)

        Flash:大约100KB的LVGL(取决于启用的功能)

        绘制缓冲区:>1/10屏幕大小的缓冲区用于渲染

        帧缓冲区:显示控制器中至少有1个帧缓冲区,内部或外部RAM

        编译器:C99或更高版本

demosLVGL官方演示代码
docsLVGL文献,解析部件的使用方法
env_support环境支持(MDK、ESP、RTThread)
examples示例、输入输出设备接口文件
scriptsLVGL手稿
srcLVGL源文件
tests官方人员的测试代码
lv_conf_template.hLVGL的剪裁文件
lvgl.hLVGL包含的头文件


LVGL移植(无操作系统)

LVGL移植第一步(基本配置):

1、裁剪LVGL库文件(保留官方demo,方便移植)

        只保留LVGL文件:demos文件夹、examples文件夹、src文件夹、lv_conf_template.h文件、lvgl.h文件。

        examples文件夹只保留porting文件夹(输入输出还有文件系统相关的接口文件)。

2、把lv_conf_template.h文件该为lv_conf.h

3、打开lv_conf.h文件,修改条件编译指令,把#if 0修改成#if 1。

#if 1 /*Set it to "1" to enable content*/

4、以触摸屏实验为基础,添加定时器文件

5、修改该目录结构

        工程目录

                丨__  Middlewares文件夹

                                丨__  LVGL文件夹

                                                丨__  GUI文件夹

                                                                丨__  lvgl文件夹

                                                丨__  GUI_APP文件夹

6、复制examples文件夹、src文件夹、lv_conf_template.h文件、lvgl.h文件到lvgl文件夹

7、复制demos文件夹到GUI_APP文件夹。(可选,用来做示例)

8、在工程中添加工程组和添加文件到工程组

Middlewares/lvgl/example/porting添加example/porting文件夹下的lv_port_disp_template.c和lv_port_indev_template.c文件
Middlewares/lvgl/src/core添加src/core文件夹下的全部.c文件
Middlewares/lvgl/src/draw添加src/draw文件夹下的全部.c文件(除了nxp_pxp、nxp_vglite、sdl和stm32_dma2d文件夹)
Middlewares/lvgl/src/extra添加src/extra文件夹下的全部.c文件
Middlewares/lvgl/src/font添加src/font文件夹下的全部.c文件
Middlewares/lvgl/src/gpu添加src/draw/stm32_dma2d和src/draw/sdl文件夹下的全部.c文件
Middlewares/lvgl/src/hal添加src/hal文件夹下的全部.c文件
Middlewares/lvgl/src/misc添加src/misc文件夹下的全部.c文件
Middlewares/lvgl/src/widgets添加src/widgets文件夹下的全部.c文件

9、添加头文件路径

..\..\Middlewares\LVGL\GUI
..\..\Middlewares\LVGL\GUI\lvgl

..\..\Middlewares\LVGL\GUI\lvgl\src

..\..\Middlewares\LVGL\GUI\lvgl\examples\porting

10、开启C99模式

        正常无报错有警告,如果有报错,取消勾选MicroLIB。

11、屏蔽MDK警告(慎用,非必须)。

        在配置界面C/C++的Misc Controls栏中填入(不要有空格):--diag_suppress=68,111,188,223,546,1295

LVGL移植第二步(配置输出,如屏幕):

1、把lv_port_disp_template.c/h的条件编译指令#if 0修改成#if 1

2、包含输出设备驱动头文件。(可以把它放到lv_port_disp_template.c/h文件中,默认.c中)

3、在disp_init函数中初始化屏幕设备,默认设置横屏(也可竖屏,无要求)。(如LCD_Init函数)

static void disp_init(void)
{
    lcd_init();            // 屏幕初始化
    lcd_display_dir(1);    // 横屏
}

4、配置图像数据缓存模式(官方lv_port_disp_init()函数中提供三种,需要哪种就注释掉其它两种)。

        第一种:单缓存模式,默认。如320*240分辨率,RGB565格式。则数组大小默认是320*10*2,默认一次10行。

        第二种:双缓存模式,配合DMA。

        第三种:全屏幕双缓冲,配合DMA。对SRAM占有过大,如320*240分辨率,RGB565格式。则内部SRAM数组大小默认是320*240*2*2。外部SRAM效果还不如第一种。

#ifndef MY_DISP_HOR_RES
    #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen width, default value 320 is used for now.
    #define MY_DISP_HOR_RES    320
#endif

#ifndef MY_DISP_VER_RES
    #warning Please define or replace the macro MY_DISP_VER_RES with the actual screen height, default value 240 is used for now.
    #define MY_DISP_VER_RES    240
#endif

5、设置屏幕尺寸(默认横屏)

disp_drv.hor_res = lcddev.width;
disp_drv.ver_res = lcddev.height;

6、在disp_flush函数中配置打点输出(填充一块区域的颜色)。

/* 原文件内容,打点较慢 */
static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, uint8_t * px_map)
{
    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;
        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, *px_map)*/
                px_map++;
            }
        }
    }

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

/* 自己修改文件内容 */
static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, uint8_t * px_map)
{
    if(disp_flush_enabled) {
        /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/

       //void lcd_color_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color);
        lcd_color_fill(area->x1, area->y1, area->x2, area->y2, (uint16_t)color);
    }

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

LVGL移植第三步(配置输入,如触摸屏):

1、把lv_port_indev_template.c/h的条件编译指令#if 0修改成#if 1

2、按需裁剪输入设备(注释:触摸屏、鼠标、键盘、编码器、按键)。

3、包含输入设备驱动头文件

4、在touchpad_init函数中初始化触摸屏

static void touchpad_init(void)
{
    tp_dev.init();            // 触摸屏初始化
}

5、配置触摸检测函数

static bool touchpad_is_pressed(void)
{
    /*Your code comes here*/        
    tp_dev.scan(0);    // 0:屏幕扫描,1:物理坐标。如果按下会保存坐标轴,&tp_dev.x[0], &tp_dev.y[0]
    if(tp_dev.sta & TP_PRES_DOWN )    
    {
        return true;
    }

    return false;
}

6、配置坐标获取函数

static void touchpad_get_xy(int32_t * x, int32_t * y)
{
    /*Your code comes here*/

    (*x) = tp_dev.x[0];
    (*y) = tp_dev.y[0];
}

LVGL移植第四步(配置时基,功能测试):

1、添加定时器驱动

2、在定时器驱动.c文件中包含:#include "lvgl.h"

3、在定时器中断函数(回调)中调用:lv_tick_inc(x);

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == BTIM_TIMX_INT)
    {
        lv_tick_inc(1);
    }
}

4、初始化定时器时,需保证:进入中断的时间间隔 = x 毫秒

5、在main.c文件中包含头文件

#include "./BSP/TIMER/btim.h"
#include "lvgl.h"
#include "lv_port_disp_teemplate.h"
#include "lv_port_indev_teemplate.h"

6、初始化定时器、LVGL库、输入输出设备

btim_timx_int_init(10-1, 9000-1);    // 以F429为例,基本定时器为90MHz,1ms。
lv_init();
lv_port_disp_init();
lv_port_indev_init();

7、在while中每隔5ms调用一次lv_timer_handler();

        lv_timer_handler()函数的中断优先级比lv_tick_inc()要低,所以lv_tick_inc()放到中断里,对时基要求较高。

while(1)
{
    delay_ms(5);
    lv_timer_handler();
}

8、编写测试代码(while循环前调用即可)。

lv_obj_t *switch_obj = lv_switch_create(lv_scr_act());
lv_obj_set_size(switch_obj, 120, 60);
lv_obj_align(switch_obj, LV_ALIGN_CENTER, 0, 0);

LVGL移植第五步(移植压力测试demos,可选):

1、把demos文件夹复制到Middlewares/LVGL/GUI_APP路径下

2、添加头文件路径

..\..\Middlewares\LVGL\GUI_APP\demos
..\..\Middlewares\LVGL\GUI_APP\demos\stress

3、打开lv_conf.h文件,找到宏定义LV_USE_DEMO_STRESS并设置为1

4、新建Middlewares/LVGL/GUI_APP工程组,添加demos/stress文件夹下的lv_demo_stress.c文件

5、main.c文件里包含头文件:#include "lv_demo_stress.h"

6、初始化官方demo:lv_demo_stress();

LVGL移植第六步(移植音乐播放器demos,可选):

1、把demos文件夹复制到Middlewares/LVGL/GUI_APP路径下

2、添加头文件路径

..\..\Middlewares\LVGL\GUI_APP\demos
..\..\Middlewares\LVGL\GUI_APP\demos\music

3、打开lv_conf.h文件,找到宏定义LV_USE_DEMO_MUSIC并设置为1

4、新建Middlewares/LVGL/GUI_APP工程组,添加demos/music文件夹下的全部.c文件

5、此时编译可能会报错,打开lv_conf.h文件,找到相应字体的宏并设置为1即可。

#define    LV_FONT_MONTSERRAT_12    1
#define    LV_FONT_MONTSERRAT_14    1
#define    LV_FONT_MONTSERRAT_16    1

6、main.c文件里包含头文件:#include "lv_demo_music.h"

7、初始化官方demo:lv_demo_music();

LVGL移植(带操作系统)

在lv_conf.h文件中配置自定义时钟源,删除定时器提供时基的部分代码

#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM
    #define LV_TICK_CUSTOM_INCLUDE "FreeRTOS.h"
    #define LV_TICK_CUSTOM_SYS_TIME_EXPR (xTaskGetTickCount())
#endif    /*LV_TICK_CUSTOM*/
//btim_timx_int_init(10-1, 9000-1);    // 以F429为例,基本定时器为90MHz,1ms。

编译时内存不够如何处理?

1、修改lv_conf.h,适当减小分配给LVGL管理的内存。

2、lv_port_disp_template.c,适当减小图形缓冲区的大小,同时需要兼顾运行效果。

3、FreeRTOSConfig.h,适当减小分配给FreeRTOS的内存,简单的工程,一般10~20k就够用了。

LVGL移植(外部SRAM)

Tips:内部SRAM够用的情况下不建议使用外部SRAM,因为会影响运行效果。

外部SRAM的使用场景:

        场景1:把LVGL管理的内存空间放到外部SRAM(非常不推荐,因为一些小控件就是在LVGL管理的内存空间里进行分配的,放到外部SRAM中速度会变慢,会导致LVGL运行效果明显变差)

                1、确定外部SRAM首地址,根据需求确定地址偏移。

                2、在lv_conf.h中将LV_MEM_ADR定义到外部SRAM的地址(不一定是首地址)。

#define Bank5_SDRAM_ADDR    ((uint32_t)(0xC0000000))    /* SDRAM开始地址 */

/* lv_conf.h */
/* MEMORY SETTING */
#define LV_MEM_ADR    (0xC0000000 + 1280*800*2)    /*0:unused*/

        场景2:把绘图缓冲区放到外部SRAM(内部空间匮乏时可取)

                1、确定外部SRAM首地址,根据需求确定地址偏移。

                2、在lv_port_disp_template.c中创建全屏分辨率大小的数组,并将其定位到外部SRAM的地址。

#define Bank5_SDRAM_ADDR    ((uint32_t)(0xC0000000))    /* SDRAM开始地址 */

/* 在lv_port_disp_template.c中,lv_port_disp_init函数中有定义了绘图缓冲区,需要注释掉 */
//static lv_color_t buf_1[800 * 60];

/* 在lv_port_disp_template.c中的开头加入内容 */
/* 为什么1280*800*2,因为这个工程有个帧缓存数组占用了0xC0000000,1280*800大小,16bit */
/* STATIC VARIABLES */
static lv_color_t buf_1[800 * 480] __attribute__((at(0xC0000000 + 1280*800*2)));
/* 假如需要双缓冲区,可定义下面,lv_color_t类型为16位 */
static lv_color_t buf_2[800 * 480] __attribute__((at(0xC0000000 + 1280*800*2 + 800*480*2)));

LVGL移植(内存管理算法)

Tips:文中为正点原子自研内存管理算法。

移植步骤:

1、添加内存管理文件:Middlewares中添加MALLOC文件夹。

2、添加分组和.c文件:Middlewares/MALLOC--malloc.c

3、包含内存管理算法头文件:#include "./MALLOC/malloc.h"

LVGL中消耗内存的地方:

Tips:不同项目,内存分配的比例不同。一般分配给LVGL管理的内存为15~40k字节。

自研内存管理算法配置流程

        配置需要管理的内存池大小:

                在malloc.h文件中通过相关的宏来定义,不同板子代码的宏定义不同。

/* mem1内存参数设定.mem1完全处于内部SRAM里面 */
#define MEM1_BLOCK_SIZE        64
#define MEM1_MAX_SIZE          40*1024
#define MEM1_ALLOC_TABLE_SIZE  MEM1_MAX_SIZE / MEM1_BLOCK_SIZE

/* mem2....CCM */

/* mem3....外部SRAM */

        初始化需要管理的内存池:

                调用my_mem_init函数对所需要管理的内存池进行初始化即可。

my_mem_init(SRAMIN);

        适配自研的内存管理算法:

                编写LVGL内存分配、内存释放、内存重新分配这三个函数,配置相关宏定义。

/*malloc.h*/
/**
 * @brief       分配内存(外部调用)
 * @param       size:要分配的内存大小(字节)
 * @retval      分配到的内存首地址
 */
void *lv_mymalloc(uint32_t size)
{
    return (void*)mymalloc(SRAMIN, size);
}

/**
 * @brief       释放内存(外部调用)
 * @param       ptr:内存首地址
 * @retval      无
 */
void *lv_myfree(void *ptr)
{
    myfree(SRAMIN, ptr);
}

/**
 * @brief       重新分配内存(外部调用)
 * @param       *ptr:旧内存首地址
 * @param       size:要分配的内存大小(字节)
 * @retval      新分配到的内存首地址.
*/
void *lv_myrealloc(void *ptr, uint32_t size)
{
    return (void*)myrealloc(SRAMIN, ptr, size);
}

/*lv_conf.h*/
/* LV_MEM_CUSTOM。如果为1则使用自研内存管理算法;为0则使用内部内存管理算法 */
#define LV_MEM_CUSTOM    1
    #define LV_MEM_CUSTOM_INCLUDE "./MALLOC/malloc.h"
    #define LV_MEM_CUSTOM_ALLOC   lv_mymalloc
    #define LV_MEM_CUSTOM_FREE    lv_myfree
    #define LV_MEM_CUSTOM_REALLOC lv_myrealloc

/* 在lv_port_disp_template.c中的开头加入内容 */
/* 为什么要改?因为malloc也有用到sram的地址,地址冲突了,所以这里需要lvgl使用的sram进行偏移 */
/* STATIC VARIABLES */
static lv_color_t buf_1[800 * 480] __attribute__((at(0xC0000000 + 1280*800*2 + 10*1024 + 16*4)));
/* 假如需要双缓冲区,可定义下面,lv_color_t类型为16位 */
static lv_color_t buf_2[800 * 480] __attribute__((at(0xC0000000 + 1280*800*2 + 800*480*2  + 10*1024 + 16*4)));

详细请看:第10讲 基础篇-LVGL移植(内存管理)_哔哩哔哩_bilibili 

LVGL内部内存管理配置流程

        配置需要管理的内存池大小:

                通过lv_conf.h中的LV_MEM_SIZE来定义,以字节为单位。

/*lv_conf.h*/
/* LV_MEM_CUSTOM。如果为1则使用自研内存管理算法;为0则使用内部内存管理算法 */
#define LV_MEM_CUSTOM    0
    #define LV_MEM_SIZE    (48U * 1024U)

        创建需要管理的内存池:

                有3种方式:大数组、地址段、内存分配函数。

LVGL移植(DMA2D)

Tips:只针对硬件支持DMA2D的板。

1、修改lv_conf.h中相关的宏定义,开启DMA2D。

#define LV_USE_GPU_STM32_DMA2D    1
    #define LV_GPU_DMA2D_CMSIS_INCLUDE "stm32f429xx.h"

2、在MDK配置中添加对应芯片的定义。

3、配置DMA2D外设。

LVGL移植(配置文件介绍)

lv_conf.h文件内容介绍:

正点原子视频中带中文注释:第12讲 基础篇-LVGL移植(配置文件介绍1)_哔哩哔哩_bilibili

序号板块介绍功能描述
1颜色颜色深度、字节交换、屏幕透明等
2内存内存管理算法选择、内存分配大小等
3硬件层显示刷新周期、输入设备读取周期等
4特征绘图、日志、帧率显示等
5编译器(不重要)大数组前缀、内存对齐等
6字体开启系统字体、配置自定义字体等
7文本(不重要)字符编码、文本特性
8核心部件使能/失能核心部件
9扩展功能使能/失能扩展部件、第三方库等
10实例使能/失能LVGL官方的实例

  • 30
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在进行STM32 LVGL移植之前,需要进行一些准备工作。首先,需要准备一个STM32工程,并确保该工程中包含了TFT LCD控制器,即LTDC。通过LTDC,STM32F429系列芯片可以直接外接RGB LCD屏幕,实现液晶驱动。 其次,需要下载LVGL组件包。可以在lvgl-8.0.2目录下找到lvgl.h、lv_conf_template.h、LICENCE.txt和README.md这四个文件。将这四个文件复制到新建的GUI文件夹中,并确保lv_conf_template.h文件中的配置符合你的具体需求。 在移植LVGL过程中,还需要根据具体的硬件平台和需求,对LVGL进行配置和适配。这包括根据自己的需求进行UI设计、设置图形库的显示驱动程序、处理输入事件、内存管理以及定时器等的适配。通过参考LVGL的文档和示例代码,可以更详细地了解如何进行移植,并按照具体需求进行相应的配置和调整。 需要注意的是,LVGL移植过程可能会涉及到一些底层硬件的操作和配置,因此需要对硬件平台有一定的了解和熟悉。同时,移植过程中可能会遇到一些问题和挑战,需要进行一定的调试和优化。建议在移植过程中保持耐心,并及时查阅LVGL的官方文档和社区资源,以获取更多的帮助和支持。 总之,STM32 LVGL移植需要准备好STM32工程和LVGL组件包,并根据具体的硬件平台和需求进行配置和适配。移植过程中可能会遇到一些问题和挑战,但通过参考LVGL的文档和示例代码,并保持耐心和坚持,最终可以成功完成移植并使用LVGL来实现液晶驱动和UI设计。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值