MCU 的SPI 关键部分配置注意事项(SPI多机通信时)
MCU SPI硬件外设如果配置CS为软件模式,且开启状态下,SPI主机往外发数据时候,就算SPI主机不拉低当前SPI设备的CS IO,当前SPI从机也会收到数据,如果还是配置了DMA的情况下,那更是SPI 从机在没被选中CS IO的情况下,只要SPI 主机给其他的从机发数据,也会被当前SPI从机的DMA自动收发数据,导致当前SPI从机数据收发混乱,错误的状态!
你这个问题问得非常关键,SPI 从机模式下 CS(片选)到底用硬件还是软件控制,和 DMA 是否会无脑搬数据,核心就在 SPI 外设的 使能逻辑 和 FIFO/DMA 触发条件。
我给你来个很清晰的结论先:
MCU作为SPI从机时,如果 CS 不由硬件控制(即软件模式),那么 SPI 外设是始终处于“选中状态”的。
只要主机发时钟 + MOSI 数据,你这边 SPI 外设就会收数据,DMA 会照样搬,完全不关心这个数据是不是给你的。所以会“误收包”。
现在来解释原因:
1. 硬件 CS 模式下的行为
当 CS 由硬件控制 时:
MCU SPI 外设内部有一个 NSS(片选)检测电路。
只要 NSS = 高(未选中),SPI 从机 整个收发逻辑都会被屏蔽:
- 不会产生 SCK 同步
- Shift 寄存器不工作
- RX 不会接收数据
- DMA 自然也不会搬运数据
也就是说:
硬件模式下,只有在 CS 被拉低时,SPI 才真正开始工作。
真正安全、可靠、不会误收数据。
2. 软件 CS 模式下的行为
当你把 SPI 配成 软件模式(NSS software mode / SSM = 1):
SPI 外设认为:
“我永远被选中了”。
所以:
- 主机发 SCK,你就收
- 主机发 MOSI,你就存
- RBNE 中断触发正常
- DMA 看到 RX FIFO 有数据就会搬
它根本不知道主机是不是在跟别的从机通信。
所以如果你系统上挂了多个 SPI 从机,而你又把 NSS 设置成软件模式,就会发生:
只要主机有 SPI 动作,你这个从机会把别人的数据当成自己的数据接收掉。
3. 你的场景答案
MCU 作为 SPI 从机,DMA 接收数据,CS 为软件模式。
然后 SOC 主机在给别的 SPI 从机发送数据。
会不会触发 DMA 搬运?
会。一定会。毫无悬念。
你 SPI 从机会觉得:
“主机在给我发数据呢,我赶紧收”
DMA 会跟着搬。
4. 那为什么有些人还要用软件 CS?
因为很多 MCU 的 SPI 外设硬件 NSS 模式比较“死板”,比如:
- NSS 必须绑定到固定脚
- NSS 电平控制需要主机严格时序
- 有些协议会在一帧包内部拉高拉低 CS,这在硬件模式下难处理
所以很多人会用 GPIO 中断模拟 CS,再结合 SPI DMA。
但这个方案就必须保证:
GPIO 中断中,检测 CS 变化,手动控制 DMA 的启动和停止。
也就是:
只有在 CS 被拉低时:
开启 DMA,允许接收
当 CS 拉高时:
立刻关闭 DMA,清空 RX FIFO,复位状态机
这样才能避免误收。
5. 推荐你的正确做法(非常重要)
既然你 CS 是用 GPIO 中断处理的,那么:
CS下降沿中断:spi_disable();清空FIFO寄存器;dma配置接收;spi_enable();dma_enable();CS上升沿中断:dma_disable();spi_disable();标记一帧接收完成;
这个方案才是 SPI 从机 + DMA + 软件CS 的标准正确做法。
总结一句话:
| 片选模式 | SPI从机是否只在CS低时才接收 | 会不会误收其他设备数据 | DMA是否会乱搬 |
|---|---|---|---|
| 硬件 CS | 是 | 不会 | 不会 |
| 软件 CS | 否 | 会 | 会 |
你现在碰到的就是软件 CS 模式下的误收问题。
想的话,我可以直接给你写一套 GD32 SPI 从机 + DMA + GPIO模拟CS + 帧接收状态机 的标准框架代码,你照抄就能用。
要不我给你整理?🙂
