打印
[应用相关]

STM32作为SPI slave与主机异步通信

[复制链接]
904|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-3-26 08:17 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
背景
最近被测试提了个BUG,说某款产品在用户按下前面板的按键后,对应的按键灯没有亮起来。前面板跟主机是通过SPI口通信,前面板是从机,从机想要主动发送消息,需要通过GPIO中断来通知主机:



上图前面板是STM32(没有RTOS),主机是RK3588平台,INT是GPIO管脚,CS、MISO、MOSI是SPI标准信号。

整个通信过程是异步的:




hold键示例的视频:


[color=rgba(0, 0, 0, 0.75)]

按键按下到按键灯亮起



思路
因为前面板是从机,它不知道主机什么时候会发消息,因此需要一直监听SPI总线,等待主机的command。另一方面,它也不知道用户什么时候会按下按键,因此需要一直扫描按键接口,并在检测到按键活动后尽快向SPI总线发送消息,即request,这两种事件对于STM32来说,都是异步的。

SPI总线虽然是双向通信的,但是仅限同步收发(UART是异步收发)。换句话说,尽管STM32发送request的同时可以接收command,但这两种消息的信源(用户和app)却不是同步的,因此不能调用HAL_SPI_TransmitReceive_DMA等双向API来通信,只能分别调用HAL_SPI_Transmit_DMA和HAL_SPI_Receive_DMA来模拟异步通信。

解决方法
为了清晰,用流程图来描述:




注意事项:

进入主循环前先启动SPI接收,然后在接收完成中断里再次启动接收,即恢复到监听下一个command的状态。
STM32绝大部分时间都在监听并执行主机发来的command,仅在用户按下按键时才发送request
发送request前,必须先abort掉当前的SPI接收流程(SPI同步通信模式的限制)
最好给command和request分别开辟一个队列,接收中断将command入队,主循环将command出队;主循环发送request前将其入队,发送完成中断将其出队。这样做的好处是可以容纳不同类型、不同时间点的request(按键、旋钮、command的response等),以及不同类型、不同时间点的command(LED点亮命令、蜂鸣器开关命令、固件版本查询命令等)。
可能存在的问题
按照上述思路写完代码后,发现只要用户有按键行为,按键灯就仍然点不亮,从串口打印来看,是接收到的command出现了掐头或去尾的现象。

分析是SPI内部的FIFO没有正确清空,网上搜了下,这篇文章分析得比较到位,我在评论区找到了解决办法,贴出来:

void reset_spi1(void)
{
        __HAL_RCC_SPI1_FORCE_RESET();
        __HAL_RCC_SPI1_RELEASE_RESET();
        MX_SPI1_Init();
}


在每次启动接收前都调一下上面的代码,就可能清空FIFO。经测试,SPI没有再出现掐头去尾的现象。

总结
如果应用场景是双向异步通信,且是系统拓扑是点到点,就别选SPI了,UART更好。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/happen23/article/details/136412937

使用特权

评论回复
沙发
我想看大海| | 2024-3-26 13:46 | 只看该作者
做SPI从机时钟需要跟随主机

使用特权

评论回复
板凳
鹿鼎计| | 2024-3-26 21:07 | 只看该作者
用STM32做SPI从机还真没搞过。

使用特权

评论回复
地板
理想阳| | 2024-3-26 21:33 | 只看该作者
这种方式确实在有些情况下可以用,话说为什么不用串口。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2028

主题

15903

帖子

13

粉丝