LVGL 使用记录
一、移植LVGL
使用LVGL的V8.3.10版本,移植对照正点原子或者网上的教程。
1.1 移植部分
- 打开LVGL Porting中
lv_port_disp
的宏,将if 0
改为if 1
,需要使用按键、旋转编码器、触摸屏则需要再打开lv_port_indev
中的宏,配置好接口。(习惯先把屏幕调通,再去调其他组件)
#if 1
/*********************
* INCLUDES
*********************/
#include "lv_port_disp.h"
#include <stdbool.h>
...
- 我是用的是单缓冲方式,由于内存不足,只开了10行,也是LVGL的最低要求,实际看自身的屏幕,我用的是320*172方式,刷17次可以刷新一次整屏,感觉还可以。
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);
- 配置lvgl刷新函数
disp_flush
,采用DMA刷屏效果会更好,由于使用了Freertos操作系统,所以利用中断完成回调函数可以避免死等,充分发挥操作系统的优势,但是在这里并没有试过用信号量同步的方式来刷屏,后续可以尝试一下,目前刷屏效果还是很理想的。(注释部分是没有采用DMA刷屏时想到更换8位到16位来增加传输速率的方法,经测试,相比8位提升也很明显,DMA资源不够的时候也可以试试)。
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
if(disp_flush_enabled) {
// int32_t x;
// int32_t y;
// spi2_set_TB(1);
// LCD_Address_Set(area->x1, area->y1, area->x2, area->y2);
// spi2_set_TB(2);
// 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)*/
// LCD_WR_DATA16(color_p->full);
// color_p++;
// }
// }
lcd_draw_fast_rgb_color(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p);
}
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
// lv_disp_flush_ready(disp_drv);
}
/**
* @brief LCD加速绘制函数
* @param (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex - sx + 1) * (ey - sy + 1)
* @param color:要填充的颜色
* @retval 无
*/
void lcd_draw_fast_rgb_color(int16_t x1, int16_t y1,int16_t x2, int16_t y2, uint16_t *color)
{
uint16_t w = x2-x1+1;
uint16_t h = y2-y1+1;
spi2_set_TB(1);
LCD_Address_Set(x1, y1, x2, y2);
spi2_set_TB(2);
uint32_t draw_size = w * h;
LCD_CS_Clr();
HAL_SPI_Transmit_DMA(&hspi2,(uint8_t*)color,draw_size);
}
// DMA刷屏
void HAL_SPI_TxCpltCallback( SPI_HandleTypeDef *hspi )
{
if( hspi->Instance == SPI2 )
{
if( hspi->State == HAL_SPI_STATE_READY )
{
LCD_CS_Set();
lv_disp_flush_ready(&disp_drv);
}
}
}
- freertos创建任务进行调度,运行例程,一定要将
lv_timer_handler()
运行在循环中,非os系统可以开定时器运行或者暂时放在主循环,加入延迟可以在空闲时间运行其他任务。
#include "FreeRTOS.h"
#include "task.h"
#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_demo_stress.h"
#define LV_DEMO_TASK_PRIO 3 /* 任务优先级 */
#define LV_DEMO_STK_SIZE 1024 /* 任务堆栈大小 */
TaskHandle_t LV_DEMOTask_Handler; /* 任务句柄 */
void lv_demo_task(void *pvParameters); /* 任务函数 */
void lvgl_demo(void)
{
lv_init();
lv_port_disp_init(); /* lvgl 显示接口初始化,放在 lv_init()的后面 */
lv_port_indev_init();
// /* 创建 LVGL 任务 */
xTaskCreate((TaskFunction_t )lv_demo_task,"lv_demo_task",LV_DEMO_STK_SIZE,NULL,LV_DEMO_TASK_PRIO,&LV_DEMOTask_Handler);
}
void lv_demo_task(void *pvParameters)
{
lv_demo_stress();
while(1)
{
lv_timer_handler(); /* LVGL 计时器 */
vTaskDelay(5);
}
}
移植后出现错误的原因大概率是draw中gpu部分未选择对。
剩下的慢慢总结,后面会讲解如何使用内部字体和外部字体,有兴趣请点个赞,有问题丢评论区,看到就回!