一、前言
在使用 SDK 的 SPI 例程的时候,偶然发现在多次发送单个字节的情况下,会出现只发了一个字节的情况。详情看下面代码。
static uint8_t TxData=0x45;
static uint8_t rxData=0;
masterXfer.txData = (uint8_t *)(&TxData);
masterXfer.rxData = (uint8_t *)(&rxData);
masterXfer.dataSize = 1;
masterXfer.configFlags =
EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);
masterXfer.txData = (uint8_t *)(&TxData);
masterXfer.rxData = (uint8_t *)(&rxData);
masterXfer.dataSize = 1;
masterXfer.configFlags =
EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);
每一次发送都只发一个字节,发两次,然后这个过程每 20ms 重复一次,然后抓到的 SPI 波形就如下图。
每次都只出来第一个 0x45,后面那个就没发出来
然后简单修改一下代码
这样就两个 0x45 都出来了,这样看似解决了问题,但是貌似这个 API 就不好用了。
二、解析
通常在使用 SPI 配置某些传感器或者设备的时候,指令会是一个 Byte,然后还要从从机那里接收回应,看看有没有写入成功,如果我们直接把接收数据的指针直接改为空,那就不知道是不是配置成功了。
进入发送函数的底层。
LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);
可以看到在最后有一个判断。
/*Read out the RX data in FIFO*/
if (rxData != NULL)
{
while (rxRemainingByteCount > 0U)
{
#if SPI_RETRY_TIMES
waitTimes = SPI_RETRY_TIMES;
while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U))
#else
while (LPSPI_GetRxFifoCount(base) != 0U)
#endif
{
readData = LPSPI_ReadData(base);
if (rxRemainingByteCount < bytesEachRead)
{
bytesEachRead = (uint8_t)rxRemainingByteCount;
}
LPSPI_SeparateReadData(rxData, readData, bytesEachRead, isByteSwap);
rxData += bytesEachRead;
rxRemainingByteCount -= bytesEachRead;
}
#if SPI_RETRY_TIMES
if (waitTimes == 0U)
{
return kStatus_LPSPI_Timeout;
}
#endif
}
}
else
{
/* If no RX buffer, then transfer is not complete until transfer complete flag sets */
#if SPI_RETRY_TIMES
waitTimes = SPI_RETRY_TIMES;
while (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U) && (--waitTimes != 0U))
#else
while ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U)
#endif
{
}
#if SPI_RETRY_TIMES
if (waitTimes == 0U)
{
return kStatus_LPSPI_Timeout;
}
#endif
}
可以看到在最后有一个判断,如果接收数据的指针不为空,就从 FIFO 里面读取数据,然后就完成这次的通信过程,如果是空的,就是说这次是单发不接收,那就等待发送完成标志置位,然后结束这次通信过程。有没有觉得少了什么。
就是接收指针不为空的时候,并没有等待发送完成的这个过程,也就是说这次过程直接就结束了,不知道有没有发送完成。
所以问题出在这里,需要在这里补上,等待发送完成的过程,等发完了才能退出,返回 success,不是直接退出。
这个时候,就算接收指针不为空,也可以正确地发出去数据了。如下图所示。
三、总结
本文总结了一个 RT1020 SPI 阻塞发送,发送不正常问题的解决过程。
四、参考资料
1、NXP SDK(可自行到官网下载)
评论