**
LVGL8.2移植学习
链接: LVGL官网.
**
LVGL8.2文件组成
LVGL8.2移植所需的文件
文件 | 描述 | 路径 |
---|---|---|
demos | 官方的示例(可要可不要) | lvgl-release-v8.2 / demos |
porting | 显示输入输出接口(API) | lvgl-release-v8.2 / examples / porting |
src | lvgl的源文件 | lvgl-release-v8.2 / src |
lv_conf_template.h | lvgl配置文件 | lvgl-release-v8.2 / lv_conf_template.h |
lvgl.h | 头文件 | lvgl-release-v8.2 / lvgl.h |
Keil工程中移植源码
- 将src内的文件添加入工程中,在魔术棒中记得添加src中文件夹的头文件路径,不要忘记lv_conf_template.h和lvgl.h路径的添加,文件列表如下图所示:
注:由于暂时没有使用DMA2D故以上文件夹目录没有LVGL / src / gpu。
文件夹 | 需添加的文件 |
---|---|
example / porting | examples / porting文件夹下的lv_port_disp_template.c;带触摸的需添加lv_port_indev_template.c文件 |
src / core | lvgl-release-v8.2 / src / core文件夹下所有的.c 文件 |
src / draw | lvgl-release-v8.2 / src / draw添加文件夹下除nxp_pxp、nxp_vglite、sdl和stm32_dmazd文件夹之外的全部.c 文件 |
src / extra | lvgl-release-v8.2 / src / extra添加该文件夹下所有.c 文件 |
src / font | lvgl-release-v8.2 / src / font添加该文件夹下所有.c 文件 |
src / hal | lvgl-release-v8.2 / src / hal添加该文件夹下所有.c 文件 |
src / misc | lvgl-release-v8.2 / src / misc添加该文件夹下所有.c 文件 |
src / widgets | lvgl-release-v8.2 / src / 添加该文件夹下所有.c 文件 |
src / gpu | lvgl-release-v8.2 / src / draw添加该文件夹下draw / sdl和draw / stm32_dmazd中所有的.c 文件 |
修改移植的lvgl文件
注:修改之前应当将LCD、IPS等显示屏幕对应的驱动文件加入到Keil工程中。
1. 把lv_conf_template.h改为lv_conf.h
,lv_port_disp_template.h改为lv_port_disp.h
,分别修改两个文件中的条件编译指令:
#if 1 /*Set it to "1" to enable content*/
/*Copy this file as "lv_port_disp.h" and set this value to "1" to enable content*/
#if 1
以下内容在lv_port_disp.c文件中编辑
2. 在disp_init(void)
函数中调用屏幕初始化函数,如下:
/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
/*You code here*/
LCD_Init();
}
3. 配置图像数据缓冲模式
- 在
lv_port_disp_init(void)
函数中,官方提供有以下缓冲模式可选择;
/* Example for 1) */
static lv_disp_draw_buf_t draw_buf_dsc_1;
static lv_color_t buf_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
/* Example for 2) */
static lv_disp_draw_buf_t draw_buf_dsc_2;
static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10]; /*An other buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
/* Example for 3) also set disp_drv.full_refresh = 1 below*/
static lv_disp_draw_buf_t draw_buf_dsc_3;
static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*A screen sized buffer*/
static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*Another screen sized buffer*/
lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2, MY_DISP_VER_RES * LV_VER_RES_MAX); /*Initialize the display buffer*/
注:在LVGL8.2中单缓冲和双缓冲效果区分不明显(可能官方没有优化好)
缓冲模式 | 内存要求 |
---|---|
1- 单缓存 | 10行像素点*颜色深度对应字节数(RGB565-2个字节)内存允许可开辟大一点空间提高显示效果。 |
2- 双缓冲 | 210行像素点颜色深度对应字节数(RGB565-2个字节) |
3-全屏双缓冲 | 相当于建立两个和屏幕分辨率相当的缓冲区,对SRAM要求比较高 |
4. 在lv_port_disp_init()
函数中找到如下代码,设置自己的屏幕尺寸(注意自己的屏幕初始化是横屏还是竖屏)
/*Set the resolution of the display*/
disp_drv.hor_res = 320;
disp_drv.ver_res = 480;
5. 在disp_flush()
函数中配置画点函数
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
#if 1
int32_t x;
int32_t y;
uint16_t color=0xFF08;
uint16_t *color_px=(uint16_t *)color_p;
uint16_t height,width;
height=area->y2 - area->y1;
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)*/
//color = color_px[(y-area->y1)*height+(x-area->x1)];
POINT_COLOR = color_p->full;
LCD_DrawPoint(x,y);
color_p++;
}
}
#else
//LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p);
LCD_Color_Fill(area->x1, area->y1, area->x2, area->y2, (uint16_t*)color_p);
#endif
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
LVGL输入配置(这里以EC11编码器为例)
注:修改之前应当将EC11编码器(或其他输入设备)对应的驱动文件加入到Keil工程中。
1.把lv_port_indev_template.h改为lv_port_indev.h
,lv_port_indev_template.c改为lv_port_indev.c
分别修改两个文件中的条件编译指令:
2.裁剪lv_port_indev.c
内容,保留所需宏定义和函数定义
3.编辑编码器初始化函数、回调函数
4.在主程序调用LVGL输入设备初始化函数
为LVGL提供时基
添加定时器时基
1. 添加定时器驱动.c文件,可以通过STM32CubeMX直接配置生成。
2. 在定时器的.c文件中#include "lvgl.h"
。
3. 在定时器中断函数或回调函数中调用lv_tick_inc(x)
//在该回调函数中添加lv_tick_inc(1)-----
/***************推荐****************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//if(htim->Instance == BTIM_)
lv_tick_inc(1);
}
/***************不推荐****************/
void BTIM_TIMX_INT_IRQHandler()
{
HAL_TIM_IRQHandler(&htim3);
}
- 初始化定时器并保证中断时间间隔==
x
ms
测试程序的编写
1. main.c
中包含以下头文件:
#include "lvgl.h"
#include "lv_port_disp.h"
2. mian()
函数中初始化定时器、LVGL库、输入输出设备
MX_TIM3_Init();
HAL_TIM_Base_Start_IT(&htim3);
lv_init();
lv_port_disp_init();
3. while(1)
主循环中每隔一段时间调用以下函数,调用
HAL_Delay(5);
lv_task_handler();
4. 内存管理(在lvgl_conf.h
中) 默认是设置了48k的内存
注:如果系统内存不够会报错,可适当减少内存分配
/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/
#define LV_MEM_CUSTOM 0
#if LV_MEM_CUSTOM == 0
/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
#define LV_MEM_SIZE (48U * 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*/
压力测试例程移植
- 将lvgl-release-v8.2 / demos 复制到工程下
- 添加
lv_demo_stress.c
和相关.h
的路径 - 在
lv_conf.h
文件中,最下面找到以下宏定义,置1。#define LV_USE_DEMO_STRESS 0
- 在
main.c
中包含#include "lv_demo_stress.h"
- 初始化官方demo
lv_demo_stress();
其他
lv_conf.h
中设置显示FPS和CPU占用
/*1: Show CPU usage and FPS count*/
#define LV_USE_PERF_MONITOR 1
在FreeRTOS上运行LVGL8.2需要修改的点
- 使用FreeRTOS获取时间的函数
xTaskGetTickCount()
为LVGL提供时基;(可删除定时器提供时基代码)(但未测试成功,调试出现FreeRTOS和LVGL的任务调度出现冲突,还没找到问题原因)
- 通过FreeRTOS的Tick滴答钩子函数实现LVGL的心跳获取,空闲任务钩子函数实现LVGL的任务管理
(测试成功)
;该方法参考freeRTOS&LVGL|在使用freertos时如何为lvgl配置心跳和任务管理器实现。