您现在的位置是:首页 >学无止境 >分别使用软件和硬件SPI驱动1.28寸LCD屏幕刷新时间对比(驱动IC为GC9A01)网站首页学无止境

分别使用软件和硬件SPI驱动1.28寸LCD屏幕刷新时间对比(驱动IC为GC9A01)

~狂想家~ 2023-06-11 04:00:04
简介分别使用软件和硬件SPI驱动1.28寸LCD屏幕刷新时间对比(驱动IC为GC9A01)

写在前面:
屏幕供应商提供的GC9A01驱动代码过于简陋,使用的话需要修改的东西比较多,还好看到一篇文章,而且博主分享了驱动代码。文章地址

以下软件SPI部分是通过博主分享的驱动代码得来的,稍微改一下就可以用,就不多说了。

使用起来发现使用软件模拟SPI的话,屏幕刷新速度特别慢(RGB565),刷新一张240*240的图片(115200字节,MCU主频使用40MHz),需要1秒多。然后就想着要提高一下刷新速度,先更改一下代码。

因为要操作的信号线除了SPI用到的CLK和MOSI之外,还有片选线CS,数据/寄存器选择线RS,如果直接使用HAL库的GPIO写函数的话会有冗余代码。
在这里插入图片描述
所以直接用宏定义替换HAL_GPIO_WritePin()函数,直接改GPIO寄存器。

#define LCD_RESET_HIGH     LCD_RESET_GPIO_Port->BSRR = (uint32_t)LCD_RESET_Pin;
#define LCD_RESET_LOW      LCD_RESET_GPIO_Port->BRR = (uint32_t)LCD_RESET_Pin;

#define LCD_CS_HIGH        LCD_CS_GPIO_Port->BSRR = (uint32_t)LCD_CS_Pin;
#define LCD_CS_LOW         LCD_CS_GPIO_Port->BRR = (uint32_t)LCD_CS_Pin;

#define LCD_RS_HIGH        LCD_RS_GPIO_Port->BSRR = (uint32_t)LCD_RS_Pin;
#define LCD_RS_LOW         LCD_RS_GPIO_Port->BRR = (uint32_t)LCD_RS_Pin;

#define LCD_TE_HIGH        LCD_TE_GPIO_Port->BSRR = (uint32_t)LCD_TE_Pin;
#define LCD_TE_LOW         LCD_TE_GPIO_Port->BRR = (uint32_t)LCD_TE_Pin;

#define LCD_CLK_HIGH       LCD_CLK_GPIO_Port->BSRR = (uint32_t)LCD_CLK_Pin;
#define LCD_CLK_LOW        LCD_CLK_GPIO_Port->BRR = (uint32_t)LCD_CLK_Pin;

#define LCD_MOSI_HIGH      LCD_MOSI_GPIO_Port->BSRR = (uint32_t)LCD_MOSI_Pin;
#define LCD_MOSI_LOW       LCD_MOSI_GPIO_Port->BRR = (uint32_t)LCD_MOSI_Pin;

修改之后刷新一张图片需要650ms左右,这些时间只是个大概,因为是看串口的时间戳,没有用示波器去抓,只是做个对比。

LCD_ShowPicture()和LCD_WR_DATA8()函数都有for循环,LCD_WR_DATA8()函数是通过移位来发送字节的,那么就改成不移位,直接发送。

void LCD_Writ_Bus_8(uint8_t dat) 
{
	LCD_CLK_LOW;
	if(dat&0x80)
	{
		 LCD_MOSI_HIGH;
	}
	else
	{
		 LCD_MOSI_LOW;
	}
	LCD_CLK_HIGH;
	LCD_CLK_LOW;
	if(dat&0x40)
	{
		 LCD_MOSI_HIGH;
	}
	else
	{
		 LCD_MOSI_LOW;
	}
	LCD_CLK_HIGH;
	LCD_CLK_LOW;
	if(dat&0x20)
	{
		 LCD_MOSI_HIGH;
	}
	else
	{
		 LCD_MOSI_LOW;
	}
	LCD_CLK_HIGH;
	LCD_CLK_LOW;
	if(dat&0x10)
	{
		 LCD_MOSI_HIGH;
	}
	else
	{
		 LCD_MOSI_LOW;
	}
	LCD_CLK_HIGH;
	LCD_CLK_LOW;
	if(dat&0x08)
	{
		 LCD_MOSI_HIGH;
	}
	else
	{
		 LCD_MOSI_LOW;
	}
	LCD_CLK_HIGH;
	LCD_CLK_LOW;
	if(dat&0x04)
	{
		 LCD_MOSI_HIGH;
	}
	else
	{
		 LCD_MOSI_LOW;
	}
	LCD_CLK_HIGH;
	LCD_CLK_LOW;
	if(dat&0x02)
	{
		 LCD_MOSI_HIGH;
	}
	else
	{
		 LCD_MOSI_LOW;
	}
	LCD_CLK_HIGH;
	LCD_CLK_LOW;
	if(dat&0x01)
	{
		 LCD_MOSI_HIGH;
	}
	else
	{
		 LCD_MOSI_LOW;
	}
	LCD_CLK_HIGH;	
}

这样下来刷新一张图片大概要350ms左右,相似的也可以一次发送16位,24位等,但是会发现速度基本没有提升。

		LCD_Writ_Bus_16(*(uint16_t*)(pic+i));
		LCD_Writ_Bus_32(*(uint32_t*)(pic+i));

然后就是主频的问题,原本用的40MHz,改为80MHz之后刷新一张图片大概要170ms左右。

之后就想着使用硬件SPI对比一下,SPI初始化好之后改一下原有的发送函数就可以了。

#ifdef HARDWARE_SPI
void LCD_Writ_Bus(uint8_t dat) 
{
	LCD_CS_LOW;
	HAL_SPI_Transmit(&hspi1,&dat,1,0xfff);
	LCD_CS_HIGH;
}
#else
void LCD_Writ_Bus(uint8_t dat) 
{	
	uint8_t i;
	LCD_CS_LOW;
	for(i=0;i<8;i++)
	{			  
		LCD_CLK_LOW;
		if(dat&0x80)
		{
		   LCD_MOSI_HIGH;
		}
		else
		{
		   LCD_MOSI_LOW;
		}
		LCD_CLK_HIGH;
		dat<<=1;
	}	
  LCD_CS_HIGH;
}
#endif

在显示图片函数里面将原有的两个for循环改为HAL_SPI_Transmit()函数,需要注意一下长度的问题,一共有240*240*2(115200)个字节需要发送,但是HAL_SPI_Transmit()函数参数中大小的类型为uint16_t,所以要分两次发送,另外就是要设置一下片选线CS状态。

void LCD_ShowPicture_Fast(uint16_t x,uint16_t y,uint16_t length,uint16_t width,const uint8_t pic[])
{
	uint32_t i,j;
	uint32_t k=0;
	LCD_Address_Set(x,y,x+length-1,y+width-1);
	LCD_CS_LOW;
	HAL_SPI_Transmit(&hspi1,(uint8_t *)pic,57600,0xfff);
	HAL_SPI_Transmit(&hspi1,(uint8_t *)(pic+57600),57600,0xfff);
	LCD_CS_HIGH;
}

之所以可以这么写,是因为手册中有一个连续写内存命令。
在这里插入图片描述
命令描述大概就是在写内存开始命令和连续写命令之后,会根据设置的范围自动换行或者换列,超出范围的数据会被忽略,所以就可以直接用HAL_SPI_Transmit()函数发送。在设置好显示区域之后,需要设置0x2C或者0x3C寄存器,后面直接跟数据就可以。

改为硬件SPI之后,刷新一张图片大概需要60ms左右(MCU主频使用40MHz),这么一对比的话还是直接用硬件SPI吧。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。