STM32G0使用HAL库并做为从机使用 SPI+DMA通信时,调试总结
最近需要使用STM32单片机的SPI做为从机使用,与其他SPI主机通信;因为速率要求最快要到10M,所以只能使用DMA方式收发数据;最常使用的时STM32的SPI做为主机使用,这个一般没啥问题,但这次使用SPI做为从机使用时,出现了一些问题,在此总结一下,提醒以后注意一下;
使用STM32CubeMX配置项目,这个没啥好说的,网上也有很多例子;这里主要强调一点,需要SPI的通信速率很快时,最好使用硬件CSN;并且从机和主机的工作模式必须一直;我这里使用的是:CPOL=0,CPHA=0;
我这里是,从机即发又收,按字节收发,所以需要DMA_RX和DMA_TX:
其它配置就不罗列了;到此基本的SPI+DMA的从机全双工,已经配置完成;
本来想着很简单,使用HAL_SPI_TransmitReceive_DMA(&hspi1, spi_tx_data, spi_rx_data,8);这个函数就可以了;刚开始比较顺利的,确实可以收发数据;但是,但是,如果主机 发送的不是正好的字节CLK,就是读取不完整,主机发了一半就不发了,或者收到外界干扰,CLK数量不对时,数据就会出现错误,或者出现数据错位,这里的数据不对,指的是主机收到的数据不是想要的数据了,但在主机的操控下,分机还能发出数据,只是数据顺序可能出现了错误,总之,数据不对了,这个时候,主机是知道出错了,但分机不知道自己已经发错了,反正发着呢,谁知道对错呢;这时解决的办法最先想到的就是让从机参与通信的参数复位,重新配置;SPI+DMA没有空闲一类的判断;在网上也搜了很多,根据上面的提示,也没有调试成功;
最后,想到一个最简单的方式,当主机收到错误数据时,就停止SPI通信,这时CSN是高电平,并持续一定时间,在重新通信;从机就利用这段时间重新配置参数;主机这边就不多说了,说一下分机处理:实际上就是主程序内一直判断CSN的电平状态,因为在SPI通信时,CSN要么一直低,要么有高有低,只有空闲时,CSN才一直高;这样就可以增加一个CSN的状态标志,并增加一个超时机制;在上电时,CSN的状态标志spi_csn_RS=0;在有通信是,CSN是低,状态标志spi_csn_RS=1,超时计时清0;然后在定时中断里面判断spi_csn_RS==1和CSN=1时,开始计时,超过规定时间,退出计时,并让spi_csn_RS=2;主程序内,判断spi_csn_RS==2时,触发通信的参数复位,重新配置;
我这里使用的时PA4做为SPI从机的硬件CSN脚:
定时中断里面:我这里定时100MS超时,这个时间可以根据具体情况更改;
然后在主程序里面,判断spi_csn_RS==2时,触发通信的参数复位,重新配置;
这里实际上有也有2中方式,第一种就是比较暴力,让芯片重新复位;另一种就是只让SPI和DMA复位后,在配置参数;
第一种方式:
这个方式比较暴力,程序重新复位执行;
第二种方式:
上面2个方式都行,看实际情况;
到此这种问题就可以得到解决;
后面还有个问题,发现:在每次通信的间隔稍长时,分机可以正常收到主机的一帧数据;但是每次通信非常非常短时,分机收到主机的数据一直是0 ,但主机收到分机的数据是正确的,这个问题还不知道怎么回事?(这里面有2个时间概念:一个是SPI的通信速率,就是一个字节的发送时间,这个是很快的,可以到10M;另一个是每次主机发起一次通信的时间间隔,上面这个问题就是出现在这个时间上,时间间隔长点时,分机收主机的数据正常;时间间隔很短很短时,分机一直收到的数据是0,但主机可以正确收到分机数据;)
作者:码农N年