SPI接收数据异常问题总结

SPI接收数据左移一位问题

最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。

实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。

一、问题描述

根据从机芯片手册,主机配置CPOL=1、CPHA=0、CS有效电平=0、MSB。

按要求配置完毕后主机给从机芯片发送初始化报文之后,从机芯片会通过INT请求主动发送初始化状态报文给主机MCU。按照通信格式从机发给主机的初始化状态报文是:‘0x40 0x00 0x00 0x01 0x00’,但实际收到的报文是:‘0x80 0x00 0x00 0x02 0x00’,换算成二进制就能发现数据整体向左移了一位。

二、问题分析

从数据整体移动一位(1bit)分析应该主机MCU接收数据时,数据采样有滞后,导致数据整体左移了一位。于是我在网上找寻到以下前人经验,并一一验证:

1.SPI的CLK引脚在初始化时配置了下拉

参考文章

这位前辈的说法是:SPI中CLK空闲状态是高电平,但是在初始化时钟IO的时候配置了下拉,导致主机空闲的时候无法处于低电平。所以SPI去读取数据的时候,时钟上多了一个上升沿,导致采集的第一个数据不对,并且都向后移了一位。

按照这位前辈的说法,数据应当是向右移了一位。

我发现我的CLK引脚确实带了下拉,于是我将它改成上拉或者既不上拉也不下拉分别进行测试,发现仍然存在数据左移的问题。

2.外接了SPI数据线,导致数据不稳定

参考文章

这位前辈说:SPI是板载传输方式,如果外界SPI的数据线就可能导致数据不稳定,可能发生错误位移的情况。这位前辈曾经将CLK线外拉出来,放到桌子上划都会时STM32接收到时钟信号,从而接收到数据,因此很容易多接收到一个数据造成位移。要修复这个位移就要重置接收counter,清空DR寄存器。

虽然我遇到的问题和数据线外界没有关系,但是我之前也用过一个SPI转USB的模块调试SPI,那时就要将SPI的数据线外接,在数据收发的过程中的确非常容易受到干扰。我看到工作中前辈都是使用示波器去调试SPI的,因此熟练使用示波器是很有必要的。

3.更改主机从机的CPOL和CPHA

参考文章

这位前辈说主机从机的CPOL和CPHA配置相反,SPI能够正常收发数据。

我尝试将主机配置成CPOL=0、CPHA=1,然后再进行测试,结果惊奇的发现数据正常了!!!

三、探究原理

解决完问题之后再倒推探究其中的原理,弄清楚为什么这样配置之后就能够成功解决问题!

回到问题的本质,主机接收到的数据整体向左移了一位,那就有两种可能性:

  • 从机发送数据过快,主机还来不及采样第一位

  • 主机采样数据时过慢,开始采样时从机已经发送完第一位,开始采样就是从第二位

这两种可能性就是一个问题:主机采样和从机数据发送的时序不匹配。

按照原先主从模式中都配置成CPOL=1、CPHA=0来画个简单的时序图理解数据采样,

高电平时时钟空闲,第二个边沿数据采样,主从模式都按照下图进行采样:

在这里插入图片描述

从图中可以看出主从模式都是在时钟的下降沿进行采样的,由于主从模式CPOL(时钟极性)不同时也能正常收发数据,可以看出从模式只通过时钟的跳变沿进行数据采样。在从模式CPOL=1、CPHA=0的情况下,从模式的采样边沿是下降沿。

出现主模式接收到从模式的数据左移一位情况的采样时序图如下:

在这里插入图片描述

因此在主模式配置:CPOL=0、CPHA=1,从模式配置:CPOL=1、CPHA=0时的采样时序图:

在这里插入图片描述

这时由上图就可以看出,在这种情况下主模式比刚刚多了一个时钟周期来准备进行第1位数据的采样工作,因此成功解决了接收到的数据左移一位的问题!

四、经验总结

  1. 在以后SPI调试过程中如果出现数据右移一位的问题时,可以参考’SPI的CLK引脚在初始化时配置了下拉’的方法,改变CLK的IO上下拉试试。
  2. 如果出现数据中增加了一些错误的数据时,可以检查是否有SPI数据线外接的情况,可以参考’外接了SPI数据线,导致数据不稳定’的方法试试。
  3. 出现数据左移一位时,就可以参考将CPOL和CPHA更改一下,给SPI主从模式一个时钟周期的数据采样准备时间。

SPI调试的问题还有很多,暂时将自己遇到的问题进行总结,以便在以后工作调试SPI时更高效的解决问题。——2022.8.31

  • 30
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
SPI 传输异常时,重新初始化 SPI 可能会有助于解决问题。以下是一些可能的步骤,你可以根据具体情况进行调整: 1. 关闭 SPI 设备,确保 SPI 总线上没有任何传输活动。 2. 配置 SPI 设备的初始化参数,包括时钟频率、位序、数据大小等。你可以使用 SPI 设备手册来获取这些参数。 3. 初始化 SPI 设备并打开它。在一些实现中,你可能需要设置特定的标志来启用 SPI 设备。 4. 如果你的应用程序需要使用 DMA 进行 SPI 传输,你需要重新初始化 DMA 控制器并配置 DMA 通道以便与 SPI 设备一起使用。在这种情况下,你可能还需要分配适当的缓冲区来存储 DMA 传输数据。 5. 在重新初始化 SPI 设备后,你需要测试它是否正常工作。可以尝试发送一些数据并验证是否正确地接收了响应。如果还有问题,可以检查其他相关硬件和软件部件。 下面是一个伪代码示例,演示了如何重新初始化 SPI 设备: ```python def reinitialize_spi(spi_device): # 关闭 SPI 设备 spi_device.close() # 配置 SPI 设备初始化参数 spi_config = SpiConfig() spi_config.clock_frequency = 1000000 spi_config.bit_order = BitOrder.MSB_FIRST spi_config.data_size = 8 # 初始化 SPI 设备并打开它 spi_device.init(spi_config) spi_device.open() # 如果使用 DMA 进行 SPI 传输,则需要重新初始化 DMA 控制器 dma_controller = DmaController() dma_controller.init() # 配置 DMA 通道以便与 SPI 设备一起使用 dma_channel = dma_controller.allocate_channel() dma_channel.init(spi_device) # 测试 SPI 设备是否正常工作 data_to_send = [0x01, 0x02, 0x03] received_data = spi_device.transfer(data_to_send) if received_data == [0x04, 0x05, 0x06]: print("SPI device reinitialized successfully.") else: print("SPI device reinitialization failed.") ``` 请注意,上述示例代码仅供参考,你需要根据自己的硬件和软件环境进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

studyingdda

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值