胡杨-409776 发表于 2013-7-23 20:25:19

SPI全双工通信主机数据接收错误——紧急求助


我采用stm F103 作为SPI的主机,stm F303作为从机,两者进行SPI通信,主机向从机发送一组数据,从机同时也向主机发送一组数据,从机和主机都是采用的中断方式,但是每次的结果,从机里面接收的数据都是正确的,主机接收的却是错误的。举个例子来说,主机发送5个数据给从机,从机也发送5个数据给主机,从机能够完全接收主机的5个数据,但主机只能接收从机的前3个数据。如主机发送a={0x01,0x02,0x03,0x04,0x05},从机发送数据b={0x21,0x22,0x23,0x24,0x25},通信完成以后,从机的接收数据是完全对的,而主机的接收数据则为a_receive={0x00,0x00,0x21,0x22,0x23};下面贴出我的程序,恳请大牛们过来指点下,不胜感激!
            从机的主函数                                    
                [*]int main(void)
[*]{
[*]/* System clocks configuration ---------------------------------------------*/
[*]RCC_Configuration();
[*]/* NVIC configuration ------------------------------------------------------*/
[*]NVIC_Configuration();
[*]/* GPIO configuration ------------------------------------------------------*/
[*]GPIO_Configuration();
[*]SPI_Config();
[*]//         /* Enable the Rx buffer not empty interrupt */
[*]   SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
[*]/* Enable SPI2 */
[*]SPI_Cmd(SPI2, ENABLE);
[*]while(1)
[*]{
[*]}
[*]}
[*]
            
            复制代码
            从机的中断函数                                    
                [*]void SPI2_IRQHandler(void)
[*]{
[*]      if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) != RESET)
[*]          {
[*]            /* Send SPI2 data */
[*]            SPI2_Buffer_Rx = SPI_I2S_ReceiveData16(SPI2);
[*]    /* Disable SPI1 TXE interrupt */
[*]         if (Rx_Idx == BufferSize)
[*]         {
[*]             SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, DISABLE);
[*]            }
[*]          }
[*]while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
[*]   /* Send SPI1 data */
[*]    SPI_I2S_SendData16(SPI2, SPI2_Buffer_Tx);
[*]
[*]}
            
            复制代码
            主机的主函数                                    
                [*]int main(void)
[*]{
[*]/* System clocks configuration ---------------------------------------------*/
[*]RCC_Configuration();
[*]/* NVIC configuration ------------------------------------------------------*/
[*]NVIC_Configuration();
[*]/* GPIO configuration ------------------------------------------------------*/
[*]GPIO_Configuration();
[*]SPI_Config();
[*]/* Enable SPI2 */
[*]          SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, ENABLE);
[*]          SPI_Cmd(SPI2, ENABLE);
[*]while(1)
[*]{
[*]}
[*]}
            
            复制代码
            主机的中断函数                                    
                [*]void SPI2_IRQHandler(void)
[*]{
[*]if(SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_TXE) != RESET);
[*]{
[*]    /* Send SPI1 data */
[*]    SPI_I2S_SendData(SPI2, SPI2_Buffer_Tx);
[*]
[*]    /* Disable SPI1 TXE interrupt */
[*]   if (Tx_Idx == BufferSize)
[*]   {
[*]       SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
[*]   }
[*]}
[*]      while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
[*]    /* Send SPI1 data */
[*]   SPI2_Buffer_Rx = SPI_I2S_ReceiveData(SPI2);
[*]}
            
            复制代码
            


胡杨-409776 发表于 2013-7-23 20:54:59

回复: SPI全双工通信主机数据接收错误——紧急求助

回复第 4 楼 于2013-07-23 20:39:57发表:
显然你的从机发送数据的流程有错误。
从机是接收SCK的,你从机RXNE中断的时候,实际上发送数据已经也同步完成了。所以你第一个RXNE中断来的时候,实际上已经发出数据了,而在之前你要发送的数据还没有送往发送缓冲区呢,导致SPI自动发出了00数据。
应该是这样的,从机将要发送的数据首先打到发送缓冲区,填满需要2次写,因为第一次写的时候立刻会被送往移位寄存器,TXE会立即出现,需要你再填一次。
另外,你在中断里面用while();等TXE标志位,有点奇葩。 

哦,非常感谢,之前也想到这一点了,就是没想明白原理,所以 发帖求助下。另外你说我中断里面用while();等TXE标志位,不应该这样吗,不然的话,怎么知道寄存器中有没有数据可以读取啊?希望大牛指点下。

王zheng 发表于 2013-7-23 20:29:32

RE: SPI全双工通信主机数据接收错误——紧急求助

从机发送数据b={0x21,0x22,0x23,0x24,0x25},,,,,
u8 TX_ADDRESS = {0xb2,0xb2,0xb3,0xb4,0x01};// 定义一个静态发送地址
发送地址是匹配的吗?

胡杨-409776 发表于 2013-7-23 20:32:38

回复: SPI全双工通信主机数据接收错误——紧急求助

回复第 2 楼 于2013-07-23 20:29:32发表:
从机发送数据b={0x21,0x22,0x23,0x24,0x25},,,,,
u8 TX_ADDRESS = {0xb2,0xb2,0xb3,0xb4,0x01}; // 定义一个静态发送地址
发送地址是匹配的吗? 

发送地址是正确的

人生之际 发表于 2013-7-23 20:39:57

RE: SPI全双工通信主机数据接收错误——紧急求助

显然你的从机发送数据的流程有错误。
从机是接收SCK的,你从机RXNE中断的时候,实际上发送数据已经也同步完成了。所以你第一个RXNE中断来的时候,实际上已经发出数据了,而在之前你要发送的数据还没有送往发送缓冲区呢,导致SPI自动发出了00数据。
应该是这样的,从机将要发送的数据首先打到发送缓冲区,填满需要2次写,因为第一次写的时候立刻会被送往移位寄存器,TXE会立即出现,需要你再填一次。
另外,你在中断里面用while();等TXE标志位,有点奇葩。

人生之际 发表于 2013-7-23 21:28:36

回复: SPI全双工通信主机数据接收错误——紧急求助

所谓中断,就是打断主流程优先执行,所以中断处理应该快进快出,不能等待较长的时间。所以,最好TXE和RXNE中断都开。
先看看主机中断吧:
主机的中断函数
<div class="blockcode"><div id="code_9M3"><ol>    void SPI2_IRQHandler(void)
         {
         if(SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_TXE) != RESET);  

人生之际 发表于 2013-7-23 21:45:02

回复: SPI全双工通信主机数据接收错误——紧急求助

然后是从机,也是TXE和RXNE全开中断,由于全双工SPI没有主控权,所以收发通信随时回来,最好不要再关中断了。收完数据的时候置全局标志位或RTOS发送事件给主任务,通知执行。发完数据后也同样置全局标志位或RTOS发送事件给主任务,通知执行。
如果你同步收发5个字节的话,显然发完标志会早于收完标志置位前2个字节就置位。
这种情况在SPI通信中是必然的,考虑主机SPI和EEPROM通信的过程(如常见的各厂家的25Cxxx系列),主机在发命令和地址之类的字节时,同样也收到了字节,但是因为EEPROM从机这时候还不知道主机要干什么(起码要收到读写命令和需要读写的地址,才能反应过来,发送正确的读出数据、或者继续接受要写入的数据),所以主机这时候接收到的字节应该丢弃。
所以你应该规划一个自己的协议,比如主机每次发起通信的前两个字节是命令,从机根据这两个字节命令来决定后续回答什么数据,主机在这两个字节发送过程中收的字节丢弃。当然这已经是属于半双工方式了。
 

黑旋风哥哥 发表于 2016-7-6 16:25:53

胡杨-409776 发表于 2013-7-23 20:54
回复第 4 楼 于2013-07-23 20:39:57发表:
显然你的从机发送数据的流程有错误。
从机是接收SCK的,你从机RXN ...

你好,我问一下第二次写的时候不会被立刻通过移位寄存器发送出去吗

黑旋风哥哥 发表于 2016-7-6 16:26:31

人生之际 发表于 2013-7-23 20:39
显然你的从机发送数据的流程有错误。
从机是接收SCK的,你从机RXNE中断的时候,实际上发送数据已经也同步完 ...

第二次写数据的时候不会被立刻发送出去吗
页: [1]
查看完整版本: SPI全双工通信主机数据接收错误——紧急求助