你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

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

[复制链接]
胡杨-409776 提问时间:2013-7-23 20:25 /
我采用stm F103 作为SPI的主机,stm F303作为从机,两者进行SPI通信,主机向从机发送一组数据,从机同时也向主机发送一组数据,从机和主机都是采用的中断方式,但是每次的结果,从机里面接收的数据都是正确的,主机接收的却是错误的。举个例子来说,主机发送5个数据给从机,从机也发送5个数据给主机,从机能够完全接收主机的5个数据,但主机只能接收从机的前3个数据。如主机发送a[5]={0x01,0x02,0x03,0x04,0x05},从机发送数据b[10]={0x21,0x22,0x23,0x24,0x25},通信完成以后,从机的接收数据是完全对的,而主机的接收数据则为a_receive[5]={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[Rx_Idx++] = 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[Tx_Idx++]);
  • }
            
            复制代码
            主机的主函数                                    

                   
  • 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[Tx_Idx++]);
  •     /* 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[Rx_Idx++] = SPI_I2S_ReceiveData(SPI2);
  • }
            
            复制代码
            


收藏 1 评论8 发布时间:2013-7-23 20:25

举报

8个回答
胡杨-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[10]={0x21,0x22,0x23,0x24,0x25},,,,,
u8 TX_ADDRESS[TX_ADR_WIDTH] = {0xb2,0xb2,0xb3,0xb4,0x01};  // 定义一个静态发送地址
发送地址是匹配的吗?
胡杨-409776 回答时间:2013-7-23 20:32:38

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

回复第 2 楼 于2013-07-23 20:29:32发表:
从机发送数据b[10]={0x21,0x22,0x23,0x24,0x25},,,,,
u8 TX_ADDRESS[TX_ADR_WIDTH] = {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中断的时候,实际上发送数据已经也同步完 ...

第二次写数据的时候不会被立刻发送出去吗

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版