QSPI 协议基础:四线 SPI 模式详解

标准 SPI 大家都熟悉——一个时钟、一根数据输出、一根数据输入,再加个片选。但到了 QSPI 时代,情况变了。QSPI 的全称是 Quad SPI,说白了就是“四路 SPI”。它用了四条数据线同时传数据,速度直接翻四倍。

我第一次用 QSPI 其实是踩坑踩出来的。当时用标准 SPI 读一个大容量的 W25Q64,发现吞吐不够。后来换成 QSPI,同样的时钟频率,一次就读 4 个 bit,速度快了不是一星半点。嗯,从那以后我就再也没回头看标准 SPI 了。

从标准 SPI 到 QSPI 的演进

先看一组对比,让你直观感受差异:

特性标准 SPIQSPI(四线模式)
数据线数量2 根(MOSI/MISO)4 根(IO0~IO3)
每次时钟拍数传数1 bit4 bit
典型最大时钟50~80 MHz80~133 MHz
单线最大吞吐50 Mbps1064 Mbps(4 倍速)
命令/地址阶段通常单线串行可配置为单线或四线
是否需要额外引脚不需要复用 SPI 引脚(IO0=MOSI, IO1=MISO)

为什么 QSPI 能这么快?因为它在同样的时钟周期里并行传了更多数据。你想想看,同样是 100MHz 时钟,SPI 每秒只能吃 100Mbit,QSPI 一次吃 4 个,每秒就是 400Mbit。容量越大的 Flash,这种优势越明显。

QSPI 的四线数据模式

QSPI 的四条线分别叫 IO0、IO1、IO2、IO3。注意,这可不是随便命名的。IO0 和 IO1 实际上就是原来的 MOSI 和 MISO 引脚复用的。IO2 和 IO3 通常是普通的 GPIO,但在 QSPI 模式下会被控制器接管。

我个人习惯在画原理图时,把这四个脚标清楚。不然一旦换方案,回头查引脚定义会特别痛苦。我在一个项目里就吃过这亏,换芯片后莫名其妙读出来都是 0x00,查了两天才发现是 IO2 和 IO3 的电平和延时没配好。

四线模式并不是所有阶段都用四线。典型的读取命令分四个阶段:

  1. 命令阶段:发送 8 位指令,通常用单线(IO0)发出。
  2. 地址阶段:发送 24 位或 32 位地址,可以配置为单线或四线。
  3. 空周期(Dummy):等 Flash 准备好数据,通常需要 4~8 个时钟周期。
  4. 数据阶段:四线同时读取数据。
我的一个小技巧: 地址阶段尽量用四线模式。虽然地址本身只有 3~4 字节,但能省不少时间。尤其当你的固件需要频繁跳转地址时,累积下来性能提升很明显。

命令、地址、数据时序

下面这张表列出了几条最常用的 QSPI 读取指令的格式。注意看模式字段:

指令名称指令码地址模式数据模式空周期
Fast Read Quad I/O0xEB四线四线6
Fast Read Dual I/O0xBB双线双线6
Quad Input Page Program0x32单线四线0
Read Status Register0x05无单线0

举例说,最常用的 0xEB(Fast Read Quad I/O)时序是这样的:

  • 片选拉低
  • 在时钟上升沿发送 0xEB(8 位)
  • 接着发送 24 位地址(四线模式下,每拍 4 位,共 6 拍)
  • 然后空跑 6 个时钟周期(什么都不发,但四条线全高阻)
  • 之后每拍从四条线同时读取 4 位数据,直到片选拉高

有人会问:空周期到底干嘛用?其实就是给 Flash 内部解码和寻址的时间。我记得调试一块 IS25LP064 时,它的规格书要求空周期至少 6 个,但我偷懒只设了 4 个,结果读回来的数据全是乱码。后来老老实实设回 6,一切正常。

注意: 不同厂家的 Flash 对空周期数要求不一样。而且在四线模式下空周期时,四条 IO 线的状态必须设置为高阻或浮空,千万不能驱动,否则会烧坏引脚。

QSPI 读取流程的核心逻辑

为了帮你快速建立整体概念,我画了一张流程图。把命令、地址、空周期、数据四个阶段的时序串起来:

QSPI 四线读取流程图(Fast Read Quad I/O 0xEB) 片选拉低 (CS#) 命令阶段: 发送 0xEB (单线) 地址阶段: 24位地址 (四线, 6拍) 空周期 (Dummy): 6时钟 数据阶段: 四线并行读取 提示: 命令、地址、数据阶段的 线数可以独立配置。 比如 0x6B 使用单线命令+ 单线地址+单线数据, 可兼容低速系统。

这张图画得很直白了。你跟着箭头走一遍,就知道 QSPI 的读取时序是怎么样的。其实核心就四个块:片选、发命令、发地址、等一会、收数据。跟我用标准 SPI 时的思路一模一样,只是数据线变成了四根。

时序图里的几个要命细节

光看流程图还不够,实际调试时还要注意下面几个点:

  • 时钟极性(CPOL)和相位(CPHA):QSPI 通常工作在模式 0(CPOL=0, CPHA=0)或模式 3。我遇到过一次明明是模式 0 的 Flash,结果 MCU 的 QSPI 控制器默认配成了模式 3,数据全部错位。所以上电后先读一下状态寄存器里的默认值。
  • 双倍数据速率(DDR):有的 QSPI 芯片支持 DDR,也就是时钟上升沿和下降沿都采数据。这样吞吐再翻倍。但前提是你的主控也支持,我就被坑过,主控手册说支持 DDR,结果工程样片不支持。
  • 连续读(Continuous Read):很多 QSPI Flash 支持连续读模式。一旦进入连续读,后续操作不需要再发指令和地址,直接收数据就行。退出时需要发特殊指令或拉高片选。我调试时没注意退出条件,导致后续读错误,折腾了好几个小时。
实战经验: 当你第一次调 QSPI 读数据时,别急着上四线。先用单线模式(比如 0x03 指令)确认基本通信没问题。能读到正确的状态寄存器值了,再切换到四线模式。这样好定位故障方向。

常见误区与避坑指南

最后聊几个我踩过的大坑,你以后遇到了能少走弯路:

  • 引脚复用配置漏了:很多 MCU 的 QSPI 引脚和普通 GPIO/FSPI 是复用的。我年轻时有一次只配了 SPI 模式,没切换到 QSPI 模式,结果 IO2/IO3 一直输出乱电平。后来在手册里找到 GPIO_AFx 寄存器,才搞定。
  • 空周期数量不对:这个前面提过了。不同 Flash 甚至同一 Flash 在不同频率下要求的空周期数都可能不同。我曾经为了省时间,直接 Copy 了别人一个工程里的数值,结果读 W25Q128JV 怎么都不对。后来查手册才发现他的 Flash 频率低,空周期 4 就够了,我跑到 80MHz 需要 8 个。
  • 片选时序抖动:QSPI 要求每次操作开始前 CS# 必须先拉高至少一个时钟(恢复时间)。我有个项目用逻辑分析仪抓才发现 CS# 在高电平只保持了 5ns,而 Flash 要求 10ns,数据就丢了。所以在软件里加了几条 NOP 延时就好了。

嗯,关于 QSPI 协议基础就先聊这么多。记住一条核心原则:命令用单线,地址和数据用四线,空周期看手册。搞懂了时序图的四个阶段,后面读取异常排查才会有方向。