2. SPI 传输模式:模式 0/1/2/3 的时序图对比、全双工与半双工通信、单主多从拓扑结构
SPI(Serial Peripheral Interface)总线协议的核心在于其灵活的时钟极性和相位配置,这定义了四种标准传输模式。理解这些模式的区别、通信方式以及拓扑结构,是编写正确且高效 SPI 驱动的基础。本章将深入剖析这些概念,并通过可视化图表帮助建立直观认知。
2.1 SPI 模式 0/1/2/3 时序对比
SPI 模式由时钟极性(CPOL)和时钟相位(CPHA)两个参数决定:
- CPOL:决定 SCK 时钟信号在空闲状态时的电平。CPOL=0 表示空闲低电平,CPOL=1 表示空闲高电平。
- CPHA:决定数据采样(锁存)发生在 SCK 时钟的哪个边沿。CPHA=0 表示在第一个边沿采样,CPHA=1 表示在第二个边沿采样。
下表总结了四种标准模式的配置关系:
| SPI 模式 | CPOL | CPHA | 空闲时钟电平 | 数据采样边沿 | 数据输出边沿 |
|---|---|---|---|---|---|
| 模式 0 | 0 | 0 | 低电平 | 上升沿(第一个边沿) | 下降沿 |
| 模式 1 | 0 | 1 | 低电平 | 下降沿(第二个边沿) | 上升沿 |
| 模式 2 | 1 | 0 | 高电平 | 下降沿(第一个边沿) | 上升沿 |
| 模式 3 | 1 | 1 | 高电平 | 上升沿(第二个边沿) | 下降沿 |
下面通过内联 SVG 时序图直观展示四种模式的波形差异:
2.2 全双工与半双工通信
SPI 总线在物理层上天然支持全双工通信,但在实际应用中,根据从设备能力和数据传输需求,可以选择不同的通信模式。
2.2.1 全双工模式
标准 SPI 通信是全双工的。主设备在发送数据(MOSI)的同时,从设备也在发送数据(MISO)。这意味着每个时钟周期内,数据在两个方向上同时传输。这种模式适用于需要高吞吐量的场景,如音频数据流、高速 ADC 采集等。
2.2.2 半双工模式
在某些情况下,从设备可能只支持单向通信(如只读传感器),或者为了节省引脚,将 MOSI 和 MISO 合并为一条双向数据线(3 线制 SPI)。此时通信退化为半双工模式,数据在同一根线上分时传输。
spi-3wire 标志,并在驱动中正确配置 SPI 控制器的模式寄存器。
下面通过 SVG 图对比全双工与半双工的数据流向:
2.3 单主多从拓扑结构
SPI 总线采用主从架构,一个主设备可以连接多个从设备。常见的拓扑结构有两种:独立片选和菊花链。
2.3.1 独立片选拓扑
这是最常用的方式。主设备为每个从设备分配一个独立的片选信号(CS/SS)。当主设备需要与某个从设备通信时,将该从设备的 CS 线拉低,其他从设备的 CS 保持高电平(高阻态)。所有从设备共享 SCK、MOSI 和 MISO 信号线。
2.3.2 菊花链拓扑
在菊花链中,所有从设备共享一个片选信号。数据从主设备发出,经过第一个从设备处理后,再传递给下一个从设备,依次类推。这种拓扑减少了主设备的引脚需求,但增加了通信延迟和复杂性,通常用于移位寄存器链或某些特定的 ADC 芯片组。
下面通过 SVG 图展示单主多从的两种拓扑结构:
2.4 驱动配置示例
在 Linux 内核中,配置 SPI 模式通过设置 spi_device 结构体的 mode 字段实现。以下代码片段展示了如何在设备驱动中设置模式 0 和全双工通信:
#include <linux/spi/spi.h>
static int my_spi_probe(struct spi_device *spi)
{
int ret;
/* 设置 SPI 模式为模式 0 (CPOL=0, CPHA=0) */
spi->mode = SPI_MODE_0;
/* 设置最大时钟频率为 10 MHz */
spi->max_speed_hz = 10 * 1000 * 1000;
/* 设置每个字的位数为 8 位 */
spi->bits_per_word = 8;
/* 应用配置 */
ret = spi_setup(spi);
if (ret < 0) {
dev_err(&spi->dev, "spi_setup failed: %d\n", ret);
return ret;
}
/* 执行全双工传输 */
struct spi_transfer t = {
.tx_buf = tx_buffer,
.rx_buf = rx_buffer,
.len = 32,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
ret = spi_sync(spi, &m);
return 0;
}