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模式选择与设备匹配

实际项目中怎么选模式?我一般按这个步骤来:

  1. 查从设备数据手册——手册里一定会写明支持的SPI模式
  2. 看时序图——确认数据采样沿和输出沿
  3. 配置主控——在Linux设备树或MCU寄存器里设置对应的CPOL和CPHA
  4. 用示波器验证——抓SCLK和MOSI/MISO,确认时序正确

举个例子,某款常见的SPI Flash芯片W25Q64,它支持模式0和模式3。你配置成模式0,SCLK空闲低,数据在上升沿采样;配置成模式3,SCLK空闲高,数据在上升沿采样。两种都能用,但要注意:一旦选定,整个通信过程中不能切换。

核心原则:SPI模式的选择权在Master,但必须匹配Slave的规格。Master可以主动适配,Slave只能被动响应。

1.4 SPI知识体系总览

下面这张图是我自己整理的SPI知识框架,涵盖了本章的核心内容。你可以把它当作一个快速索引:

SPI总线知识体系结构图 SPI总线知识体系 SPI总线核心 物理层(四线制) 协议层(模式配置) 应用层(设备匹配) SCLK MOSI MISO CS CPOL CPHA 4种模式 设备树配置 时序匹配 示波器验证 说明 SPI总线从物理层到应用层层层递进。物理层决定接线,协议层决定时序,应用层决定设备兼容性。

1.5 本章小结

这一章我们聊了SPI总线最基础的东西:四根信号线各自干什么、四种工作模式怎么配。这些东西看起来简单,但实际项目中出问题往往就出在这些基础环节上。

我记得有一次帮同事排查一个SPI通信问题,他调了两天没搞定。我过去一看,CS引脚在原理图上标的是CS#,他以为是高电平有效,结果代码里配成了高电平选通——嗯,从设备一直没被选中,当然没反应。所以,永远不要想当然,永远以数据手册为准。

给新手的一个建议:刚开始学SPI,别急着上DMA、中断那些高级功能。先用轮询模式把四根线调通,确认模式配置正确,数据收发正常。基础打牢了,后面优化才有意义。