1. SPI协议基础:从物理层到通信规则

大家好,我是你们的嵌入式系统讲师。今天咱们开始SPI NOR Flash驱动开发的第一课。说实话,SPI协议看起来简单,但我在实际项目中见过太多人在这上面栽跟头。咱们先把地基打牢,后面写驱动才能得心应手。

1.1 SPI总线简介

SPI,全称Serial Peripheral Interface,串行外设接口。它是由摩托罗拉公司在上世纪80年代推出的。你想想看,一个80年代的技术到现在还在广泛使用,说明它确实有两把刷子。

SPI是一种同步、全双工、主从式的串行通信协议。同步意味着有独立的时钟线;全双工意味着可以同时收发数据;主从式则意味着总线上只有一个设备能控制时钟。

我个人习惯把SPI比作一个「对话场景」:

  • 主机是老师,负责发号施令(产生时钟)
  • 从机是学生,听老师的指令回应
  • 数据线就像传纸条的通道

SPI总线的最大优势是什么?速度快。相比I2C的100kHz-400kHz,SPI轻松跑到几十MHz。我在一个项目中用过50MHz的SPI时钟,读Flash的速度那叫一个爽。

1.2 四线制详解:SCK/MOSI/MISO/CS

SPI总线通常需要4根线。咱们一个一个来看。

信号线 全称 方向 作用
SCK Serial Clock 主机→从机 时钟信号,由主机产生
MOSI Master Out Slave In 主机→从机 主机发送数据给从机
MISO Master In Slave Out 从机→主机 从机发送数据给主机
CS Chip Select 主机→从机 片选信号,低电平有效

SCK(时钟线):这是总线的「心跳」。没有时钟,SPI就玩不转。时钟频率决定了通信速度。我记得有一次调试,发现Flash读写偶尔出错,查了半天发现是时钟线走线太长,信号质量变差了。

MOSI(主机输出/从机输入):数据从主机流向从机。主机在时钟的某个边沿把数据放到这条线上,从机在另一个边沿采样。

MISO(主机输入/从机输出):数据从从机流向主机。注意,这条线在从机没有被选中时,必须处于高阻态。否则多个从机同时驱动这条线,就会打架。

CS(片选线):这条线决定了「谁在跟主机说话」。低电平有效,也就是说CS拉低时,对应的从机被选中。CS拉高时,从机释放总线。

重点提醒:CS信号必须在整个传输过程中保持低电平。我曾经见过一个新手,在发送每个字节之间把CS拉高再拉低,结果Flash根本不认数据。嗯,这里要注意,CS不能随便抖动。

1.3 SPI四种模式(CPOL/CPHA)配置

SPI有4种工作模式,由两个参数决定:CPOL(时钟极性)和CPHA(时钟相位)。

  • CPOL:决定时钟空闲时的电平。CPOL=0,空闲时SCK为低电平;CPOL=1,空闲时SCK为高电平。
  • CPHA:决定数据在哪个边沿采样。CPHA=0,在第一个边沿采样;CPHA=1,在第二个边沿采样。

说白了,这4种模式就是「时钟怎么摆,数据怎么取」的4种组合。咱们用表格来看:

模式 CPOL CPHA 采样边沿 数据变化边沿
模式0 0 0 上升沿 下降沿
模式1 0 1 下降沿 上升沿
模式2 1 0 下降沿 上升沿
模式3 1 1 上升沿 下降沿

你可能会问:「这么多模式,我该用哪个?」

答案是:看从机的数据手册。大多数SPI NOR Flash默认工作在模式0或模式3。为什么?因为这两种模式下,时钟的上升沿和下降沿刚好对称,硬件实现最简单。

我的经验:如果你不确定从机支持哪种模式,先试试模式0。我做过的大多数Flash芯片,模式0都能正常工作。如果不行,再试模式3。模式1和模式2用得比较少。

配置模式时,你需要在MCU的SPI外设寄存器中设置CPOL和CPHA位。比如在STM32上:

// STM32 SPI配置示例 - 模式0
SPI_InitTypeDef SPI_InitStruct;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;   // CPOL=0
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // CPHA=0
// 其他配置...
HAL_SPI_Init(&hspi);

为什么模式配置这么重要?因为主机和从机的模式必须一致。我曾经调试一个项目,Flash死活读不出正确数据,示波器一看,主机是模式0,从机配置成了模式3。时钟边沿对不上,数据全乱了。

1.4 多从机拓扑结构

一个SPI总线上可以挂多个从机。常见的连接方式有两种:

方式一:独立CS线

每个从机有自己的CS线,SCK、MOSI、MISO共享。这是最常用的方式。

  • 优点:每个从机独立控制,互不干扰
  • 缺点:占用GPIO多,N个从机需要N个CS引脚

方式二:菊花链(Daisy Chain)

所有从机共享CS、SCK,但数据像串糖葫芦一样传递。从机的MISO接到下一个从机的MOSI。

  • 优点:节省GPIO,只需要一个CS
  • 缺点:延迟大,所有从机必须支持菊花链模式

我个人在实际项目中几乎只用独立CS线的方式。为什么?因为简单可靠。菊花链虽然省引脚,但调试起来太痛苦了。我记得有一次用菊花链挂了4个Flash,数据传一圈回来,时序已经乱得没法看了。

避坑指南:多从机共享MISO线时,一定要确保未选中的从机输出高阻态。否则多个从机同时驱动MISO,轻则数据错误,重则烧坏IO口。我曾经见过一块板子,就是因为从机没有配置高阻态,MISO线上两个信号打架,最后MCU的IO口烧了。

多从机拓扑中还有一个容易忽略的问题:总线负载。每个从机都会给时钟线和数据线增加电容负载。挂的从机越多,信号质量越差。一般来说,一个SPI总线上挂3-4个从机是比较合理的。如果超过这个数,建议加SPI缓冲器或者分多个SPI接口。

小结

好了,这一章咱们把SPI协议的基础过了一遍。从四根信号线的功能,到4种模式的配置,再到多从机的连接方式。这些东西看起来简单,但都是后面写Flash驱动的基石。

下一章,咱们会深入SPI NOR Flash的内部结构,看看数据到底是怎么存进去、读出来的。到时候你会明白,为什么SPI协议要这么设计。