HLK-W801开发-LVGL图像库移植,并驱动GC9A01圆形屏幕

移植后的效果如上图所示,采用的LVGL版本是8.2,接下来是详细的移植过程。

项目来源简单介绍

某天在某宝瞎逛时,突然发现一款单片机,最小系统板只有9.9,这不正好戳中老夫穷逼的心,想到就现在就一块F103最小系统板也得要20、30元,而且仔细一看主频240M,支持WiFi/蓝牙,好家伙我直呼太香,于是果断入手。

主控芯片介绍

W801 芯片是基于平头哥XT804内核设计的soc芯片,支持2.4G IEEE802.11b/g/n Wi-Fi 通讯协议;支持 BT/BLE 双模工作模式,支持 BT/BLE4.2 协议。芯片集成32位 CPU 处理器,内置丰富数字接口;支持TEE安全引擎,支持多种硬件加解密算法,内置DSP、浮点运算单元与安全引擎,支持代码安全权限设置,内置2MBFlash存储器,支持固件加密存储、固件签名,适用于用于智能家居等广泛的物联网领域。

圆形屏幕

选择的是优信电子店铺下的,驱动芯片是GC9A01。

项目目标

最终是希望在W801芯片上实现开源项目SmartKonb智能旋钮开源项目的效果(其实做不到。。。)。

平台搭建和代码准备

1、安装剑池CDK

在平头哥官网下载,国产软件安装都很简单,几乎就是下一步,也没有破解的操作,直接上手就能用。

下载地址:https://occ.t-head.cn/product?id=3864775351511420928&type=soft

2、下载串口烧录软件

去联盛德官网搜W800,找到下面的页面,下载Upgrade_Tools_V1.4.8,无需安装,解压双击就能运行:

下载地址:https://www.winnermicro.com/html/1/156/158/558.html

3、下载W800SDK代码

我使用的是在海凌科官网下载的wm_sdk_w80x_20211115,解压到本地后,在wm_sdk_w80x_20211115\tools\w800\projects\SDK_Project\project\CDK_WS\W800_SDK目录下找到W800_SDK.cdkproj,双击打开工程项目。

下载地址:https://www.hlktech.com/Goods-199.html

4、下载LVGL-8.2和驱动代码代码

命令:git clone --recurse-submodules https://github.com/lvgl/lv_sim_visual_studio.git -b release/v8.2 
命令:git clone --recurse-submodules https://github.com/lvgl/lv_drivers.git -b release/v8.2

代码移植过程

1、前期代码准备

在wm_sdk_w80x_20211115目录下新建一个lvgl文件夹,将lvgl库下的src,examples文件夹和lvgl.h、lvgl_conf_template.h文件复制到新建目录下,并将lvgl_conf_template.h重命名为lvgl_conf.h

在examples目录下的porting文件夹中,将 lv_port_disp_template.c和lv_port_disp_template.h文件复制到lvgl目录下,并删除命名中的_template,删除porting文件夹。最终如下图所示:

 2、代码编写

2.1、将LVGL库加载进入项目下

在CDK编辑器下,左侧项目结构右键选择Add Source Folder,并选择刚刚新建的lvgl目录,点击添加即可。

 2.2、SPI驱动代码

在工程项目src目录下右键选择新建文件lcd.h  lcd.c  lcd_spi_dirver.h  lcd_spi_driver.c  四个文件 ,如下图所示:

 代码如下

lcd.h

#ifndef _LCD_H_
#define _LCD_H_
#include "lcd.h"
#include "wm_gpio_afsel.h"

#define LCD_SCL        	WM_IO_PB_15 //--->>TFT --SCL
#define LCD_SDA        	WM_IO_PB_17 //--->>TFT --SDA
#define LCD_RST     	WM_IO_PB_24	//--->>TFT --RST
#define LCD_DC         	WM_IO_PB_25	//--->>TFT --RS/DC
#define LCD_CS        	WM_IO_PB_14 //--->>TFT --CS
#define LCD_BL        	WM_IO_PB_27 //--->>TFT --BL

#define LCD_DC_SET   do{ tls_gpio_write(LCD_DC, 1);} while(0)   
#define LCD_LED_SET  do{ tls_gpio_write(LCD_BL, 1);} while(0)   
#define LCD_RST_SET  do{ tls_gpio_write(LCD_RST,1);} while(0)  

#define LCD_DC_CLR   do{ tls_gpio_write(LCD_DC, 0);} while(0) 
#define LCD_LED_CLR  do{ tls_gpio_write(LCD_BL, 0);} while(0)   
#define LCD_RST_CLR  do{ tls_gpio_write(LCD_RST,0);} while(0)     


#define X_MAX_PIXEL	        (128)
#define Y_MAX_PIXEL	        (160)


#define RED  	0xF800
#define GREEN	0x07E0
#define BLUE 	0x001F
#define WHITE	0xFFFF
#define BLACK	0x0000
#define YELLOW  0xFFE0
#define GRAY0   0xEF7D   	    
#define GRAY1   0x8410      	
#define GRAY2   0x4208      	


void LCD_GpioInit(void);

void LCD_Reset(void);

void LCD_Back_On(void);

void LCD_Back_Off(void);

void LCD_Init(void);


void LCD_Address_Set(u16 x_start, u16 y_start, u16 x_end, u16 y_end);

void LCD_Fill(u16 x_start, u16 y_start, u16 x_end, u16 y_end, u16 color);

void LCD_Clear(u16 Color);


#endif

lcd.c

​

#include "wm_include.h"
#include "lcd.h"
#include "wm_gpio_afsel.h"
#include "lcd_spi_driver.h"
#include "string.h"

/* GC9A01 Commands that we know of.  Limited documentation */
#define GC9A01_INVOFF		0x20
#define GC9A01_INVON		0x21
#define GC9A01_DISPON		0x29
#define GC9A01_CASET		0x2A
#define GC9A01_RASET		0x2B
#define GC9A01_RAMWR		0x2C
#define GC9A01_COLMOD		0x3A
#define GC9A01_MADCTL		0x36
#define GC9A01_MADCTL_MY  	0x80
#define GC9A01_MADCTL_MX  	0x40
#define GC9A01_MADCTL_MV  	0x20
#define GC9A01_MADCTL_RGB 	0x00
#define GC9A01_DISFNCTRL	0xB6

/**********************
 *      TYPEDEFS
 **********************/

/* Init script function */
struct GC9A01_function {
	uint16_t cmd;
	uint16_t data;
};

/* Init script commands */
enum GC9A01_cmd {
	GC9A01_START,
	GC9A01_END,
	GC9A01_CMD,
	GC9A01_DATA,
	GC9A01_DELAY
};


// Documentation on op codes for GC9A01 are very hard to find.
// Will document should they be found.
static struct GC9A01_function GC9A01_cfg_script[] = {
	{ GC9A01_START, GC9A01_START},
	{ GC9A01_CMD, 0xEF},

	{ GC9A01_CMD, 0xEB},
	{ GC9A01_DATA, 0x14},

	{ GC9A01_CMD, 0xFE}, // Inter Register Enable1
	{ GC9A01_CMD, 0xEF}, // Inter Register Enable2

	{ GC9A01_CMD, 0xEB},
	{ GC9A01_DATA, 0x14},

	{ GC9A01_CMD, 0x84},
	{ GC9A01_DATA, 0x40},

	{ GC9A01_CMD, 0x85},
	{ GC9A01_DATA, 0xFF},

	{ GC9A01_CMD, 0x86},
	{ GC9A01_DATA, 0xFF},

	{ GC9A01_CMD, 0x87},
	{ GC9A01_DATA, 0xFF},

	{ GC9A01_CMD, 0x88},
	{ GC9A01_DATA, 0x0A},

	{ GC9A01_CMD, 0x89},
	{ GC9A01_DATA, 0x21},

	{ GC9A01_CMD, 0x8A},
	{ GC9A01_DATA, 0x00},

	{ GC9A01_CMD, 0x8B},
	{ GC9A01_DATA, 0x80},

	{ GC9A01_CMD, 0x8C},
	{ GC9A01_DATA, 0x01},

	{ GC9A01_CMD, 0x8D},
	{ GC9A01_DATA, 0x01},

	{ GC9A01_CMD, 0x8E},
	{ GC9A01_DATA, 0xFF},

	{ GC9A01_CMD, 0x8F},
	{ GC9A01_DATA, 0xFF},

	{ GC9A01_CMD, GC9A01_DISFNCTRL}, // Display Function Control
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x00},

	{ GC9A01_CMD, GC9A01_MADCTL}, // Memory Access Control
	{ GC9A01_DATA, 0x48}, // Set the display direction 0,1,2,3	four directions

	{ GC9A01_CMD, GC9A01_COLMOD}, // COLMOD: Pixel Format Set
	{ GC9A01_DATA, 0x05}, // 16 Bits per pixel

	{ GC9A01_CMD, 0x90},
	{ GC9A01_DATA, 0x08},
	{ GC9A01_DATA, 0x08},
	{ GC9A01_DATA, 0x08},
	{ GC9A01_DATA, 0x08},

	{ GC9A01_CMD, 0xBD},
	{ GC9A01_DATA, 0x06},

	{ GC9A01_CMD, 0xBC},
	{ GC9A01_DATA, 0x00},

	{ GC9A01_CMD, 0xFF},
	{ GC9A01_DATA, 0x60},
	{ GC9A01_DATA, 0x01},
	{ GC9A01_DATA, 0x04},

	{ GC9A01_CMD, 0xC3}, // Power Control 2
	{ GC9A01_DATA, 0x13},
	{ GC9A01_CMD, 0xC4}, // Power Control 3
	{ GC9A01_DATA, 0x13},

	{ GC9A01_CMD, 0xC9}, // Power Control 4
	{ GC9A01_DATA, 0x22},

	{ GC9A01_CMD, 0xBE},
	{ GC9A01_DATA, 0x11},

	{ GC9A01_CMD, 0xE1},
	{ GC9A01_DATA, 0x10},
	{ GC9A01_DATA, 0x0E},

	{ GC9A01_CMD, 0xDF},
	{ GC9A01_DATA, 0x21},
	{ GC9A01_DATA, 0x0C},
	{ GC9A01_DATA, 0x02},

	{ GC9A01_CMD, 0xF0}, // SET_GAMMA1
	{ GC9A01_DATA, 0x45},
	{ GC9A01_DATA, 0x09},
	{ GC9A01_DATA, 0x08},
	{ GC9A01_DATA, 0x08},
	{ GC9A01_DATA, 0x26},
	{ GC9A01_DATA, 0x2A},

	{ GC9A01_CMD, 0xF1}, // SET_GAMMA2
	{ GC9A01_DATA, 0x43},
	{ GC9A01_DATA, 0x70},
	{ GC9A01_DATA, 0x72},
	{ GC9A01_DATA, 0x36},
	{ GC9A01_DATA, 0x37},
	{ GC9A01_DATA, 0x6F},

	{ GC9A01_CMD, 0xF2}, // SET_GAMMA3
	{ GC9A01_DATA, 0x45},
	{ GC9A01_DATA, 0x09},
	{ GC9A01_DATA, 0x08},
	{ GC9A01_DATA, 0x08},
	{ GC9A01_DATA, 0x26},
	{ GC9A01_DATA, 0x2A},

	{ GC9A01_CMD, 0xF3}, // SET_GAMMA4
	{ GC9A01_DATA, 0x43},
	{ GC9A01_DATA, 0x70},
	{ GC9A01_DATA, 0x72},
	{ GC9A01_DATA, 0x36},
	{ GC9A01_DATA, 0x37},
	{ GC9A01_DATA, 0x6F},

	{ GC9A01_CMD, 0xED},
	{ GC9A01_DATA, 0x1B},
	{ GC9A01_DATA, 0x0B},

	{ GC9A01_CMD, 0xAE},
	{ GC9A01_DATA, 0x77},

	{ GC9A01_CMD, 0xCD},
	{ GC9A01_DATA, 0x63},

	{ GC9A01_CMD, 0x70},
	{ GC9A01_DATA, 0x07},
	{ GC9A01_DATA, 0x07},
	{ GC9A01_DATA, 0x04},
	{ GC9A01_DATA, 0x0E},
	{ GC9A01_DATA, 0x0F},
	{ GC9A01_DATA, 0x09},
	{ GC9A01_DATA, 0x07},
	{ GC9A01_DATA, 0x08},
	{ GC9A01_DATA, 0x03},

	{ GC9A01_CMD, 0xE8},
	{ GC9A01_DATA, 0x34},

	{ GC9A01_CMD, 0x62},
	{ GC9A01_DATA, 0x18},
	{ GC9A01_DATA, 0x0D},
	{ GC9A01_DATA, 0x71},
	{ GC9A01_DATA, 0xED},
	{ GC9A01_DATA, 0x70},
	{ GC9A01_DATA, 0x70},
	{ GC9A01_DATA, 0x18},
	{ GC9A01_DATA, 0x0F},
	{ GC9A01_DATA, 0x71},
	{ GC9A01_DATA, 0xEF},
	{ GC9A01_DATA, 0x70},
	{ GC9A01_DATA, 0x70},

	{ GC9A01_CMD, 0x63},
	{ GC9A01_DATA, 0x18},
	{ GC9A01_DATA, 0x11},
	{ GC9A01_DATA, 0x71},
	{ GC9A01_DATA, 0xF1},
	{ GC9A01_DATA, 0x70},
	{ GC9A01_DATA, 0x70},
	{ GC9A01_DATA, 0x18},
	{ GC9A01_DATA, 0x13},
	{ GC9A01_DATA, 0x71},
	{ GC9A01_DATA, 0xF3},
	{ GC9A01_DATA, 0x70},
	{ GC9A01_DATA, 0x70},

	{ GC9A01_CMD, 0x64},
	{ GC9A01_DATA, 0x28},
	{ GC9A01_DATA, 0x29},
	{ GC9A01_DATA, 0xF1},
	{ GC9A01_DATA, 0x01},
	{ GC9A01_DATA, 0xF1},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x07},

	{ GC9A01_CMD, 0x66},
	{ GC9A01_DATA, 0x3C},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0xCD},
	{ GC9A01_DATA, 0x67},
	{ GC9A01_DATA, 0x45},
	{ GC9A01_DATA, 0x45},
	{ GC9A01_DATA, 0x10},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x00},

	{ GC9A01_CMD, 0x67},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x3C},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x01},
	{ GC9A01_DATA, 0x54},
	{ GC9A01_DATA, 0x10},
	{ GC9A01_DATA, 0x32},
	{ GC9A01_DATA, 0x98},

	{ GC9A01_CMD, 0x74},
	{ GC9A01_DATA, 0x10},
	{ GC9A01_DATA, 0x85},
	{ GC9A01_DATA, 0x80},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x00},
	{ GC9A01_DATA, 0x4E},
	{ GC9A01_DATA, 0x00},

	{ GC9A01_CMD, 0x98},
	{ GC9A01_DATA, 0x3E},
	{ GC9A01_DATA, 0x07},

	{ GC9A01_CMD, 0x35}, // Tearing Effect Line ON
	{ GC9A01_CMD, 0x21}, // Display Inversion ON

	{ GC9A01_CMD, 0x11}, // Sleep Out Mode
	{ GC9A01_DELAY, 120},
	{ GC9A01_CMD, GC9A01_DISPON}, // Display ON
	{ GC9A01_DELAY, 255},
	{ GC9A01_END, GC9A01_END},
};


//液晶IO初始化配置
void LCD_GpioInit(void)
{
	int clk = 20000000;   // 2 M
	int type = 2;         // 2 DMA
	/*MASTER SPI configuratioin*/
	wm_spi_cs_config(LCD_CS);
	wm_spi_ck_config(LCD_SCL);
	wm_spi_do_config(LCD_SDA);

	tls_gpio_cfg(LCD_BL, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
	tls_gpio_cfg(LCD_DC,  WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
	tls_gpio_cfg(LCD_RST, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
	
	tls_spi_trans_type(SPI_DMA_TRANSFER);
    tls_spi_setup(TLS_SPI_MODE_3, TLS_SPI_CS_LOW, clk);	
	
}

void LCD_Reset(void)
{
	LCD_RST_SET;
	tls_os_time_delay(50);
	LCD_RST_CLR;
	tls_os_time_delay(50);
	LCD_RST_SET;
	tls_os_time_delay(50);
}

void LCD_Back_On(void)
{
	LCD_LED_SET;
}

void LCD_Back_Off(void)
{
	LCD_LED_CLR;
}

static void LCD_WriteReg(u8 reg)
{
	S_WriteReg(reg);
}

static void LCD_WriteData8(u8 data)
{
	S_WriteData8(data);
}

static void LCD_WriteData16(u16 data)
{
	S_WriteData16(data);
}

static void LCD_WriteData(u8 *data, u32 len)
{
	u32 t1 = 0, t2 = 0;
	
	t1 = tls_os_get_time();
	S_WriteData(data, len);
	t2 = tls_os_get_time();
	printf("s %d use %d\n", len, t2 - t1);

}
//

static void LCD_run_cfg_script(void)
{
	int i = 0;
	int end_script = 0;

	do {
		switch (GC9A01_cfg_script[i].cmd)
		{
			case GC9A01_START:
				break;
			case GC9A01_CMD:
				LCD_WriteReg( GC9A01_cfg_script[i].data & 0xFF );
				break;
			case GC9A01_DATA:
				LCD_WriteData8( GC9A01_cfg_script[i].data & 0xFF );
				break;
			case GC9A01_DELAY:
        tls_os_time_delay(GC9A01_cfg_script[i].data);
				break;
			case GC9A01_END:
				end_script = 1;
		}
		i++;
	} while (!end_script);
}

void LCD_Init(void)
{
	//初始化GPIO
	LCD_GpioInit();
	
	tls_gpio_write(LCD_CS,FALSE);
	
	LCD_Reset();
	LCD_Back_On();
	//配置GC9A01驱动
	LCD_run_cfg_script();
	
	
}

void LCD_Address_Set(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
  uint16_t x_start = x0, x_end = x1;
  uint16_t y_start = y0, y_end = y1;

  LCD_WriteReg(GC9A01_CASET); // Column addr set
  LCD_WriteData8(x_start >> 8);
  LCD_WriteData8(x_start & 0xFF);     // XSTART
  LCD_WriteData8(x_end >> 8);
  LCD_WriteData8(x_end & 0xFF);     // XEND

  LCD_WriteReg(GC9A01_RASET); // Row addr set
  LCD_WriteData8(y_start >> 8);
  LCD_WriteData8(y_start & 0xFF);     // YSTART
  LCD_WriteData8(y_end >> 8);
  LCD_WriteData8(y_end & 0xFF);     // YEND

  LCD_WriteReg(GC9A01_RAMWR);

}
// 整个屏幕填充颜色
void LCD_Clear(u16 Color)               
{		
	// LCD_Fill(0, 0, X_MAX_PIXEL, Y_MAX_PIXEL, Color);

	LCD_Address_Set(0,0,X_MAX_PIXEL-1,Y_MAX_PIXEL-1);
	LCD_WriteReg(0x2C);
	u32 total = X_MAX_PIXEL * Y_MAX_PIXEL * 2;
	u8 High_8bit = Color>>8;
	u8 Low_8bit = Color;
	u8 *data =  tls_mem_alloc(8160);

	if(data == NULL) {
		printf("mem null\n");
		return;
	}
	else {
		memset(data, Low_8bit, 8160);
		for(int i = 0; i<8160; i+=2)
		{
			data[i] = High_8bit;
		}
	}

	u16 body = total/8160;
	u16 tail = total%8160;
    if(body > 0)
	{
		do
		{
			S_WriteData((u8 *)data, 8160);
		} while (--body);
	}
	if(tail > 0)
	{
		S_WriteData((u8 *)data, tail);
	}
	tls_mem_free(data);
}

lcd_spi_driver.h

#ifndef __LCD_SPI_DRIVER_H__
#define __LCD_SPI_DRIVER_H__
#include "wm_include.h"

void S_WriteReg(u8 reg);

void S_WriteData8(u8 data);

void S_WriteData16(u16 data);

void S_WriteData(u8 *data, u32 len);

#endif

lcd_spi_driver.c

#include "wm_include.h"
#include "lcd_spi_driver.h"
#include "wm_hostspi.h"
#include "lcd.h"

void S_WriteReg(u8 reg)
{
	LCD_DC_CLR;
	tls_spi_write(&reg, 1);
	LCD_DC_SET;
}

void S_WriteData8(u8 data)
{
	tls_spi_write(&data, 1);
}

void S_WriteData16(u16 data)
{
	u8 temp[2];
	
	temp[0] = data >> 8;
	temp[1] = data;
	tls_spi_write(temp, 2);
}


static void SPI_Transmit_dma(u8 *pData, u32 Size)
{
	u32 body = Size/8160;
	u32 tail = Size%8160;
	u32 offset = 0;

	LCD_DC_SET;

	if(body > 0)
	{
		do
		{
			tls_spi_write((u8 *)pData+offset*8160, 8160);
			offset++;
		} while (--body);
	}
	tls_spi_write((u8 *)pData+(offset*8160), tail);
}

void S_WriteData(u8 *data, u32 len)
{
	SPI_Transmit_dma(data, len);
}

2.3、修改lvgl代码

修改lv_conf.h中的条件编译,将#if 0改为#if 1,启用lv_conf.h文件,且调整屏幕的颜色设置,如下图所示:

同理打开lv_port_disp.h和 lv_port_disp.c文件。并修改 lv_port_disp.c中一下几处地方:

/*********************
 *      DEFINES
 *********************/

#define MY_DISP_HOR_RES 240
#define MY_DISP_VER_RES 240    //屏幕尺寸

/**********************
 *   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*/
#if 0
    /* 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*/
#endif
    /*-----------------------------------
     * 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 = 240;
    disp_drv.ver_res = 240;

    /*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*/
#if 0
    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)*/
            color_p++;
        }
    }
#endif

	extern void LCD_Flush(lv_disp_drv_t * disp_drv,const lv_area_t * area, lv_color_t *color_p);
	LCD_Flush(disp_drv,area,color_p);
    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    //lv_disp_flush_ready(disp_drv);
}

注:移植lvgl库时有一个特殊报错,困扰我很久才解决,目前只是解决了,但不知原因是啥。

报错内容:CDK error: conflicting types for 'lv_group_set_editing'

解决办法:将报错所在位置的bool类型换成unsigned char类型即可,函数声明和函数实现都要改,如下:

void lv_group_set_editing(lv_group_t * group, unsigned char edit)

2.4、编写main函数

#include "wm_include.h"
#include "wm_cpu.h"
#include "lcd.h"
#include "wm_timer.h"
#include "../lvgl/lvgl.h"
#include "../lvgl/lv_port_disp.h"
#include "lv_examples.h"

//通过SPI接口将图形输出到屏幕端
void LCD_Flush(lv_disp_drv_t * disp_drv,const lv_area_t * area, lv_color_t *color_p)
{
	tls_gpio_write(LCD_CS,FALSE); // Listen to us

	LCD_Address_Set(area->x1, area->y1, area->x2, area->y2);
	int32_t len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;

	S_WriteData((char*)color_p, len);

	tls_gpio_write(LCD_CS,true);
	lv_disp_flush_ready(disp_drv);         /* Indicate you are ready with the flushing*/
}

static void tick_timer_irq(u8 *arg)
{
	lv_tick_inc(1);
	// printf("timer irq\n");
}

int create_tick_timer(void)
{

	u8 timer_id;
	struct tls_timer_cfg timer_cfg;
	
	timer_cfg.unit = TLS_TIMER_UNIT_MS;
	timer_cfg.timeout = 1;
	timer_cfg.is_repeat = 1;
	timer_cfg.callback = (tls_timer_irq_callback)tick_timer_irq;
	timer_cfg.arg = NULL;
	timer_id = tls_timer_create(&timer_cfg);
	tls_timer_start(timer_id);
	// printf("timer start\n");	

	return WM_SUCCESS;
}

void UserMain(void)
{
	tls_sys_clk_set(CPU_CLK_80M);//系统时钟
	
	LCD_Init(); //SPI驱动打开
	
	create_tick_timer();
	
	lv_init();
	lv_port_disp_init(); //LVGL初始化
	
	lv_example_meter_1(); //仪表示例1
    //lv_example_meter_2();    //可自行更换examples/widgets目录下的所有示例
	
	while(1){
		tls_os_time_delay(3);
		lv_task_handler();
	}
}

写在最后

国产芯片行业的崛起需要依赖市场的需求,需要每一个项目工程师的努力,时光不负赶路人,加油各位赶路人!

猜你喜欢

转载自blog.csdn.net/hellocode_7812/article/details/126817540