1. SPI总线概述
SPI,全称是Serial Peripheral Interface,串行外设接口。这玩意儿在嵌入式系统里太常见了,几乎每个工程师都会打交道。我最早接触SPI是在做一款工业传感器采集板的时候,当时选型时对比了好几种总线,最后还是用了SPI——原因很简单,它够快、够简单、够可靠。
说白了,SPI是一种全双工、同步、主从式的串行通信总线。由Motorola公司在上世纪80年代推出,一直用到现在。你想想看,三十多年了还没被淘汰,说明它确实有两把刷子。
核心特点速览:
- 全双工通信:发送和接收可以同时进行
- 主从架构:一个Master,可以挂多个Slave
- 同步时钟:由Master提供SCLK,所有设备同步
- 高速传输:典型速率从几MHz到几十MHz
1.1 四线制功能解析
标准的SPI总线就四根线,不多不少。我见过不少新手工程师把这四根线搞混,结果调了两天发现是MOSI和MISO接反了——嗯,我也干过这种事。
| 信号线 | 全称 | 方向 | 功能说明 |
|---|---|---|---|
| SCLK | Serial Clock | Master → Slave | 时钟信号,由Master产生,决定通信速率 |
| MOSI | Master Out Slave In | Master → Slave | 主设备输出,从设备输入 |
| MISO | Master In Slave Out | Slave → Master | 从设备输出,主设备输入 |
| CS | Chip Select | Master → Slave | 片选信号,低电平有效,选中对应从设备 |
这里有个关键点:SCLK和CS都由Master控制。从设备是被动的,它只能等Master给它时钟才能干活。我曾经在一个项目里遇到过从设备没反应的情况,查了半天发现是CS引脚的上拉电阻没焊——CS浮空,从设备一直处于复位状态。
实战小技巧:调试SPI时,先用示波器抓SCLK和CS。如果SCLK有波形但CS一直高,那问题大概率在GPIO控制上。如果SCLK都没有,先查时钟配置。
1.2 SPI四种工作模式详解
SPI的四种模式,核心就是两个参数:CPOL(Clock Polarity,时钟极性)和CPHA(Clock Phase,时钟相位)。
- CPOL:决定SCLK空闲时的电平
- CPOL=0:空闲时SCLK为低电平
- CPOL=1:空闲时SCLK为高电平
- CPHA:决定数据在哪个时钟沿采样
- CPHA=0:在第一个时钟沿采样(上升沿或下降沿,取决于CPOL)
- CPHA=1:在第二个时钟沿采样
组合起来就是四种模式。我建议你直接记这张表,比看时序图快得多:
| 模式 | CPOL | CPHA | 空闲时钟电平 | 数据采样沿 | 数据输出沿 |
|---|---|---|---|---|---|
| 模式0 | 0 | 0 | 低电平 | 上升沿 | 下降沿 |
| 模式1 | 0 | 1 | 低电平 | 下降沿 | 上升沿 |
| 模式2 | 1 | 0 | 高电平 | 下降沿 | 上升沿 |
| 模式3 | 1 | 1 | 高电平 | 上升沿 | 下降沿 |
最常见的模式是模式0和模式3。为什么?因为很多Flash芯片、ADC芯片默认就支持这两种。我个人习惯先用模式0,如果通信不稳定再换模式3试试。
避坑指南:我曾经在一个项目里,主控用模式0,从设备用模式3,结果数据全是乱的。示波器一看,采样沿完全对不上。记住:主设备和从设备的模式必须一致,否则数据错位是必然的。
1.3 SPI模式选择与设备匹配
实际项目中怎么选模式?我一般按这个步骤来:
- 查从设备数据手册——手册里一定会写明支持的SPI模式
- 看时序图——确认数据采样沿和输出沿
- 配置主控——在Linux设备树或MCU寄存器里设置对应的CPOL和CPHA
- 用示波器验证——抓SCLK和MOSI/MISO,确认时序正确
举个例子,某款常见的SPI Flash芯片W25Q64,它支持模式0和模式3。你配置成模式0,SCLK空闲低,数据在上升沿采样;配置成模式3,SCLK空闲高,数据在上升沿采样。两种都能用,但要注意:一旦选定,整个通信过程中不能切换。
核心原则:SPI模式的选择权在Master,但必须匹配Slave的规格。Master可以主动适配,Slave只能被动响应。
1.4 SPI知识体系总览
下面这张图是我自己整理的SPI知识框架,涵盖了本章的核心内容。你可以把它当作一个快速索引:
1.5 本章小结
这一章我们聊了SPI总线最基础的东西:四根信号线各自干什么、四种工作模式怎么配。这些东西看起来简单,但实际项目中出问题往往就出在这些基础环节上。
我记得有一次帮同事排查一个SPI通信问题,他调了两天没搞定。我过去一看,CS引脚在原理图上标的是CS#,他以为是高电平有效,结果代码里配成了高电平选通——嗯,从设备一直没被选中,当然没反应。所以,永远不要想当然,永远以数据手册为准。
给新手的一个建议:刚开始学SPI,别急着上DMA、中断那些高级功能。先用轮询模式把四根线调通,确认模式配置正确,数据收发正常。基础打牢了,后面优化才有意义。