1、SPI从站错位问题和现象
最近用SPI做一套总线协议,主站是一个Cortex-A7处理器,从站是16块STM32F0xx的PCB,通过排针连在一起,每片M0的SPI使用软件CS,上电初始化之后就一直使能,MOSI,MISO,CLK信号通过高速差分芯片挂总线,每个PCB有一个地址,通信采用一问一答的形式,匹配地址的从站会应答Cortex-A7主站的请求。
开始好好的,16块板连在一起,连续通信两三天都没什么问题,以为很简单,方案基本可以用了,准备上EFT测试干扰性能。然后事实并不是想象那样,上测试台之前,在通信过程中给其中一个M0板子下固件,下载的时候,M0的GPIO脚都是高组态,由于PCB是一个刚毕业的新人做的,没有考虑这样的情况,导致CLK信号的差分芯片输出使能被上拉电阻锁死输出,CLK差分芯片的输出数据脚也被上拉电阻锁死在高电平,将整条总线上的所有PCB的CLK全部锁死在高电平,升级结束之后,其他15块PCB全部通信中断,无法正确响应主站请求。后来自测,直接用镊子夹住CLK的两跟差分线,所有从站很容易进入通信断开状态,放开镊子也无法恢复。
因为M0打开了SPI的硬件计算CRC功能,我想这也简单,连续累计CRC错误10次,我就复位SPI和DMA,以为很简单的事情,居然没有效果,即使复位,通信仍然不能恢复。于是我上各大网站,看了各种论坛和博客,但是能将这件事情说清楚的几乎没有,仅有几篇说到SPI从站错位的时候应该怎么恢复,按他们的做法,也不能恢复通信。
2、问题分析
M0的从站使用了DMA循环模式接收和发送,并且打开的CRC硬件校验。那么,随机的中断CLK,类干扰导致的CLK增多或减少,短路只能模拟减少,SPI接收或发送的移位寄存器可能没有获得完整的8bit数据,也可能在DMA接收到一帧数据的一半,CLK被短路就没有了,这时候DMA的计数器处于接收一部分数据,但又没有达到中断个数。从主站这边来看,上一次的请求必然就是失败了,主站设计了超时重发,那么超时之后,主站并不知道从站的情况,继续发送一帧数据,M0的DMA之前收到一部分数据,没收完一帧数据,就进入中断了,则CRC必然错误。如果是移位寄存器在没有满8bit情况下CLK就没了,即使在链路层采用帧头识别的办法也无法正常通信,因为每个字节都不是原来的bit位数顺序了。
问题总结下来就是,移位寄存器需要清除多余的bit,CRC校验需要对齐其实的字节。
3、问题解决
原因明确了,解决就不会很难。
必须复位移位寄存器,清除多余接收数据,并重置DMA的计数器。
根据STM32的特点,竟然没有任何寄存器可以清除移位寄存器,只能通过RCC寄存器,将整个SPI模块复位,然后重新配置SPI。
值得注意的是,DMA不需要复位,但是必须先停止DMA,SPI复位完成之后,重新配置DAM收发计数器值,再打开DMA。
还有一点就是复位过程必须避过主站的重发数据帧,如果复位刚结束,又收到半截帧数据,又回到字节不对齐的 状态了。
避过主站发送可以通过BSY,RXNE,TXE标志联合起来使用,注意移位寄存器bit位错位异常的时候,BSY可能一直为高,具体怎么弄,动手调试吧少年。
STM32居然没设计复位移位寄存器功能,一旦错位就一直错下去,怪不得网上很多吐槽难搞,不禁想到我们公司的其他产品把SPI扩展出来的情况,在强干扰环境下可靠性堪忧。
|