2、SPI总线协议基础:从物理层到实战对比
大家好,我是你们的嵌入式Linux驱动讲师。今天我们来聊聊SPI总线协议的基础知识。说实话,SPI和I2C是我在驱动移植工作中打交道最多的两种总线。很多初学者觉得SPI协议简单,不就是四根线嘛——但真正到了调试阶段,各种坑就冒出来了。
我个人习惯把SPI协议拆成四个维度来理解:物理层长什么样、时钟极性怎么配、时序怎么分析、以及它和I2C到底有啥区别。咱们一个一个来。
2.1 SPI物理层特性
SPI的全称是Serial Peripheral Interface,串行外设接口。它由Motorola公司提出,后来成了事实上的工业标准。
物理层信号线:
- SCLK(Serial Clock):主设备产生的时钟信号
- MOSI(Master Out Slave In):主设备输出,从设备输入
- MISO(Master In Slave Out):主设备输入,从设备输出
- SS/CS(Slave Select/Chip Select):片选信号,低电平有效
嗯,这里要注意:SPI是全双工通信。什么意思?就是发送和接收可以同时进行。这一点和I2C完全不同,I2C是半双工的,同一时间只能一个方向传数据。
我在项目中遇到过一个问题:某款ADC芯片的MISO引脚在片选拉高后没有进入高阻态,导致多个从设备共用MISO线时产生冲突。后来我加了一个三态缓冲器才解决。所以大家设计多从设备SPI总线时,一定要确认从设备的MISO是否支持高阻态输出。
关键参数速查:
- 最大速率:通常10MHz~50MHz,高速器件可达100MHz+
- 通信距离:板级通信(几厘米到几十厘米),远距离需加驱动
- 从设备数量:理论上无限,但受限于片选引脚和负载电容
- 数据格式:MSB First(大多数器件)或LSB First
2.2 SPI四种工作模式(CPOL/CPHA)
这是SPI协议里最容易搞混的地方。我刚开始学的时候也绕了好一阵子。说白了,就是时钟极性(CPOL)和时钟相位(CPHA)的组合。
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最常用。模式0是"空闲低、上升采",模式3是"空闲高、上升采"。你想想看,大多数SPI Flash和传感器都默认用模式0或模式3。
我曾经踩过一个坑:某款温湿度传感器手册上写支持"SPI模式0",但我用模式3也能通信。后来仔细看时序图才发现,它其实对时钟沿不敏感,只要保证建立时间和保持时间就够了。但这种情况很少见,千万不要赌,一定要按手册配。
2.3 SPI总线时序分析
时序分析是驱动移植的核心能力。说白了,就是看波形图,搞清楚数据什么时候被采样、什么时候被输出。
我们以最常用的模式0为例:
SCLK: ▔▁▔▁▔▁▔▁▔▁▔▁▔▁▔▁
┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
└─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘
MOSI: ──┐ ┌───┐ ┌───┐ ┌───┐ ┌──
└───┘ └───┘ └───┘ └───┘
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
MISO: ──┐ ┌───┐ ┌───┐ ┌───┐ ┌──
└───┘ └───┘ └───┘ └───┘
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
采样点: ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
看到没?在模式0下,数据在SCLK的上升沿被采样,在下降沿被更新。主设备在下降沿把数据放到MOSI上,从设备在上升沿读取。反过来,从设备在下降沿把数据放到MISO上,主设备在上升沿读取。
这里有个关键点:建立时间(tSU)和保持时间(tHD)。数据必须在采样沿之前稳定下来,并且在采样沿之后保持一段时间。不同器件的时序要求不一样,我建议你在移植驱动时,一定要去查数据手册里的时序参数表。
避坑指南:我曾经在移植一款LCD驱动时,发现显示偶尔出现花屏。用示波器一抓,发现SCLK频率太高,导致数据建立时间不足。把时钟从20MHz降到10MHz,问题就解决了。所以,不要一味追求高速,稳定才是第一位的。
2.4 SPI与I2C对比
很多初学者会问:什么时候用SPI,什么时候用I2C?我的回答是:看需求。
下面这张表是我自己总结的,你可以收藏一下:
| 对比项 | SPI | I2C |
|---|---|---|
| 信号线数量 | 4根(SCLK, MOSI, MISO, CS) | 2根(SCL, SDA) |
| 通信方式 | 全双工 | 半双工 |
| 传输速率 | 通常10~50MHz,可达100MHz+ | 标准100kHz,快速400kHz,高速3.4MHz |
| 从设备寻址 | 片选信号(硬件寻址) | 7位或10位地址(软件寻址) |
| 总线冲突 | 无(片选独立) | 需要仲裁机制 |
| 从设备数量 | 受限于片选引脚 | 理论上127个(7位地址) |
| 硬件复杂度 | 简单,无上拉电阻 | 需要上拉电阻,有开漏输出 |
| 典型应用 | Flash、ADC/DAC、LCD、传感器 | EEPROM、温度传感器、RTC |
我个人习惯这样选型:
- 需要高速传输(>1MHz)→ 选SPI
- 需要全双工通信 → 选SPI
- 引脚资源紧张 → 选I2C
- 需要挂载大量从设备 → 选I2C
- 对实时性要求高 → 选SPI(I2C有仲裁延迟)
你想想看,为什么SPI Flash那么普遍?因为SPI的速率可以轻松跑到几十兆,而I2C的EEPROM最多也就几兆。但反过来,为什么很多传感器用I2C?因为传感器数据量小,两根线就能搞定,省引脚。
核心结论:SPI是"速度优先"的协议,I2C是"引脚优先"的协议。没有谁好谁坏,只有谁更合适。
2.5 本章知识体系总览
下面这张SVG图是我画的,把SPI协议基础的核心逻辑串起来了。你可以把它当作一个思维导图来用。
这张图把SPI协议基础的四个维度串在了一起。你从物理层入手,理解四根线怎么接;然后配置CPOL/CPHA,选对工作模式;接着用示波器抓时序,验证建立时间和保持时间;最后根据项目需求,决定用SPI还是I2C。
好了,这一章的内容就到这里。SPI协议基础是驱动移植的基石,你把它吃透了,后面移植SPI Flash、SPI LCD、SPI传感器的时候就会轻松很多。