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

引言

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

现象

SPI可以正常发送数据,屏幕却始终不亮。
屏幕PWR(背光)始终开启,屏幕CS(spi片选)始终使能。
检查屏幕的RST(复位),波形正常。
上逻辑分析仪。
由于我的逻辑分析仪最大采样为100Mhz,这里将SPI进行256分频,频率:(50/256)Mhz
image
图中通道2为屏幕的DC引脚,DC拉低代表数据为命令,DC拉高表示数据为参数。这段应用等效代码如下:

void vST7789V3_WR_CMD(u8 cmd){
	/* 拉低DC脚 */
	LCD_DC_ON();

	/* SPI1发送数据 */
	SPI_I2S_SendData(SPI1, Byte);
	/* 等待发送区空 */
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

	/* 拉高DC脚 */
	LCD_DC_OFF();
}

分析

波形不是我们想要的,SPI还没发送完1字节,DC引脚就拉高了,显然循环等待的东西并不能判断SPI是否完成。
查询标准库电子书
image

其中关于标志的解读,SPI_I2S_FLAG_TXE标志是发送区空标志,SPI_I2S_FLAG_RXNE标志是接收区不空标志。
那问题找到了,代码中仅仅判断了发送区为空就把DC拉高了,而此时SPI并没有发送完。即,SPI_I2S_FLAG_TXE标志不能判断SPI发送完成。
如何判断SPI发送完成呢?列出的标志里没有这一项。参考标准库中的例程,写法如下:
文件:spi_flash.c

/**
  * @brief  Sends a Half Word through the SPI interface and return the Half Word
  *         received from the SPI bus.
  * @param  HalfWord: Half Word to send.
  * @retval The value of the received Half Word.
  */
uint16_t sFLASH_SendHalfWord(uint16_t HalfWord)
{
  /*!< Loop while DR register in not empty */
  while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);

  /*!< Send Half Word through the sFLASH peripheral */
  SPI_I2S_SendData(sFLASH_SPI, HalfWord);

  /*!< Wait to receive a Half Word */
  while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_RXNE) == RESET);

   /*!< Return the Half Word read from the SPI bus */
  return SPI_I2S_ReceiveData(sFLASH_SPI);
}

这里是先等待发送区为空,然后发送数据,最后等待接收区为非空,接收区为空即表示发送也同时完成了,可以将该位作为发送完成标志位。
由于使用了接收标志,所以spi必须设置为全双工模式,在单线发送模式下,SPI_I2S_FLAG_RXNE标志一直不会置位,就无法判断发送完成。

解决方案

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配置全双工模式,如果不想使用MISO端口,在GPIO配置时,不配MISO即可,不能使用单线发送模式。
对于数据量小,使用频繁的SPI发送,使用这种直接发送的方式。对于数据量大,使用相对不频繁,速度要求较快的地方,使用DMA方式发送。

posted @   起振电容  阅读(1063)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示