Skip to content

先搞懂它是什么

  • 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):

模式CPOLCPHA说明
Mode 000最常见,多数设备默认
Mode 101少见
Mode 210少见
Mode 311与 Mode 0 类似但空闲电平相反

如果设备手册写明“SPI Mode 0”,而代码配置成 Mode 3,数据就会错位/全错。 这也是 SPI 调试最常踩的坑。

4. 速率与数据位

  • 传输速率由 SCLK 频率决定,主设备可配置;从设备有最高频率限制(如 Flash 常见 50~100MHz),超了会出错。
  • 数据位宽常见 8 位,也有 16/32 位模式;读写数据时注意与设备手册一致。

结合 SDK 看实现

SDK 使用 SPI 的套路是“初始化 → 配置模式/速率 → 读写数据”:

c
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

Released under the MIT License. Build Time 2026-09-11 14:52:23