4、SPI通信协议详解:SPI四线制(SCK/MOSI/MISO/CS)、四种模式(CPOL/CPHA)、多从机级联与菊花链

各位同学好,我是老张。今天咱们来聊聊SPI这个协议。说实话,SPI是我在嵌入式开发中用得最多的串行接口之一,比I2C简单直接,比UART灵活。很多压传感器、ADC、显示屏都爱用它。我个人习惯是,只要从机数量不多、距离不远,首选SPI。

SPI全称是Serial Peripheral Interface,摩托罗拉公司搞出来的。它是个同步、全双工的通信协议。什么叫同步?就是有专门的时钟线来同步数据。全双工呢?就是可以同时收发数据。嗯,这一点比I2C和UART都强。

4.1 SPI四线制:SCK、MOSI、MISO、CS

标准的SPI有四根线,少一根都不行(除非你搞特殊)。咱们一个一个说:

  • SCK(Serial Clock):时钟线,由主机产生。说白了就是心跳,数据跟着它跳。
  • MOSI(Master Out Slave In):主机输出,从机输入。数据从主机流向从机。
  • MISO(Master In Slave Out):主机输入,从机输出。数据从从机流回主机。
  • CS(Chip Select):片选线,低电平有效。主机拉低哪个从机的CS,就跟哪个从机说话。

我在项目中遇到过一个问题:有个同事把MOSI和MISO接反了,结果调了一整天没通。你想想看,数据发出去收不回来,能不头疼吗?所以布线时一定要仔细核对。

核心要点:SPI是主从结构,一个主机可以带多个从机。每个从机独占一根CS线,但共享SCK、MOSI、MISO。

4.2 四种模式:CPOL和CPHA

SPI有四种工作模式,由两个参数决定:CPOL(时钟极性)和CPHA(时钟相位)。

CPOL:决定时钟空闲时的电平。

  • CPOL=0:空闲时SCK为低电平
  • CPOL=1:空闲时SCK为高电平

CPHA:决定数据在哪个时钟沿采样。

  • CPHA=0:第一个时钟沿采样(上升沿或下降沿取决于CPOL)
  • CPHA=1:第二个时钟沿采样

组合起来就是四种模式:

模式 CPOL CPHA 采样沿 数据变化沿
模式0 0 0 上升沿 下降沿
模式1 0 1 下降沿 上升沿
模式2 1 0 下降沿 上升沿
模式3 1 1 上升沿 下降沿

我曾经踩过一个坑:某款压传感器手册上写的是模式0,但我用模式1也能通信,就是数据偶尔错位。后来用示波器一看,原来是时序差了一个沿。所以一定要严格按照手册来,别想当然。

我的建议:调试SPI时,先用示波器抓一下SCK和MOSI的波形,看看数据对齐在哪个沿。这比盯着代码看有效得多。

4.3 多从机连接方式

当你有多个从机时,有两种连接方式:独立片选和菊花链。

4.3.1 独立片选(标准方式)

每个从机单独一根CS线,主机有多少个GPIO就能带多少个从机。这种方式最简单,也最常用。我做的压传感器采集板,一个MCU带了4个传感器,就是用的独立片选。

// 伪代码示例:独立片选方式
void spi_write_read(uint8_t cs_pin, uint8_t *tx_data, uint8_t *rx_data, uint16_t len) {
    GPIO_Reset(cs_pin);  // 拉低片选
    for (uint16_t i = 0; i < len; i++) {
        while(!SPI_IsTxEmpty());  // 等待发送缓冲区空
        SPI_SendData(tx_data[i]); // 发送一个字节
        while(!SPI_IsRxNotEmpty()); // 等待接收数据
        rx_data[i] = SPI_ReceiveData(); // 读取接收数据
    }
    GPIO_Set(cs_pin);  // 拉高片选
}

4.3.2 菊花链(Daisy Chain)

菊花链就有点意思了。所有从机共享SCK和CS,但数据线是串联的。主机的MOSI接第一个从机的SI,第一个从机的SO接第二个从机的SI,以此类推。最后一个从机的SO接主机的MISO。

为什么要用菊花链?因为有些场景下GPIO不够用,或者布线空间有限。但代价是延迟增加了——数据要经过每个从机才能到达主机。

注意:不是所有SPI从机都支持菊花链。必须看芯片手册里有没有提到"daisy-chain capable"。我曾经买了一批便宜的ADC,手册里没写支持菊花链,结果死活连不上。

4.4 知识体系总览

下面我用一张图来总结SPI的核心知识点,方便你理解整体结构:

SPI通信协议知识体系 SPI协议 四线制:SCK / MOSI / MISO / CS 四种模式:CPOL + CPHA 组合 多从机连接:独立片选 / 菊花链 四线制详解 SCK:时钟同步 MOSI:主机→从机 MISO:从机→主机 CS:片选使能 四种模式 模式0:CPOL=0, CPHA=0 模式1:CPOL=0, CPHA=1 模式2:CPOL=1, CPHA=0 模式3:CPOL=1, CPHA=1 多从机连接 独立片选: 每个从机单独CS 菊花链: 数据串联传输

4.5 避坑指南

做SPI驱动这么多年,我总结了几条血泪教训:

  • 片选时序要留余量:拉低CS后,别急着发数据,等几个微秒。有些从机反应慢,你发太快它还没准备好。
  • 时钟频率别太高:理论值归理论值,实际布线有寄生电容,频率高了波形就变形了。我一般留50%的余量。
  • MISO要加上拉:如果从机是三态输出,CS没选中时MISO是高阻态。不加个上拉电阻,主机可能读到不确定的电平。
  • 注意字节顺序:有的芯片是MSB first,有的是LSB first。搞反了数据全乱套。

调试小技巧:先用逻辑分析仪抓一下CS、SCK、MOSI的波形,确认时序对不对。我每次调SPI都是这么干的,比看代码快多了。

好了,SPI协议的核心内容就这些。四线制、四种模式、多从机连接,这三个点搞明白了,SPI驱动就没什么大问题了。下一节咱们会结合具体的压传感器芯片,手把手写一个完整的SPI驱动代码。


公众号:蓝海资料掘金营,微信deep3321