我使用SPI(Slave端)一次性接收138Bytes数据,但是FIFO最大也只能是16Bytes(应该是这样吧?),所以为了保证Master端和Slave端都能接收到完整的138Bytes数据,我在中断里对Tx和Rx的FIFO进行实时操作,不断填充和取出数据,但是出现了SPI数据接收不全的问题,比如138Bytes只能接收到120个左右,然后我怀疑中断处理的时间可能过长,但是实在也没法再缩减了,处理内容不是很多,所以我把时钟HFClk和SysClk从24MHz改成了32MHz,问题是解决了,但是我改成更高的时钟48MHz,发现又不好用了,这是为什么呢?有什么好的办法来处理一次性接收138Bytes数据的问题吗?
已解决! 转到解答。
- 标签:
-
PSoC 4 MCU
- 标记:
- SPI中断接收数据不全
你看polling的那个code example:
从机回给主机的数据准备:(按照你的需求,这里可能要准备138个字节的数据)
static void SPIS_UpdateStatus(uint32 status)
{
/* Put data into the slave TX buffer to be transferred while following
master access. */
static uint8 sTxBuffer[PACKET_SIZE] = {PACKET_SOP, STS_CMD_FAIL, PACKET_EOP};
sTxBuffer[PACKET_CMD_POS] = (uint8) status;
SPIS_SpiUartPutArray(sTxBuffer, PACKET_SIZE);
}
主机读取的时候会发送138个字节,然后才能获得138个字节数据,你可以不发dummy数据,而是发有用的138个字节的数据,这样你主机也同时可以收到138个字节的数据。按照spi的通信原理,主机发送138个字节的数据,同时一定会收到138个字节的数据,你这里要做的事是如何获得你想要的数据。
static uint32 SPIM_ReadStatusPacket(void)
{
uint8 tmpBuffer[PACKET_SIZE];
uint8 status;
uint8 i = 0;
/* Start transfer */
SPIM_SpiUartPutArray(dummyBuffer, PACKET_SIZE);
/* Wait for the end of the transfer. The number of transmitted data
* elements has to be equal to the number of received data elements. */
while (PACKET_SIZE != SPIM_SpiUartGetRxBufferSize());
/* Clear dummy bytes from TX buffer */
SPIM_SpiUartClearTxBuffer();
/* Read data from the RX buffer */
while(0u != SPIM_SpiUartGetRxBufferSize())
{
tmpBuffer[i] = (uint8) SPIM_SpiUartReadRxData();
i++;
}
/* Clears the Rx buffer after reading it */
SPIM_SpiUartClearRxBuffer();
/* Check packet format */
if ((tmpBuffer[PACKET_SOP_POS] == PACKET_SOP) &&
(tmpBuffer[PACKET_EOP_POS] == PACKET_EOP))
{
/* Return status */
status = tmpBuffer[PACKET_STS_POS];
}
else
{
/* Invalid packet format, return fail status */
status = STS_CMD_FAIL;
}
return ((uint32)status);
}
你从PSoC Creator中直接找SPI的示例。如果你是主机发送138个字节你,你就把138个字节都收下来再处理。
void Slave_ISR()
{
uint8 i = 0u;
/* Sets global flag for use by background thread */
flag = 1;
set_r /* Waits for the end of the data transfer */
while (PACKET_SIZE != SPIS_SpiUartGetRxBufferSize());
/* Moves data from the Rx buffer into array */
while (0u != SPIS_SpiUartGetRxBufferSize())
{
tmpBuffer[i] = (uint8) SPIS_SpiUartReadRxData();
i++;
}
/* Clears out the Rx buffer */
SPIS_SpiUartClearRxBuffer();
/* Clears the interrupt source */
SPIS_ClearRxInterruptSource(SPIS_INTR_RX_NOT_EMPTY);
}
你看polling的那个code example:
从机回给主机的数据准备:(按照你的需求,这里可能要准备138个字节的数据)
static void SPIS_UpdateStatus(uint32 status)
{
/* Put data into the slave TX buffer to be transferred while following
master access. */
static uint8 sTxBuffer[PACKET_SIZE] = {PACKET_SOP, STS_CMD_FAIL, PACKET_EOP};
sTxBuffer[PACKET_CMD_POS] = (uint8) status;
SPIS_SpiUartPutArray(sTxBuffer, PACKET_SIZE);
}
主机读取的时候会发送138个字节,然后才能获得138个字节数据,你可以不发dummy数据,而是发有用的138个字节的数据,这样你主机也同时可以收到138个字节的数据。按照spi的通信原理,主机发送138个字节的数据,同时一定会收到138个字节的数据,你这里要做的事是如何获得你想要的数据。
static uint32 SPIM_ReadStatusPacket(void)
{
uint8 tmpBuffer[PACKET_SIZE];
uint8 status;
uint8 i = 0;
/* Start transfer */
SPIM_SpiUartPutArray(dummyBuffer, PACKET_SIZE);
/* Wait for the end of the transfer. The number of transmitted data
* elements has to be equal to the number of received data elements. */
while (PACKET_SIZE != SPIM_SpiUartGetRxBufferSize());
/* Clear dummy bytes from TX buffer */
SPIM_SpiUartClearTxBuffer();
/* Read data from the RX buffer */
while(0u != SPIM_SpiUartGetRxBufferSize())
{
tmpBuffer[i] = (uint8) SPIM_SpiUartReadRxData();
i++;
}
/* Clears the Rx buffer after reading it */
SPIM_SpiUartClearRxBuffer();
/* Check packet format */
if ((tmpBuffer[PACKET_SOP_POS] == PACKET_SOP) &&
(tmpBuffer[PACKET_EOP_POS] == PACKET_EOP))
{
/* Return status */
status = tmpBuffer[PACKET_STS_POS];
}
else
{
/* Invalid packet format, return fail status */
status = STS_CMD_FAIL;
}
return ((uint32)status);
}
void SPIS_SpiUartPutArray(const uint8 wrBuf[], uint32 count)这个函数没有保证16个字节这一说。你之所有会提出上面一个问题,是因为你在你的组件里面没有配置你TX buffer的大小,你配置成138个字节就可以了。
SPI的通信中不管是读或者写,都是主机操作完成的,从机读就是直接读buffer,但是这个数据也是主机发送的,从机如果写,只是需要准备好buffer的数据,然后主机还是通过写来获得。SPI的通信就是:主机发送一个字节,那么从机获得一个字节的同时,会从发送buffer里面挤出去一个字节给主机。所以一个管脚叫MISO,另外一个叫MOSI,希望我的解释可以解决你对这个通信的一些困惑。
简单的理解就是:你不要管fifo,在这个知识点上面fifo和buffer没有区别。如果你想深究,你可以看一下这个函数的函数体是怎么写的:
void SPIS_SpiUartWriteTxData(uint32 txData)
如果设置的buffer小于fifo,那么直接往寄存器里面写就可以了,如果大于,也就是使能了软件buffer,这个时候分了两段。
你可以直接用我们polling的工程进行测试,把3个字节改到138个字节就可以了,但是把头和尾,还有总字节这些宏定义要改掉。