先搞懂它是什么
- SPI(串行外设接口):一种高速、全双工、主从式的串行总线,常用于 Flash、屏幕、传感器等对速度要求高的设备。
- 主从模式:总线里只有一个是“主”(Master,发起通信、提供时钟),其余是“从”(Slave,被动响应)。
- “四根线”:SPI 靠时钟线同步、两条数据线同时收发、一条片选线选中设备,所以速度快、时序简单。
层层拆解原理
1. 四根线各干什么
| 信号 | 全称 | 方向(主视角) | 作用 |
|---|---|---|---|
| SCLK | 串行时钟 | 主 → 从 | 每个脉冲传输 1 位,同步双方 |
| MOSI | 主出从入 | 主 → 从 | 主发送数据 |
| MISO | 主入从出 | 从 → 主 | 从回传数据 |
| CS/SS | 片选 | 主 → 从 | 拉低选中某个从设备 |
一根时钟线 + 两条数据线 = 全双工:每个时钟周期同时发 1 位、收 1 位。
2. 片选:怎么选中“那一个”从设备
总线上可以挂多个从设备,但同一时刻只能有一个被选中:主设备把目标从设备的 CS 拉低,其他从设备保持 CS 高电平、不参与通信。所以“CS 接哪根 IO”必须和代码里配置一致。
3. 时钟极性(CPOL)与相位(CPHA):最难背的一对概念
SPI 没有规定数据在时钟的哪个沿采样,需要主从双方约定:
- CPOL(极性):空闲时时钟是高还是低(0 = 空闲低,1 = 空闲高)。
- CPHA(相位):数据在第一个沿还是第二个沿采样(0 = 第一个沿,1 = 第二个沿)。
组合出 4 种模式(SPI Mode 0~3):
| 模式 | CPOL | CPHA | 说明 |
|---|---|---|---|
| Mode 0 | 0 | 0 | 最常见,多数设备默认 |
| Mode 1 | 0 | 1 | 少见 |
| Mode 2 | 1 | 0 | 少见 |
| Mode 3 | 1 | 1 | 与 Mode 0 类似但空闲电平相反 |
如果设备手册写明“SPI Mode 0”,而代码配置成 Mode 3,数据就会错位/全错。 这也是 SPI 调试最常踩的坑。
4. 速率与数据位
- 传输速率由 SCLK 频率决定,主设备可配置;从设备有最高频率限制(如 Flash 常见 50~100MHz),超了会出错。
- 数据位宽常见 8 位,也有 16/32 位模式;读写数据时注意与设备手册一致。
结合 SDK 看实现
- 相关例程页:SPI 协议、Flash 内部存储
SDK 使用 SPI 的套路是“初始化 → 配置模式/速率 → 读写数据”:
struct bflb_device_s *spi = bflb_device_get_by_name("spi");
/* 主模式、Mode 0(CPOL=0, CPHA=0)、8 位数据 */
bflb_spi_init(spi, SPI_MODE_MASTER, 8, 0);
bflb_spi_set_clk(spi, 1000000); /* SCLK 1MHz */
bflb_spi_send(spi, (uint8_t *)tx_buf, len); /* MOSI 发出 */
bflb_spi_recv(spi, (uint8_t *)rx_buf, len); /* MISO 接收 */读 Flash/传感器这类“先发指令再读数据”的流程,本质就是多次 SPI 收发,中间用 CS 保持选中。
常见考点 / 面试题
SPI 为什么比 UART 快?
SPI 有专用时钟线(SCLK)同步,且可以工作在很高频率;UART 靠波特率异步采样,速率受限于双方的精度和时钟漂移。
SPI Mode 0 和 Mode 3 有什么区别?
两者都是第一个沿采样,区别是空闲时钟电平:Mode 0 空闲低、Mode 3 空闲高;配置与设备手册不一致会导致数据采错。
多个从设备挂一条 SPI 总线怎么区分?
靠片选 CS:同一时刻只把一个从设备的 CS 拉低,其他保持高电平不参与通信;每个从设备接独立的 CS 引脚。
MOSI 和 MISO 接反会怎样?
主发从收、从发主收的数据线互换后,双方都收不到对方数据(读到全 0/全 1 或乱码),属于接线级常见错误。
为什么 SPI 是全双工而 I2C 是半双工?
SPI 有独立的 MOSI/MISO 两根数据线,可同时收发;I2C 只有一根数据线 SDA,同一时刻只能一个方向传输。
遇到问题?
如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

