LittleV GUI移植用于ST7789——显示配置
2021/11/10 6:09:50
本文主要是介绍LittleV GUI移植用于ST7789——显示配置,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Step 1 — 准备移植所需文件
从lvgl官网下载到的文件中,主要需要以下选中的文件或文件夹:
在自己的工程中新建文件夹,命名为lvgl,将上述选中文件全部提取至该文件夹中,完整的工程文件树如下:
其中:
- Bsp文件夹中的问价为ST7789的驱动文件,详情请参考ST7789驱动;
- lvgl/example文件夹中包含了官方给出的各类例子,之所以建议将之拷贝至工程中主要是方便日后随时查阅,同时,其中的porting文件夹中包含了移植的关键性接口文件的模板;
- lvgl/src文件夹中包含了GUI库的所有核心文件;
- lvgl.h中包含了各类函数的声明,方便调用,lv_conf_template.h为lvgl配置的模板。
Step 2 — 修改和补充相关的文件
1. porting文件夹中的文件
porting文件夹中个包含以下文件:
其中:
- disp的模板文件为显示相关的接口函数的注册文件;
- fs的模板文件为文件系统相关的接口函数的注册文件;
- indev的模板文件为输入设备的接口函数的注册文件。
本随笔中将重点讨论GUI系统的移植,因此此处仅说明disp的模板文件的修改:
- 将disp相关的模板文件创建副本,并重命名,去掉_template后缀;
- 将h文件中的开始处的
#if 0
改为#if 1
使能该文件; - 在h文件中声明外部调用初始化端口的函数:
/********************** * GLOBAL PROTOTYPES **********************/ void lv_port_disp_init(void);
- 将c文件中的开始处的
#if 0
改为#if 1
使能该文件; - LVGL的buffer设置,源文件提供了三种方式的例子,本文采用第一种方式,故注释掉后面两种方式,仅修改第一种方式,如下:
/** * 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) */ #define MY_DISP_HOR_RES 256U 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]; /*An other 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*/
- 修改分辨率,如下:
disp_drv.hor_res = 240; disp_drv.ver_res = 240;
- 补充初始化函数,如下:
/*Initialize your display and the required peripherals.*/ static void disp_init(void) { st7789_init(); }
- 补充flush函数,注意,如果采用写点函数来做,刷屏会很慢,所以推荐的方式如下:
/*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*/ // 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, *color_p)*/ // st7789_draw_pixel(x, y, color_p->full); // color_p++; // } // } uint16_t x1, y1, x2, y2, size; x1 = area->x1; y1 = area->y1; x2 = area->x2; y2 = area->y2; size = (x2 - x1 + 1) * (y2 - y1 + 1); st7789_set_address(x1, y1, x2, y2); st7789_cfg_dcx_set(); st7789_cfg_spi_write((uint8_t*)color_p, size * 2); /*IMPORTANT!!! *Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(disp_drv); }
2. 修改lv_conf.h
文件
- 将
lv_conf_template.h
创建副本并重命名为lv_conf.h
; - 将
#if 0
修改为#if 1
以使能该文件; - 将
LV_COLOR_16_SWAP
宏定义为1,以解决注册的flush
函数颜色错误问题。
3. 添加时基
听闻LVGL自带非抢占式操作系统,需要时基支持,此处可采用系统自带的滴答定时器中断来实现,如下:
/** * @brief This function handles System tick timer. */ void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); /* USER CODE BEGIN SysTick_IRQn 1 */ lv_tick_inc(1); /* USER CODE END SysTick_IRQn 1 */ }
Step 3 — 工程属性设置修改
在路径中加入相关的文件路径,如下:
在源文件位置中添加相关文件夹,如下:
Step 4 — LVGL相关函数的调用
首先需经过初始化,如下:
/* USER CODE BEGIN 2 */ lv_init(); lv_port_disp_init(); /* USER CODE END 2 */
其次,非常重要的一步,需要在while (1)
循环中调用lv_task_handler()
函数,如下:
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { lv_task_handler(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
考虑到函数的使用相对复杂,因此此时库中的例子将有非常重要的参考意义,在使用自带的例子时,只需包含头文件lv_examples.h
即可调用其自带的例子,例如:
/* USER CODE BEGIN 2 */ lv_init(); lv_port_disp_init(); lv_example_keyboard_1(); /* USER CODE END 2 */
最终显示效果如下:
Step 5 — LVGL库的剪裁
在实际使用中,完成上述移植后,系统的Flash占用率非常高,如下:
为此,应考虑进行合理的剪裁。很遗憾,我尝试过,但并没有成功。
这篇关于LittleV GUI移植用于ST7789——显示配置的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!