2、LVGL移植

LVGL移植

准备工作

我使用的IDE是MDK.
硬件方面是自己画的硬件,主控F411CEUx(Flash:512/RAM:128),屏幕是1.14寸LCD屏幕.分辨率135*240,通信方式SPI.

下载源码

进入LVGL源码托管链接,下载release/v6版本(最新的已经到了V7).如下所示.

20201220171759

其中master是最新程序,修补程序直接在此合并.
dev在此合并新功能,稳定后合并到master
release/Vx代表了主要版本的稳定版本.

备注: 如果想知道版本之间的变化的话,可以查看CHANGELOG.md文档(仅V7版本有这个文件).

准备工程文件

我是用的是CUBEMX生成的工程,外加一部分淘宝卖家提供的LCD驱动程序.
CUBEMX的SPI设置为默认即可,开启SPI_TX的DMA及DMA中断.如下

20201220210818

20201220210921

备注:实际的SPI频率不是图中的8M,我是用的频率是24Mhz

新建一个bsp_lcd.c和bsp_lcd.h文件,内容分别如下所示.

bsp_lcd.c文件如下所示

#include "main.h"
#include "lcd.h"
#include "spi.h "
#define delay_ms HAL_Delay

//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;
static void LCD_direction(uint8_t direction);

//画笔颜色,背景颜色
//uint16_t POINT_COLOR = 0x0000, BACK_COLOR = 0xFFFF;
//uint16_t DeviceCode;
/*****************************************************************************
 * @name       :void LCD_WR_REG(uint8_t data)
 * @date       :2018-08-09
 * @function   :Write an 8-bit command to the LCD screen
 * @parameters :data:Command value to be written
 * @retvalue   :None
******************************************************************************/
void LCD_WR_REG(uint8_t data)
{
    LCD_CS_CLR;
    LCD_RS_CLR;
    SPI_WriteByte(SPI3, data);
    LCD_CS_SET;
}
/*****************************************************************************
 * @name       :void LCD_WR_DATA(uint8_t data)
 * @date       :2018-08-09
 * @function   :Write an 8-bit data to the LCD screen
 * @parameters :data:data value to be written
 * @retvalue   :None
******************************************************************************/
void LCD_WR_DATA(uint8_t data)
{
    LCD_CS_CLR;
    LCD_RS_SET;
    SPI_WriteByte(SPI3, data);
    LCD_CS_SET;
}
/*****************************************************************************
 * @name       :void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
 * @date       :2018-08-09
 * @function   :Write data into registers
 * @parameters :LCD_Reg:Register address
                LCD_RegValue:Data to be written
 * @retvalue   :None
******************************************************************************/
void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
{
    LCD_WR_REG(LCD_Reg);
    LCD_WR_DATA(LCD_RegValue);
}
/*****************************************************************************
 * @name       :void LCD_WriteRAM_Prepare(void)
 * @date       :2018-08-09
 * @function   :Write GRAM
 * @parameters :None
 * @retvalue   :None
******************************************************************************/
void LCD_WriteRAM_Prepare(void)
{
    LCD_WR_REG(lcddev.wramcmd);
}

/*****************************************************************************
 * @name       :void LCD_RESET(void)
 * @date       :2018-08-09
 * @function   :Reset LCD screen
 * @parameters :None
 * @retvalue   :None
******************************************************************************/
void LCD_RESET(void)
{
    LCD_RST_CLR;
    delay_ms(200);
    LCD_RST_SET;
    delay_ms(300);
}
/*****************************************************************************
 * @name       :void LCD_Clear(uint16_t Color)
 * @date       :2018-08-09
 * @function   :Full screen filled LCD screen
 * @parameters :color:Filled color
 * @retvalue   :None
******************************************************************************/
void LCD_Clear(uint16_t Color)
{
    uint32_t i, m;
    LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1);
    LCD_CS_CLR;
    LCD_RS_SET;

    for(i = 0; i < lcddev.height; i++)
    {
        for(m = 0; m < lcddev.width; m++)
        {
            SPI_WriteByte(SPI3, Color >> 8);
            SPI_WriteByte(SPI3, Color);
        }
    }

    LCD_CS_SET;
}
/*****************************************************************************
 * @name       :void LCD_RESET(void)
 * @date       :2018-08-09
 * @function   :Initialization LCD screen
 * @parameters :None
 * @retvalue   :None
******************************************************************************/
void LCD_Init(void)
{

    LCD_RESET(); //LCD 复位
//************* ST7789V初始化**********//
//    LCD_WR_REG(0x11);               //Sleep out
//    HAL_Delay(200);                //Delay 120ms
    LCD_WR_REG(0x36);
    LCD_WR_DATA(0x00);
    
    LCD_WR_REG(0x3A);
    LCD_WR_DATA(0x05);  //0x05( 65K Color)
    
    LCD_WR_REG(0xB2);
    LCD_WR_DATA(0x0C);
    LCD_WR_DATA(0x0C);
    LCD_WR_DATA(0x00);
    LCD_WR_DATA(0x33);
    LCD_WR_DATA(0x33);
    
    LCD_WR_REG(0xB7);
    LCD_WR_DATA(0x35);
    
    LCD_WR_REG(0xBB);
    LCD_WR_DATA(0x19);
    
    LCD_WR_REG(0xC0);
    LCD_WR_DATA(0x2C);
    
    LCD_WR_REG(0xC2);
    LCD_WR_DATA(0x01);
    
    LCD_WR_REG(0xC3);
    LCD_WR_DATA(0x12);
    
    LCD_WR_REG(0xC4);
    LCD_WR_DATA(0x20);
    
    LCD_WR_REG(0xC6);
    LCD_WR_DATA(0x0F);
    
    LCD_WR_REG(0xD0);
    LCD_WR_DATA(0xA4);
    LCD_WR_DATA(0xA1);
    
//    LCD_WR_REG(0xD6);
//    LCD_WR_DATA(0xA1);
    
    LCD_WR_REG(0xE0);
    LCD_WR_DATA(0xD0);
    LCD_WR_DATA(0x04);
    LCD_WR_DATA(0x0D);
    LCD_WR_DATA(0x11);
    LCD_WR_DATA(0x13);
    LCD_WR_DATA(0x2B);
    LCD_WR_DATA(0x3F);
    LCD_WR_DATA(0X53);
    LCD_WR_DATA(0x4C);
    LCD_WR_DATA(0x08);
    LCD_WR_DATA(0x0D);
    LCD_WR_DATA(0x0B);
    LCD_WR_DATA(0x1F);
    LCD_WR_DATA(0x23);
    
    LCD_WR_REG(0xE1);
    LCD_WR_DATA(0xD0);
    LCD_WR_DATA(0x04);
    LCD_WR_DATA(0x0C);
    LCD_WR_DATA(0x11);
    LCD_WR_DATA(0x13);
    LCD_WR_DATA(0x2C);
    LCD_WR_DATA(0x3F);
    LCD_WR_DATA(0x44);
    LCD_WR_DATA(0x51);
    LCD_WR_DATA(0x2F);
    LCD_WR_DATA(0x1F);
    LCD_WR_DATA(0x1F);
    LCD_WR_DATA(0x20);
    LCD_WR_DATA(0x23);

    LCD_WR_REG(0x21);
    LCD_WR_REG(0x11);

    LCD_WR_REG(0x29);     //Display on


    LCD_direction(USE_HORIZONTAL);//设置LCD显示方向
    LCD_LED = 1; //点亮背光
    LCD_Clear(WHITE);//清全屏白色
}
/*****************************************************************************
 * @name       :void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
 * @date       :2018-08-09
 * @function   :Setting LCD display window
 * @parameters :xStar:the bebinning x coordinate of the LCD display window
								yStar:the bebinning y coordinate of the LCD display window
								xEnd:the endning x coordinate of the LCD display window
								yEnd:the endning y coordinate of the LCD display window
 * @retvalue   :None
******************************************************************************/
void LCD_SetWindows(uint16_t xStar, uint16_t yStar, uint16_t xEnd, uint16_t yEnd)
{

    LCD_WR_REG(lcddev.setxcmd);
    LCD_WR_DATA((xStar + lcddev.xoffset) >> 8);
    LCD_WR_DATA(xStar + lcddev.xoffset);
    LCD_WR_DATA((xEnd + lcddev.xoffset) >> 8);
    LCD_WR_DATA(xEnd + lcddev.xoffset);

    LCD_WR_REG(lcddev.setycmd);
    LCD_WR_DATA((yStar + lcddev.yoffset) >> 8);
    LCD_WR_DATA(yStar + lcddev.yoffset);
    LCD_WR_DATA((yEnd + lcddev.yoffset) >> 8);
    LCD_WR_DATA(yEnd + lcddev.yoffset);

    LCD_WriteRAM_Prepare();	//开始写入GRAM
}
/*****************************************************************************
 * @name       :void LCD_direction(uint8_t direction)
 * @date       :2018-08-09
 * @function   :Setting the display direction of LCD screen
 * @parameters :direction:0-0 degree
                          1-90 degree
													2-180 degree
													3-270 degree
 * @retvalue   :None
******************************************************************************/
static void LCD_direction(uint8_t direction)
{
    lcddev.setxcmd = 0x2A;
    lcddev.setycmd = 0x2B;
    lcddev.wramcmd = 0x2C;

    switch(direction)
    {
    case 0:
        lcddev.width = LCD_W;
        lcddev.height = LCD_H;
        lcddev.xoffset = 52;
        lcddev.yoffset = 40;
        LCD_WriteReg(0x36, 0); //BGR==1,MY==0,MX==0,MV==0
        break;

    case 1:
        lcddev.width = LCD_H;
        lcddev.height = LCD_W;
        lcddev.xoffset = 40;
        lcddev.yoffset = 53;
        LCD_WriteReg(0x36, (1 << 6) | (1 << 5)); //BGR==1,MY==1,MX==0,MV==1
        break;

    case 2:
        lcddev.width = LCD_W;
        lcddev.height = LCD_H;
        lcddev.xoffset = 53;
        lcddev.yoffset = 40;
        LCD_WriteReg(0x36, (1 << 6) | (1 << 7)); //BGR==1,MY==0,MX==0,MV==0
        break;

    case 3:
        lcddev.width = LCD_H;
        lcddev.height = LCD_W;
        lcddev.xoffset = 40;
        lcddev.yoffset = 52;
        LCD_WriteReg(0x36, (1 << 7) | (1 << 5)); //BGR==1,MY==1,MX==0,MV==1
        break;

    default:
        break;
    }
}

bsp_lcd.h如下所示

 #ifndef __LCD_H
#define __LCD_H	
#include "main.h"
#include "sys.h"
//LCD重要参数集
typedef struct  
{										    
	uint16_t  width;			//LCD 宽度
	uint16_t  height;			//LCD 高度
	uint16_t  id;				//LCD ID
	uint8_t   dir;			//横屏还是竖屏控制:0,竖屏;1,横屏。	
	uint16_t  wramcmd;		//开始写gram指令
	uint16_t  setxcmd;		//设置x坐标指令
	uint16_t  setycmd;		//设置y坐标指令	
    uint8_t   xoffset;    
    uint8_t	  yoffset;
}_lcd_dev; 	

//LCD参数
/用户配置区///	 
#define USE_HORIZONTAL  	 0 //定义液晶屏顺时针旋转方向 	0-0度旋转,1-90度旋转,2-180度旋转,3-270度旋转

//	  
//定义LCD的尺寸
#define LCD_W 135
#define LCD_H 240



//-----------------LCD端口定义---------------- 

#define LED  7       //背光控制引脚
#define CS   1       //片选引脚
#define RS   0       //寄存器/数据选择引脚  
#define RST  4       //复位引脚

//QDtech全系列模块采用了三极管控制背光亮灭,用户也可以接PWM调节背光亮度
#define	LCD_LED PAout(LED) //LCD背光    

#define LCD_CS  PBout(CS)

#define LCD_RS  PBout(RS)

#define LCD_RST PBout(RST)
//如果使用官方库函数定义下列底层,速度将会下降到14帧每秒,建议采用我司推荐方法
//以下IO定义直接操作寄存器,快速IO操作,刷屏速率可以达到28帧每秒! 

#define	LCD_CS_SET  LCD_CS=1 //GPIO_TYPE->BSRRL=1<<LCD_CS    //片选端口  	PB11
#define	LCD_RS_SET	LCD_RS=1 //GPIO_TYPE->BSRRL=1<<LCD_RS    //数据/命令  PB10	  
#define	LCD_RST_SET	LCD_RST=1 //GPIO_TYPE->BSRRL=1<<LCD_RST    //复位			PB12

 							    
#define	LCD_CS_CLR  LCD_CS=0 //GPIO_TYPE->BSRRH=1<<LCD_CS     //片选端口  	PB11
#define	LCD_RS_CLR	LCD_RS=0 //GPIO_TYPE->BSRRH=1<<LCD_RS     //数据/命令  PB10	 
#define	LCD_RST_CLR	LCD_RST=0 //GPIO_TYPE->BSRRH=1<<LCD_RST    //复位			  PB12

			
//画笔颜色
#define WHITE       0xFFFF
#define BLACK      	0x0000	  
#define BLUE       	0x001F  
#define BRED        0XF81F
#define GRED 			 	0XFFE0
#define GBLUE			 	0X07FF
#define RED         0xF800
#define MAGENTA     0xF81F
#define GREEN       0x07E0
#define CYAN        0x7FFF
#define YELLOW      0xFFE0
#define BROWN 			0XBC40 //棕色
#define BRRED 			0XFC07 //棕红色
#define GRAY  			0X8430 //灰色
#define GRAY0       0xEF7D 
#define GRAY1       0x8410      	//灰色1      00000 000000 00000
#define GRAY2       0x4208 
//GUI颜色

#define DARKBLUE      	 0X01CF	//深蓝色
#define LIGHTBLUE      	 0X7D7C	//浅蓝色  
#define GRAYBLUE       	 0X5458 //灰蓝色
//以上三色为PANEL的颜色 
 
#define LIGHTGREEN     	0X841F //浅绿色
#define LIGHTGRAY     0XEF5B //浅灰色(PANNEL)
#define LGRAY 			 		0XC618 //浅灰色(PANNEL),窗体背景色

#define LGRAYBLUE      	0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE          0X2B12 //浅棕蓝色(选择条目的反色)
void LCD_Init(void);
void LCD_Clear(uint16_t Color);	 	   
void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd);
#endif 

上述的几个IO根据自己的硬件连线去修改.

开始移植

终于要开始了,墨迹了这么久了…

将下面所有文件夹内的C文件加入到MDK工程中去.

20201220212405

然后进行如下操作.

  1. lvgl-release-v6\porting目录下的lv_port_disp_templatec文件和头文件copy到工程中并改名为lv_port_disp.clv_port_disp.h文件.
  2. lvgl-release-v6目录下的lv_conf_template.h文件copy到工程中改名为lv_conf.h.
  3. 添加头文件路径.

最终我的工程目录如下所示.

20201220215712

LVGL/GUI目录下就是lvgl-release-v6\src目录下所有子目录的C文件集合.

适配工作

  1. 修改lv_conf.h文件,主要修改如下.

    • #if 0修改为#if 1

    • 修改宏为如下所示.

    #define LV_HOR_RES_MAX          (135)
    #define LV_VER_RES_MAX          (240)
    
    • 打开LV_COLOR_16_SWAP
    • 修改LV_DPI为20
    • LV_MEM_SIZE改为16*1024
    • 关闭LV_USE_GPULV_USE_FILESYSTEM
    • LV_IMG_CACHE_DEF_SIZE修改为128
    • 修改宏为如下所示
    #define LV_TICK_CUSTOM     1
    #if LV_TICK_CUSTOM == 1
    #define LV_TICK_CUSTOM_INCLUDE  "main.h"       /*Header for the sys time function*/
    #define LV_TICK_CUSTOM_SYS_TIME_EXPR (HAL_GetTick())     /*Expression evaluating to current systime in ms*/
    #endif   /*LV_TICK_CUSTOM*/
    
    • 关闭LV_USE_DEBUG
    • 关闭 LV_THEME_LIVE_UPDATE
  2. 修改lv_port_disp.c文件为如下内容.

#include "lv_port_disp.h"
#include "lcd.h"
#include "spi.h"
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);


static lv_disp_buf_t disp_buf_3;
static lv_color_t buf3_1[LV_HOR_RES_MAX * 20];            /*A screen sized buffer*/
static lv_color_t buf3_2[LV_HOR_RES_MAX * 20];            /*An other screen sized buffer*/

static lv_disp_drv_t * p_disp_drv;

void lv_port_disp_init(void)
{
    lv_disp_buf_init(&disp_buf_3, buf3_1, buf3_2, sizeof(buf3_1)/sizeof(lv_color_t));   

    lv_disp_drv_t disp_drv;                     
    lv_disp_drv_init(&disp_drv);                  

    disp_drv.flush_cb = disp_flush;
    disp_drv.buffer = &disp_buf_3;
    lv_disp_drv_register(&disp_drv);
}

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*/
    p_disp_drv = disp_drv;
    int16_t w = (area->x2 - area->x1 + 1);
    int16_t h = (area->y2 - area->y1 + 1);
    uint32_t size = w * h * 2;
    LCD_SetWindows(area->x1, area->y1, area->x2, area->y2);
    LCD_CS_CLR;
    LCD_RS_SET;
    HAL_SPI_Transmit_DMA(&hspi3,(void *)color_p,size);

}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    LCD_CS_SET;
    lv_disp_flush_ready(p_disp_drv);
}

lv_port_disp.h文件如下所示

#ifndef LV_PORT_DISP_H
#define LV_PORT_DISP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
 *      INCLUDES
 *********************/
#include "lvgl.h"
/*********************
 *      DEFINES
 *********************/
void lv_port_disp_init(void);
/**********************
 *      TYPEDEFS
 **********************/
/**********************
 * GLOBAL PROTOTYPES
 **********************/
/**********************
 *      MACROS
 **********************/
#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /*LV_PORT_DISP_H*/

这个屏幕没有触摸IC,所以不用移植lv_port_indev.c文件

  1. SysTick_Handler中断中添加函数lv_tick_inc(1).

  2. 裸机的话在main函数内添加函数lv_task_handler();,带OS的话创建一个任务以一定间隔运行该函数.

至此,结束.

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值