本帖最后由 linguanghua 于 2021-9-1 16:13 编辑
上次移植过单色屏的GUI到AC781X开发板,现在找个彩屏,移植littlevGL(选择叫LVGL)。这个GUI版本更新很快,我最初使用是2019年,那时候国内很少人使用,现在已经更新到8.0版本了,已经很流行了,而原来的API已经面目全非。V7中的原来自带的task任务系统变成V8中的timer,不过本质上是一样的,定时调用。
0.开始移植,准备一个可正常使用的工程,包含LCD驱动。工程目录新建文件夹“LVGL”。
1.下载LVGL代码。目前最新V8.1了。
源码:https://github.com/lvgl/lvgl
官网:https://lvgl.io/
2.文档lvgl-master解压,复制文件夹“src”,文件lvgl.h和lv_conf_template.h 到文件夹“LVGL”,复制 examples下porting文件夹到文件夹“LVGL”。
3.文件夹“LVGL”下,将lv_conf_template.h改名为lv_conf.h,此文件内部,将开头的 #if 0 改为 #if 1,#define LV_COLOR_DEPTH 16这里修改为LCD位深。
此文件内有许多宏定义,可开关特定的功能、性能。
4.将lv_port_disp_template.c改名lv_port_disp.c,对应.H文件名也要修改。
lv_port_disp.c修改如下:(不知道为什么显示不了)
/**
* [url=home.php?mod=space&uid=288409]@file[/url] lv_port_disp_templ.c
*
*/
/*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/
#if 1
/*********************
* INCLUDES
*********************/
#include "lv_port_disp.h"
#include "../../lvgl.h"
#include "lcd.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void disp_init(void);
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
// const lv_area_t * fill_area, lv_color_t color);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/* Maximal horizontal and vertical resolution to support by the library.*/
#define MY_DISP_HOR_RES (160) //320
#define MY_DISP_VER_RES (128) //480
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
disp_init();
/*-----------------------------
* Create a buffer for drawing
*----------------------------*/
/**
* LVGL requires a buffer where it internally draws the widgets.
* Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
* The buffer has to be greater than 1 display row
*
* There are 3 buffering configurations:
* 1. Create ONE buffer:
* LVGL will draw the display's content here and writes it to your display
*
* 2. Create TWO buffer:
* LVGL will draw the display's content to a buffer and writes it your display.
* You should use DMA to write the buffer's content to the display.
* It will enable LVGL to draw the next part of the screen to the other buffer while
* the data is being sent form the first buffer. It makes rendering and flushing parallel.
*
* 3. Double buffering
* Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
* This way LVGL will always provide the whole rendered screen in `flush_cb`
* and you only need to change the frame buffer's address.
*/
/* 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*/
/*-----------------------------------
* Register the display in LVGL
*----------------------------------*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set up the functions to access to your display*/
/*Set the resolution of the display*/
disp_drv.hor_res = MY_DISP_HOR_RES;
disp_drv.ver_res = MY_DISP_VER_RES;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_flush;
/*Set a display buffer*/
disp_drv.draw_buf = &draw_buf_dsc_1;
/*Required for Example 3)*/
//disp_drv.full_refresh = 1
/* Fill a memory array with a color if you have GPU.
* Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
* But if you have a different GPU you can use with this callback.*/
//disp_drv.gpu_fill_cb = gpu_fill;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
/*You code here*/
}
/*Flush the content of the internal buffer the specific area on the display
*You can use DMA or any hardware acceleration to do this operation in the background but
*'lv_disp_flush_ready()' has to be called when finished.*/
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*/
LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(u16*)color_p);
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
/*OPTIONAL: GPU INTERFACE*/
/*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
// const lv_area_t * fill_area, lv_color_t color)
//{
// /*It's an example code which should be done by your GPU*/
// int32_t x, y;
// dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
//
// for(y = fill_area->y1; y <= fill_area->y2; y++) {
// for(x = fill_area->x1; x <= fill_area->x2; x++) {
// dest_buf[x] = color;
// }
// dest_buf+=dest_width; /*Go to the next line*/
// }
//}
#else /*Enable this file at the top*/
/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
5.打开工程文件,添加连个组 lvgl/src 和 lvgl/port ,将各个C文件导入工程。一些字体文件(font)和 extra 内的文件,gpu文件可不用添加,除非使用到。
6.定时器中断函数里加入lv_tick_inc(1);
/**
* [url=home.php?mod=space&uid=555622]@prototype[/url] TIM2_IRQnCallBack(uint8_t lparam)
*
* @param[in] ...
* [url=home.php?mod=space&uid=266161]@return[/url] ...
*
* [url=home.php?mod=space&uid=247401]@brief[/url] TIM2 module interrupt handler.
* TIM2中断处理函数.
*/
void TIM2_IRQnCallBack(uint8_t lparam)
{
if (TIMER_GetIntFlag(TIMER2))
{
g_ctimeflag=1;
lv_tick_inc(1);
}
TIMER_ClrIntFlag(TIMER2);
}
6.在需要的地方添加头文件(如main.c)
#include "lvgl.h"
#include "lv_port_disp.h"
程序开头加入
lv_init();
lv_port_disp_init();
然后在主函数的死循环或者低优先级任务中加入lv_task_handler();
这样就可以正常使用了。
用的屏幕比较小,不好发挥这个GUI的长处,随便弄些看看效果。在大屏中,这个GUI效果很不错。总体上比emWin好看。
|