摘要:SPI 主机一发数据,从机就罢工?不是从机坏了,而是 NSS(片选)引脚的硬件管理模式冲突。本文解析为什么 SPI 经常“莫名其妙被取消选中”。
一、问题描述(现象)
**主机发送一串数据,从机只收到第一个字节;
示波器看 CS 引脚在传输中途突然拉高了。**
很多工程师的排查方向是:
从机固件写错了?
干扰导致 CS 抖动?
换一块板子试试?
二、原理分析
1. 物理模型
NSS(CS)有两种管理模式:
硬件管理(NSS Hard):由 SPI 外设自动控制。
软件管理(NSS Soft):由用户代码控制。
2. 核心参数
-
SSOE (Slave Select Output Enable):主模式下的 NSS 输出使能。
-
SSM (Software Slave Management):软件从机管理。
3. 反直觉真相
CubeMX 默认配置经常是“硬件 NSS”,但你的代码却在用 GPIO 控制 CS。
冲突发生了:
-
SPI 硬件认为传输结束,自动拉高 NSS。
-
你的 GPIO 代码试图拉低 NSS。
-
结果:NSS 电平不确定,从机被意外取消选中。
三、工程级解决方案
方案 1:强制软件管理(最稳妥)
除非你用 TI 模式或复杂多从机,否则一律用软件管理。
hspi1.Init.NSS = SPI_NSS_SOFT;
HAL_SPI_Init(&hspi1);
然后 CS 完全由 GPIO 控制:
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, buf, len, timeout);
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
方案 2:硬件 NSS 的正确用法
如果你想用硬件 NSS(多主机仲裁时用):
-
配置 SPI_CR2的 SSOE = 1。
-
CS 引脚必须连接到 SPIx_NSS 复用功能。
-
严禁再用 GPIO 代码控制该引脚。
方案 3:检查 MODF 错误
NSS 冲突会导致 MODF(模式错误)。
if (__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_MODF)) {
// 必须清标志并复位 SPI
__HAL_SPI_CLEAR_MODFFLAG(&hspi1);
}
四、选型避坑建议
单主机 + 单从机:永远用 SPI_NSS_SOFT。
多从机:每个从机一个独立的 GPIO CS,不要用硬件 NSS。
多主机:才考虑硬件 NSS 仲裁。
五、总结 Checklist
-
[ ] SPI 配置是 NSS_SOFT 还是 NSS_HARD?
-
[ ] 是否混用了 GPIO 代码和硬件 NSS?
-
[ ] 是否检查并处理了 MODF 错误?
-
[ ] CS 引脚是否有外部上拉电阻?
💡 注意区分:本文讨论的是 片选信号管理。
若你的问题是读回来全是 0xFF,请检查 CPOL/CPHA,详见《SPI 读回来全是 0xFF?》。
References
-
STM32 Reference Manual – SPI slave select management
-
SPI Protocol Specification




