stm32硬件SPI驱动3线SPI-LCD的方法

1.基本控制原理
三线SPI LCD, 顾名思义,最少只需要3个IO控制LCD显示,如果采用硬件控制上电时序和背光,最少只需要接SCK,CS,MOSI三个引脚即可控制LCD,并且不管接不接其他引脚,控制刷屏的只需要这三个引脚;
CS为片选引脚,CS拉低代表数据传输开始;CS拉高,代表数据传输结束;
SCK为SPI时钟线,一般LCD上标识SCL;
MOSI是master数据输出,即单片机发送数据到LCD,一般LCD上标识SDA;
3线SPI-LCD与4线的唯一区别是少了一个DC引脚,DC拉低代表传输的是指令;DC拉高代表传输的是数据,3线SPI驱动需要使用MOSI模拟DC的时序;
那么使用STM32单片机驱动,很容易使用GPIO模拟SPI时序实现3线SPI-LCD的驱动,但是由于GPIO的翻转速度,就算使用寄存器操作,屏幕刷新速度也非常慢;
2.如何使用硬件SPI驱动3线SPI-LCD
本文提供两种方法使用stm32单片机实现:
(1)单字节转换后SPI发送;
所谓单字节转换后发送,就是每次只发送一个有效字节,将一个8位的数据,转换成16位,再位或0x8000,然后通过SPI发送出去,具体可以拆分成两个8bit数据发送;
具体实现如下:

unsigned char spi_send_data_8bit(unsigned char Txdata)
{
	while((SPI2->SR & SPI_I2S_FLAG_TXNE) == (uint16_t)RESET);
	 SPI2->DR=Txdata;  
	while((SPI2->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);  
	return (unsigned char)(SPI2->DR);
}

void LCD_Send_8bit(unsigned char data)
{
	cs_low;
	spi_send_data_8bit((data>>1)|0x80);
	spi_send_data_8bit(data<<7);
	cs_high;			
}

上述单字节发送在stm32F4平台,50MHz SPI下,320x240 分辨率显示能刷4fps;
320x240x2x4x8 大约有5Mbps,如果采用更小的分辨率刷10帧以上没有问题。

(2)多字节转换后发送
使用单字节发送存在一个问题,SPI 每次只能按字节发送,就算SPI速度再快,单字节发送出去也会影响性能,其次每次发送一个有效字节都存在cs的拉高拉低,极大的影响了效率。既然单字节转换后可以发送,多字节转换后当然也能发送。其原理就是每一个DC后面跟8个有效bit,使用MOSI模拟时序做数据转换;
先看看怎么一次发8个字节;

void LCD_Send_8byte(unsigned char  *send_buf,unsigned char buflen)
{

	if(send_buf==NULL||buflen!=8)
	{
		printf("param error");
		return;
	}
	unsigned char  *pbuf=send_buf;
	nsigned char lcd_buf[9]={0};
	lcd_buf[0]=0x80|(*pbuf>>1);
	lcd_buf[1]=0x40|(*pbuf<<7)|(*(pbuf+1)>>2);
	lcd_buf[2]=0x20|(*(pbuf+1)<<6)|(*(pbuf+2)>>3);
	lcd_buf[3]=0x10|(*(pbuf+2)<<5)|(*(pbuf+3)>>4);
	lcd_buf[4]=0x08|(*(pbuf+3)<<4)|(*(pbuf+4)>>5);
	lcd_buf[5]=0x04|(*(pbuf+4)<<3)|(*(pbuf+5)>>6);
	lcd_buf[6]=0x02|(*(pbuf+5)<<2)|(*(pbuf+6)>>7);
	lcd_buf[7]=0x01|(*(pbuf+6)<<1);
	lcd_buf[8]=*(pbuf+7);
	int i=0;
	 cs_low;
	 for(i=0;i<9;i++)
	 {
	 	spi_send_data_8bit(lcd_buf[i]);
	 }
	 cs_high; 
}
//使用CCM快速内存分配数据作为LCD的缓冲,如果内存足够这个缓冲也可以大一点

static int nwidth=image_width8/9*16*2//分配一个16行的缓冲

unsigned char* lcd_buf=mymalloc(SRAM_CCM,nwidth);

/*******************************

功能:lcd显示n行数据,发送RGB565

入参:图像数据指针,发送长度,LCD缓冲数据指针,长度

出参:无

*********************************/

void LCD_Send_Nwith(unsigned char  *send_buf,unsigned int send_length,unsigned char *lcd_buf,unsigned int nwidth)
{
	if((send_buf ==NULL)||((send_length%8)!=0))
	{
		printf(“param error”);
		return;
	}
	unsigned char  *pbuf=send_buf;
	unsigned char  *plcd_buf=lcd_buf;
	or(i=0;i<nwidth/9;i++)
	{
		*plcd_buf=0x80|(*pbuf>>1);
		*(plcd_buf+1)=0x40|(*pbuf<<7)|(*(pbuf+1)>>2);
		*(plcd_buf+2)=0x20|(*(pbuf+1)<<6)|(*(pbuf+2)>>3);
		*(plcd_buf+3)=0x10|(*(pbuf+2)<<5)|(*(pbuf+3)>>4);
		*(plcd_buf+4)=0x08|(*(pbuf+3)<<4)|(*(pbuf+4)>>5);
		*(plcd_buf+5)=0x04|(*(pbuf+4)<<3)|(*(pbuf+5)>>6);
		*(plcd_buf+6)=0x02|(*(pbuf+5)<<2)|(*(pbuf+6)>>7);
		*(plcd_buf+7)=0x01|(*(pbuf+6)<<1);
		*(plcd_buf+8)=(*pbuf+7);
		pbuf+=8;
		plcd_buf+=9}
		pbuf=NULL;
	plcd_buf=lcd_buf;;
	cs_low;
	while(nwidth–)
	{
		spi_send_data_8bit(*plcd_buf++);
	}
	cs_high;
	plcd_buf=NULL;
}
	```
	对应与发送8bit的有效数据,实际需要MOSI发送9bit数据,因为第一个bit代表了数据标识,那么发送任意字节长度的3线SPI数据,可以按照下面的方式:


	void LCD_Send_bytes(unsigned char *send_buf,int length) 
	{  

		if((send_buf ==NULL)||((length%8)!=0))
		{
			printf("param error \n");
			return;
		}
		int len1=length/8;
		unsigned char  *pbuf= send_buf;		
		 cs_low;  
		 while( len1--)
		  {   
		    LCD_Send_8byte(pbuf,8);		
		    pbuf+=8;
		 }   
		  cs_high;  
	} 
	
	
按照以上方式,3线SPI发送数据时可以按行进行批量发送,并且可以配置DMA进行搬运,CPU只需要处理数据转换即可;
上述单字节发送在stm32F4平台,50MHz SPI下,320x240 分辨率显示能刷到8fps;
320x240x2x8x8 大约有10Mbps,如果采用更小的分辨率刷20帧以上没有问题。

以上为全部3线SPI-LCD的硬件SPI驱动方法,下次在ESP32-CAM平台也试试,采用16bit模式会更快。















你可能感兴趣的:(openmv/梦飞智能,stm32,单片机,arm)