SPI中断收取数据不全问题

公告

大中华汽车电子生态圈社区并入开发者社区- 更多资讯点击此

Tip / 登入 to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Lin_Qiang
Level 4
Level 4
5 likes given First like given 50 replies posted

我使用SPI(Slave端)一次性接收138Bytes数据,但是FIFO最大也只能是16Bytes(应该是这样吧?),所以为了保证Master端和Slave端都能接收到完整的138Bytes数据,我在中断里对Tx和Rx的FIFO进行实时操作,不断填充和取出数据,但是出现了SPI数据接收不全的问题,比如138Bytes只能接收到120个左右,然后我怀疑中断处理的时间可能过长,但是实在也没法再缩减了,处理内容不是很多,所以我把时钟HFClk和SysClk从24MHz改成了32MHz,问题是解决了,但是我改成更高的时钟48MHz,发现又不好用了,这是为什么呢?有什么好的办法来处理一次性接收138Bytes数据的问题吗?

0 点赞
1 解答
LinglingG_46
Moderator
Moderator
Moderator
500 solutions authored 1000 replies posted 10 questions asked

你看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);
}

 

 

 

在原帖中查看解决方案

0 点赞
9 回复数
LinglingG_46
Moderator
Moderator
Moderator
500 solutions authored 1000 replies posted 10 questions asked

你从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);

}

 

0 点赞
Lin_Qiang
Level 4
Level 4
5 likes given First like given 50 replies posted

我看过这个例程,如果我是从机,接收主机的138Bytes数据的同时也发送138Bytes数据给主机能做到吗?SPI通信是个交换的过程,就是说从机接收一个Byte的同时填充一个Byte数据给主机,连续138个Byte。

0 点赞
LinglingG_46
Moderator
Moderator
Moderator
500 solutions authored 1000 replies posted 10 questions asked

你看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);
}

 

 

 

0 点赞
Lin_Qiang
Level 4
Level 4
5 likes given First like given 50 replies posted

多谢回复,但是我没太明白SPIS_SpiUartPutArray这个函数是怎么将138Bytes数据传输给Master的,需要做中断处理吗?因为从截取的波形来看,调用SPIS_SpiUartPutArray能保证的最大有效数据只有16Bytes,其他都是FF。

0 点赞
LinglingG_46
Moderator
Moderator
Moderator
500 solutions authored 1000 replies posted 10 questions asked

 void SPIS_SpiUartPutArray(const uint8 wrBuf[], uint32 count)这个函数没有保证16个字节这一说。你之所有会提出上面一个问题,是因为你在你的组件里面没有配置你TX buffer的大小,你配置成138个字节就可以了。

SPI的通信中不管是读或者写,都是主机操作完成的,从机读就是直接读buffer,但是这个数据也是主机发送的,从机如果写,只是需要准备好buffer的数据,然后主机还是通过写来获得。SPI的通信就是:主机发送一个字节,那么从机获得一个字节的同时,会从发送buffer里面挤出去一个字节给主机。所以一个管脚叫MISO,另外一个叫MOSI,希望我的解释可以解决你对这个通信的一些困惑。

 

0 点赞
Lin_Qiang
Level 4
Level 4
5 likes given First like given 50 replies posted

我理解你的意思,组件里我是这样配置的,Tx的buff大小设置成150.

Li_Qiang_0-1615880106203.png

我不知道哪里出了问题,下面是我测试的波形,在接收Master前我调用了SPIS1_SpiUartPutArray(wubSPIAppSendBuff_a,138);这个函数,后面的数据都是FF。

Li_Qiang_2-1615880431025.png

 

Li_Qiang_1-1615880294066.png

 

 

 

0 点赞
Lin_Qiang
Level 4
Level 4
5 likes given First like given 50 replies posted

我虽然用SPIS1_SpiUartPutArray这个函数放了138个byte数据,但是FIFO是16byte,你的意思是FIFO数据都被读取完毕后,138byte的buff会自动往FIFO中填入数据吗?

0 点赞
LinglingG_46
Moderator
Moderator
Moderator
500 solutions authored 1000 replies posted 10 questions asked

简单的理解就是:你不要管fifo,在这个知识点上面fifo和buffer没有区别。如果你想深究,你可以看一下这个函数的函数体是怎么写的:

void SPIS_SpiUartWriteTxData(uint32 txData)

如果设置的buffer小于fifo,那么直接往寄存器里面写就可以了,如果大于,也就是使能了软件buffer,这个时候分了两段。

你可以直接用我们polling的工程进行测试,把3个字节改到138个字节就可以了,但是把头和尾,还有总字节这些宏定义要改掉。

 

0 点赞
Lin_Qiang
Level 4
Level 4
5 likes given First like given 50 replies posted

明白了,谢谢。

0 点赞