SPI外设驱动与DMA传输结合内存映射性能调优 - 第1节
1.1 SPI 总线架构与四线制工作原理
SPI(Serial Peripheral Interface,串行外设接口)是一种由 Motorola 公司推出的全双工、同步、主从式串行通信总线。在嵌入式系统中,SPI 凭借其极低的引脚开销(仅需 4 根线)和高达数十 MHz 的时钟速率,成为连接传感器、ADC/DAC、LCD 控制器、Flash 存储器等外设的首选接口之一。
1.1.1 总线拓扑结构
SPI 总线采用主-从(Master-Slave)架构。一个 SPI 主设备(通常是 MCU 或 SoC)可以连接一个或多个从设备。根据从设备的片选信号连接方式,分为两种典型拓扑:
| 拓扑类型 | 连接方式 | 优点 | 缺点 |
|---|---|---|---|
| 独立片选(标准模式) | 每个从设备独占一根 CS 线,SCLK/MOSI/MISO 共享 | 从设备完全独立,支持任意组合 | 从设备数量受限于主设备 GPIO 引脚数 |
| 菊花链(Daisy-Chain) | 所有从设备共享 CS,数据从主设备经第一个从设备依次传递 | 节省 CS 引脚,适合大量同型号设备 | 延迟累加,仅支持支持菊花链模式的设备 |
struct spi_device 的 chip_select 字段标识;菊花链模式则需要驱动层手动处理数据帧的拼接与拆分,通常不推荐在性能敏感场景中使用。
1.1.2 四线制信号定义
SPI 总线使用四根信号线完成全双工通信,每根线的角色在通信过程中是固定的:
- SCLK(Serial Clock) —— 串行时钟,由主设备产生,决定数据传输的比特率。每个时钟脉冲传输 1 bit 数据。
- MOSI(Master Out Slave In) —— 主设备输出、从设备输入。数据从主设备流向从设备。
- MISO(Master In Slave Out) —— 主设备输入、从设备输出。数据从从设备流向主设备。
- CS(Chip Select) —— 片选信号,由主设备控制,低电平有效(大多数器件)。选中从设备后,该设备才能参与通信。
1.1.3 SPI 全双工通信流程
SPI 的每一次数据传输都是同步且全双工的:主设备在 SCLK 的每个时钟周期同时发送 1 bit(通过 MOSI)并接收 1 bit(通过 MISO)。下图展示了单次 8-bit 传输的典型时序:
1.2 时钟极性(CPOL)与相位(CPHA)详解
SPI 协议定义了四种工作模式,由时钟极性(CPOL)和时钟相位(CPHA)两个参数组合决定。这两个参数决定了 SCLK 空闲时的电平状态以及数据采样/切换的边沿时刻。主设备和从设备必须使用相同的模式才能正常通信。
1.2.1 CPOL 与 CPHA 的定义
| 参数 | 取值 | 含义 |
|---|---|---|
| CPOL | 0 | SCLK 空闲时为低电平(低电平有效) |
| CPOL | 1 | SCLK 空闲时为高电平(高电平有效) |
| CPHA | 0 | 数据在 SCLK 的第一个跳变沿(上升沿或下降沿)被采样 |
| CPHA | 1 | 数据在 SCLK 的第二个跳变沿被采样 |
struct spi_device 的 mode 字段通过 SPI_CPOL 和 SPI_CPHA 标志位设置模式。例如:spi->mode = SPI_MODE_0 对应 CPOL=0, CPHA=0。
1.2.2 四种 SPI 模式对比
将 CPOL 和 CPHA 组合,得到 SPI 的四种标准模式。下表总结了每种模式的特点和典型应用场景:
| 模式 | CPOL | CPHA | 空闲电平 | 数据采样边沿 | 典型器件 |
|---|---|---|---|---|---|
| SPI Mode 0 | 0 | 0 | 低电平 | 第一个边沿(上升沿) | W25Qxx Flash, MCP3008 ADC |
| SPI Mode 1 | 0 | 1 | 低电平 | 第二个边沿(下降沿) | 某些 SD 卡、CC1101 射频模块 |
| SPI Mode 2 | 1 | 0 | 高电平 | 第一个边沿(下降沿) | 某些 LCD 控制器、MAX31865 温度传感器 |
| SPI Mode 3 | 1 | 1 | 高电平 | 第二个边沿(上升沿) | Microchip ENC28J60 以太网控制器 |
1.2.3 四种模式的时序对比图
下面的 SVG 图直观展示了四种模式下 SCLK 与数据采样的关系。注意观察空闲电平以及数据采样点的位置差异:
1.2.4 驱动开发中的模式配置
在 Linux 内核 SPI 驱动中,模式配置通常在设备树(Device Tree)或板级代码中完成。以下是一个典型的设备树配置示例:
/* 设备树中 SPI 从设备节点配置 */
&spi1 {
status = "okay";
cs-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
flash: w25q128@0 {
compatible = "winbond,w25q128";
reg = <0>; /* CS 索引 0 */
spi-max-frequency = <50000000>; /* 50 MHz */
spi-cpol; /* CPOL = 1 */
spi-cpha; /* CPHA = 1 */
/* 等效于 SPI Mode 3 */
};
};
/sys/bus/spi/devices/.../modalias 查看当前模式。
1.3 SPI 通信的典型时序与数据帧结构
一次完整的 SPI 传输通常包含以下步骤:
- 片选(CS)拉低:主设备将对应从设备的 CS 引脚置为低电平,激活从设备。
- 时钟启动:主设备在 SCLK 线上产生连续的时钟脉冲。
- 数据交换:在每个时钟周期,主设备通过 MOSI 发送 1 bit,同时从设备通过 MISO 返回 1 bit。
- 传输结束:主设备停止 SCLK,并将 CS 拉高,释放从设备。
数据帧的长度通常是 8 位(1 字节),但许多现代 SPI 器件支持 16 位、32 位甚至可变长度帧。在 Linux SPI 子系统中,struct spi_transfer 的 bits_per_word 字段用于指定每帧的位数:
struct spi_transfer t = {
.tx_buf = tx_data, /* 发送缓冲区 */
.rx_buf = rx_data, /* 接收缓冲区 */
.len = 4, /* 传输 4 字节 */
.bits_per_word = 16, /* 每帧 16 位 */
.speed_hz = 20000000, /* 20 MHz */
.cs_change = 0, /* 传输结束后不改变 CS */
};
1.4 本章小结
- SPI 总线采用主-从架构,四线制(SCLK、MOSI、MISO、CS)实现全双工同步通信。
- 时钟极性(CPOL)决定空闲电平,时钟相位(CPHA)决定数据采样边沿,两者组合定义四种 SPI 模式。
- 主设备和从设备必须使用相同的 SPI 模式,否则通信将失败。
- 在 Linux 内核中,通过设备树的
spi-cpol和spi-cpha属性或spi->mode标志位配置模式。 - 理解 SPI 时序是后续实现 DMA 传输和内存映射性能调优的基础。