3. SPI 总线详解:四线制、全双工通信与时钟极相
SPI(Serial Peripheral Interface,串行外设接口)是嵌入式系统中使用最广泛的同步串行总线之一。在 SPI 转 UART 扩展方案中,SPI 作为主控端的高速接口,承担着向 UART 扩展芯片下发数据、读取接收缓冲区的核心任务。理解 SPI 的四线制结构、全双工机制以及时钟极性与相位配置,是正确驱动扩展芯片的前提。
3.1 四线制信号定义
标准 SPI 总线使用四条信号线完成主从设备间的同步通信。下表列出了每条信号线的名称、方向与功能:
| 信号线 | 全称 | 方向(主→从) | 功能描述 |
|---|---|---|---|
| SCK | Serial Clock | 主→从 | 由主机产生的同步时钟,决定数据传输速率 |
| MOSI | Master Out Slave In | 主→从 | 主机输出数据线,从机在该线上接收数据 |
| MISO | Master In Slave Out | 从→主 | 从机输出数据线,主机在该线上接收数据 |
| CS | Chip Select | 主→从 | 片选信号,低电平有效,选中特定从机 |
设计要点:在 SPI 转 UART 芯片(如 WK2124、SC16IS752)中,CS 引脚通常连接主控 GPIO,用于在发送或接收数据前选中芯片。多从机共享 SCK/MOSI/MISO 总线时,必须确保同一时刻只有一个从机的 CS 被拉低。
3.2 全双工通信机制
SPI 最显著的特性是全双工:在每个时钟周期内,主机通过 MOSI 发送一位数据的同时,从机通过 MISO 返回一位数据。这意味着一次 SPI 传输在物理上总是同时完成一个字节的发送和一个字节的接收。
下图展示了 SPI 全双工传输的数据流结构:
实战理解:当主控向 SPI 转 UART 芯片发送一个字节的待发送数据时,芯片会同时返回一个字节——通常是当前接收 FIFO 的状态或已接收数据。因此,每次 SPI 读写操作都必须同时处理发送和接收两个方向的数据。
3.3 时钟极性与相位(CPOL & CPHA)
SPI 协议没有规定固定的时钟空闲电平与数据采样时刻,而是通过时钟极性(CPOL)和时钟相位(CPHA)两个参数来定义四种工作模式。主从设备必须使用相同的模式才能正确通信。
3.3.1 参数定义
| 参数 | 取值 | 含义 |
|---|---|---|
| CPOL | 0 | SCK 空闲时为低电平 |
| CPOL | 1 | SCK 空闲时为高电平 |
| CPHA | 0 | 数据在 SCK 的第一个边沿(上升或下降)被采样 |
| CPHA | 1 | 数据在 SCK 的第二个边沿被采样 |
3.3.2 四种模式对照
| 模式 | CPOL | CPHA | 空闲电平 | 数据采样边沿 | 数据输出边沿 |
|---|---|---|---|---|---|
| 模式 0 | 0 | 0 | 低 | 上升沿 | 下降沿 |
| 模式 1 | 0 | 1 | 低 | 下降沿 | 上升沿 |
| 模式 2 | 1 | 0 | 高 | 下降沿 | 上升沿 |
| 模式 3 | 1 | 1 | 高 | 上升沿 | 下降沿 |
常见错误:多数 SPI 转 UART 芯片(如 WK2124、SC16IS752)默认工作在模式 0(CPOL=0,CPHA=0)。如果主控 SPI 配置为模式 3,会导致数据采样错位,通信完全失败。调试时务必先确认芯片数据手册中指定的 SPI 模式。
3.4 时钟极相时序图
下图以模式 0 和模式 3 为例,展示 SCK、MOSI、MISO 在传输一个字节时的时序关系:
3.5 软件配置示例
以下代码展示在 STM32 HAL 库中配置 SPI 为模式 0(CPOL=0,CPHA=0),时钟分频为 8 分频:
// SPI 句柄定义
SPI_HandleTypeDef hspi1;
// SPI 初始化函数
void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER; // 主机模式
hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 全双工
hspi1.Init.DataSize = SPI_DATASIZE_8BIT; // 8 位数据
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL = 0
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA = 0
hspi1.Init.NSS = SPI_NSS_SOFT; // 软件 CS 控制
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 8 分频
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; // MSB 先发
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
}
配置检查清单:
- 确认主控 SPI 的 CPOL/CPHA 与扩展芯片数据手册一致
- 时钟频率不超过从机支持的最大 SCK(常见 SPI 转 UART 芯片上限为 20~40 MHz)
- 使用软件 CS 控制时,每次传输前拉低 CS,传输完成后拉高 CS
- 全双工模式下,每次发送后必须读取接收寄存器,避免 RX 溢出
3.6 多从机扩展架构
当系统需要扩展多路 UART 时,可以使用多个 SPI 转 UART 芯片共享同一 SPI 总线,通过独立的 CS 引脚进行片选。下图展示典型的多从机连接架构: