SPI时序分析:四种工作模式与核心机制

SPI通信,说白了就是主设备跟从设备之间的一场「时钟对话」。我刚开始做驱动时,总觉得时序这东西太抽象,不就是几个波形嘛。直到有一次,我调试一块ADC芯片,数据死活读不对——后来才发现,是SPI模式配错了。嗯,从那以后,我再也不敢小看时序分析了。

这一节,咱们把SPI的四种工作模式、数据采样与移位机制、片选控制策略,还有传输速率计算,一次性讲透。

SPI四种工作模式波形图

SPI有四种工作模式,由两个参数决定:时钟极性(CPOL)和时钟相位(CPHA)。CPOL决定时钟空闲时的电平,CPHA决定数据在哪个时钟边沿被采样。

模式 CPOL CPHA 空闲时钟电平 数据采样边沿 数据移位边沿
模式0 0 0 低电平 上升沿 下降沿
模式1 0 1 低电平 下降沿 上升沿
模式2 1 0 高电平 上升沿 下降沿
模式3 1 1 高电平 下降沿 上升沿

你想想看,模式0和模式3是最常用的。我个人习惯,只要从设备手册没特别说明,优先用模式0。为什么?因为很多MCU的SPI外设默认就是模式0,省事。

关键记忆法:CPOL=0时空闲低电平,CPOL=1时空闲高电平。CPHA=0时在第一个边沿采样,CPHA=1时在第二个边沿采样。

下面这张SVG图,把四种模式的波形关系画清楚了。注意看采样时刻和移位时刻的对应关系。

SPI四种工作模式波形对比 模式0 (CPOL=0, CPHA=0) SCK MOSI D0 D1 D2 D3 采样点 模式1 (CPOL=0, CPHA=1) SCK MOSI D0 D1 D2 D3 采样点 模式2 (CPOL=1, CPHA=0) SCK MOSI D0 D1 D2 D3 采样点 模式3 (CPOL=1, CPHA=1) SCK MOSI D0 D1 D2 D3 采样点 数据线 采样点

数据采样与移位机制

SPI的数据传输,本质上是主从设备各自有一个移位寄存器。主设备在每个时钟边沿把数据从MOSI线移出去,从设备在另一个边沿把数据从MISO线采样进来。这两个动作是同步的,所以SPI是全双工通信。

我举个例子,假设主设备要发送0xA5(二进制10100101)给从设备。在模式0下,主设备在SCK的下降沿把数据一位一位移出,从设备在SCK的上升沿采样。反过来,从设备也在同一时刻把自己的数据移出到MISO线上。

经验之谈:很多新手以为SPI是「发完再收」,其实不是。SPI的收发是同时进行的。你发一个字节的同时,也收到了一个字节。如果你只关心发送,收到的数据可以忽略;如果你只关心接收,那你也得发一个字节(通常是0x00或0xFF)来产生时钟。

移位机制的核心,就是MSB优先还是LSB优先。大部分SPI设备默认MSB优先,但有些传感器(比如某些温度传感器)用LSB优先。我踩过这个坑——有一次读一个加速度计的数据,读出来的值总是对不上,折腾了半天才发现是位序搞反了。

// MSB优先发送0xA5 (10100101)
// 发送顺序: 1 -> 0 -> 1 -> 0 -> 0 -> 1 -> 0 -> 1
for (int i = 7; i >= 0; i--) {
    MOSI = (data >> i) & 0x01;
    // 产生时钟边沿...
}

// LSB优先发送0xA5 (10100101)
// 发送顺序: 1 -> 0 -> 1 -> 0 -> 0 -> 1 -> 0 -> 1
for (int i = 0; i <= 7; i++) {
    MOSI = (data >> i) & 0x01;
    // 产生时钟边沿...
}

片选信号控制策略

片选信号(CS/SS),说白了就是主设备用来「点名」从设备的。低电平有效,拉低表示选中,拉高表示释放。

片选控制有几个关键点,我总结一下:

  • 传输前拉低CS:在第一个时钟边沿之前,CS必须已经拉低。有些设备要求CS拉低后等待一小段时间(tCSS)才能开始传数据。
  • 传输后拉高CS:最后一个时钟边沿之后,CS才能拉高。同样,有些设备要求最后一个时钟边沿后等待一小段时间(tCSH)。
  • 多字节传输:有些设备支持连续传输多个字节时保持CS低电平(比如Flash存储器),有些设备则要求每个字节之间拉高CS(比如某些ADC)。
  • 多从设备:每个从设备独立一根CS线。同一时刻只能有一个CS为低。

注意:CS信号的毛刺是常见问题。我曾经在一个项目里,CS线太长,信号反射导致CS在拉低瞬间出现了一个短暂的高电平脉冲,结果从设备以为传输结束了,数据全乱套。解决办法是在CS引脚上加一个10kΩ上拉电阻,或者降低GPIO的驱动速度。

传输速率与时钟频率计算

SPI的传输速率,直接由SCK时钟频率决定。但时钟频率不是想多高就多高,它受几个因素限制:

限制因素 说明 典型值
主设备最大SCK MCU的SPI外设支持的最高频率 通常为系统时钟的1/2或1/4
从设备最大SCK 从设备数据手册中规定的最高频率 几MHz到几十MHz不等
PCB走线长度 走线越长,信号完整性越差,频率上限越低 10cm以内可跑几十MHz
电容负载 每个从设备的引脚电容会累加 每个引脚约5-10pF

传输速率的计算公式很简单:

传输速率(bps) = SCK频率(Hz) × 数据位宽(bit)
实际吞吐量(bps) = 传输速率 × (有效数据位 / 总传输位)

举例:
SCK = 10MHz, 8位数据, 无额外开销
理论速率 = 10M × 8 = 80Mbps = 10MB/s
实际吞吐量 ≈ 10MB/s(因为SPI没有协议开销)

但要注意,实际吞吐量还要考虑片选切换时间、中断响应时间、DMA配置时间等。我做过一个测试,用10MHz的SPI读一个Flash芯片,理论速率是10MB/s,但实际用CPU轮询方式只能跑到6MB/s左右,换成DMA方式才接近9MB/s。

选型建议:如果你的系统需要高速SPI通信,优先考虑:1) 使用DMA而不是CPU轮询;2) 减少CS切换次数,尽量用连续传输模式;3) 缩短PCB走线,控制在5cm以内;4) 每个从设备单独走线,不要共用一条长总线。