BUG分享|SPI接口屏幕无法点亮(SPI无法判断发送完成)

发布时间 2023-12-29 00:21:54作者: 起振电容

引言

在驱动ST7735、ST7789之类的屏幕时,明明SPI能够发送数据,可是就是点不亮,下面分享一个遇到的这种问题。
问题起因是想以最快速度驱动屏幕,由于这块屏幕只需要SPI-MOSI,所以SPI配置直接配置单线发送模式。
单片机:STM32F411CEU6
库函数:标准库

现象

SPI可以正常发送数据,屏幕却始终不亮。
屏幕PWR(背光)始终开启,屏幕CS(spi片选)始终使能。
检查屏幕的RST(复位),波形正常。

分析

上逻辑分析仪。
由于我的逻辑分析仪最大采样为100Mhz,这里将SPI进行256分频,频率:(50/256)Mhz
image
图中通道2为屏幕的DC引脚,DC拉低代表数据为命令,DC拉高表示数据为参数。可以看到数据发送前,DC拉低,数据才刚开始发送,DC就拉高了,明显不正常。这段应用代码如下:

void vST7789V3_WR_CMD(u8 cmd){
	LCD_DC_ON();
	SPI1_ReadWriteByte(cmd);;
	LCD_DC_OFF();
}

DC在SPI还没发送完成就拉高了。SPI的发送函数如下:

u8 SPI1_ReadWriteByte(u8 Byte){ //通过SPI2口发送1字节数据
	SPI_I2S_SendData(SPI1, Byte);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空
}

通过现象分析,显然while循环内的东西并不能判断SPI是否完成,百度得知SPI_I2S_FLAG_TXE标志只能标志SPI的发送区空了,可以继续往里面填下一个数据了,但此时是SPI并没有发送完全。
去找有没有发送完成标志,只找到一个SPI_I2S_FLAG_RXNE标志,用来标记SPI接收完成。可是我用的单线发送模式,这个标志位根本不会置位。百度半天,也没有什么收获。有建议直接delay,这不优雅啊。我想要的是发送完成那一刻。等等,SPI发送完成不也意味着接收完成吗?那就不能用单线模式了。

解决方案

u8 SPI1_ReadWriteByte(u8 Byte){ //通过SPI2口发送1个数据,同时接收1个数据 如果失败返回0
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空 
	SPI_I2S_SendData(SPI1, Byte); //通过外设 SPIx 发送一个byte 数据 
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完 
	return SPI_I2S_ReceiveData(SPI1); //返回通过 SPIx 最近接收的数据 
}

前提,SPI使用全双工模式。先等待SPI_I2S_FLAG_TXE置位,发送区空再填入新数据,等待SPI_I2S_FLAG_RXNE置位,才算发送完成。
不要问我既然发送完了,为什么下一次发送还要判断发送区是否空,问就是严谨。
一夜回到解放前,当初觉得我不接收为什么要判断他,还会增加时间,本来就想缩短中间步骤,以极限速度循环发送SPI,才换成单线,删掉了一些中间步骤,现在看来徒劳。
对于数据量小,使用频繁的SPI发送,使用这种直接发送的方式。对于数据量大,使用相对不频繁,速度要求较快的地方,使用DMA方式发送。