1. SPI协议基础解析
SPI(Serial Peripheral Interface)作为一种同步串行通信协议,在嵌入式系统中扮演着重要角色。我第一次接触SPI是在调试一块OLED屏幕时,当时被其全双工、高速传输的特性所吸引。与I2C相比,SPI不需要复杂的地址机制,通过简单的四线制就能实现主从设备之间的高效数据交换。
1.1 硬件接口组成
标准的SPI接口包含四条关键信号线:
- SCLK(Serial Clock):时钟信号,由主机产生
- MOSI(Master Out Slave In):主机输出,从机输入
- MISO(Master In Slave Out):主机输入,从机输出
- SS/CS(Slave Select/Chip Select):片选信号
在实际项目中,我遇到过HC32F460芯片的48脚封装SPI引脚分配问题。通过查阅数据手册发现,其SPI1的SCK对应PA5,MOSI对应PA7,MISO对应PA6。这种映射关系在不同芯片上可能完全不同,因此硬件设计时必须仔细核对手册。
重要提示:某些低功耗设备会复用SPI引脚为GPIO,配置时需特别注意外设引脚映射寄存器设置。
1.2 四种工作模式解析
SPI的四种模式由CPOL(Clock Polarity)和CPHA(Clock Phase)组合决定:
- 模式0:CPOL=0,CPHA=0 - 时钟空闲低电平,数据在第一个边沿采样
- 模式1:CPOL=0,CPHA=1 - 时钟空闲低电平,数据在第二个边沿采样
- 模式2:CPOL=1,CPHA=0 - 时钟空闲高电平,数据在第一个边沿采样
- 模式3:CPOL=1,CPHA=1 - 时钟空闲高电平,数据在第二个边沿采样
在STM32CubeMX配置SPI3的Mode3时,需要特别注意:
- 在Configuration选项卡选择CPOL=High
- 设置CPHA=2nd Edge Capture
- 确保从设备支持相同模式
2. SPI数据收发实现
2.1 基本收发流程
典型的SPI数据传输遵循以下步骤:
- 拉低对应从机的CS信号
- 主机生成时钟信号
- 主机通过MOSI发送数据(MSB或LSB优先)
- 从机通过MISO返回数据
- 传输完成后拉高CS信号
在STM32 HAL库中,发送函数参数设计为8位(而非16位)主要考虑:
- 兼容大多数SPI外设的8位数据寄存器
- 可通过多次调用实现16/32位传输
- 简化DMA配置复杂度
c复制// STM32 SPI发送示例
HAL_SPI_Transmit(&hspi1, (uint8_t*)txData, sizeof(txData), HAL_MAX_DELAY);
2.2 高速SPI设计要点
实现高速SPI通信时需注意:
-
PCB布局:
- 保持信号线等长(特别是SCK与数据线)
- 使用地平面减少干扰
- 短线连接(理想长度<10cm)
-
参数配置:
- 适当增加驱动强度
- 启用预取缓冲
- 使用DMA减少CPU开销
在NUC980 IBR从SPI-NAND启动失败案例中,问题常出在:
- 时序配置不匹配(需调整建立/保持时间)
- 未正确初始化SPI控制器
- Flash芯片ID识别错误
3. 高级应用场景
3.1 多从机管理
管理多个SPI从机的三种方案:
-
独立CS方案:
- 每个从机独占CS引脚
- 优点:简单可靠
- 缺点:占用IO资源
-
菊花链方案:
- 从机串联,数据级联传输
- 优点:节省CS线
- 缺点:延迟累积
-
复用CS方案:
- 配合解码器使用(如74HC138)
- 平衡IO占用与复杂度
3.2 SPI与DMA配合
以STM32H7 SPI DMA配置为例:
- 在CubeMX中启用SPI和DMA控制器
- 配置DMA流参数:
- 方向:内存到外设/外设到内存
- 数据宽度:匹配SPI数据大小
- 循环模式:根据需求选择
- 编写传输完成回调函数
c复制// DMA初始化片段
hdma_spi1_tx.Instance = DMA1_Stream0;
hdma_spi1_tx.Init.Request = DMA_REQUEST_SPI1_TX;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
HAL_DMA_Init(&hdma_spi1_tx);
4. 常见问题排查
4.1 无SCK信号问题
SPI接收字节时缺少SCK信号的常见原因:
-
时钟配置错误:
- 检查SPI外设时钟是否使能
- 验证预分频系数设置
-
硬件连接问题:
- 测量SCK引脚电平
- 检查线路通断
-
软件触发缺失:
- 确认已调用传输函数
- 检查CS信号状态
4.2 数据错位问题
MSB/LSB配置不当会导致:
- 接收数据位序颠倒
- CRC校验失败
- 协议解析错误
解决方案:
- 主从设备统一设置
- 必要时软件位序反转
- 使用逻辑分析仪验证波形
5. 协议对比与选型
5.1 SPI vs I2C vs UART
三种串行协议关键区别:
| 特性 | SPI | I2C | UART |
|---|---|---|---|
| 线制 | 4线(3+CS) | 2线 | 2线 |
| 速度 | 可达50Mbps | 通常400Kbps | 通常115Kbps |
| 拓扑 | 点对点/菊花链 | 多主多从 | 点对点 |
| 硬件复杂度 | 中等 | 低 | 低 |
| 寻址方式 | CS线选择 | 软件地址 | 无 |
5.2 AutoSAR SPI配置特点
相比普通MCU SPI配置,AutoSAR方案:
-
抽象层级更高:
- 通过ECUC文件定义
- 使用SpiDriver组件
-
功能更丰富:
- 支持Job/Sequence概念
- 提供异步通知机制
- 包含错误恢复策略
-
配置更复杂:
- 需要定义Channel/Job/Sequence
- 需处理Dem事件
- 需考虑BSW调度
在EB配置SPI DMA时,需要特别注意:
- 正确设置DMA通道优先级
- 配置传输完成中断
- 处理缓冲区对齐问题
6. 特殊应用实例
6.1 FPGA SPI实现
实现FPGA SPI Slave的关键点:
-
时钟域处理:
- 同步外部SCK到FPGA时钟域
- 处理跨时钟域数据
-
状态机设计:
- 检测CS下降沿
- 跟踪当前bit位置
- 处理模式0/3时序差异
-
数据采样策略:
- 根据CPHA选择采样边沿
- 实现数字滤波器消除毛刺
6.2 BQ79600唤醒方案
针对BQ79600的SPI唤醒流程:
-
硬件准备:
- 确保VIO电压匹配
- 上拉WP引脚
-
唤醒序列:
- 发送特定模式识别码
- 等待t_WAKE时间
- 验证设备ID
-
错误处理:
- 监测超时
- 重试机制
- 回退策略
在调试Py32F403 SPI外设时,发现其特殊之处在于:
- 支持8/16/32位数据宽度
- 具有独立的RX/TX FIFO
- 可配置硬件CRC
对于0.95寸4线SPI AMOLED屏幕,驱动时需注意:
- 初始化序列必须严格按时序发送
- 需要处理DC命令/数据选择线
- 合理设置SPI时钟(通常<20MHz)
最后分享一个实际调试经验:当SPI通信不稳定时,可以尝试降低时钟频率,逐步排查是时序问题还是硬件问题。我曾遇到STM32H7 SPI DMA传输偶尔丢数据的情况,最终发现是PCB走线过长导致的信号完整性问题,通过降低时钟频率到原计划的1/4后问题解决。
