QSPI 协议基础:四线 SPI 模式详解
标准 SPI 大家都熟悉——一个时钟、一根数据输出、一根数据输入,再加个片选。但到了 QSPI 时代,情况变了。QSPI 的全称是 Quad SPI,说白了就是“四路 SPI”。它用了四条数据线同时传数据,速度直接翻四倍。
我第一次用 QSPI 其实是踩坑踩出来的。当时用标准 SPI 读一个大容量的 W25Q64,发现吞吐不够。后来换成 QSPI,同样的时钟频率,一次就读 4 个 bit,速度快了不是一星半点。嗯,从那以后我就再也没回头看标准 SPI 了。
从标准 SPI 到 QSPI 的演进
先看一组对比,让你直观感受差异:
| 特性 | 标准 SPI | QSPI(四线模式) |
|---|---|---|
| 数据线数量 | 2 根(MOSI/MISO) | 4 根(IO0~IO3) |
| 每次时钟拍数传数 | 1 bit | 4 bit |
| 典型最大时钟 | 50~80 MHz | 80~133 MHz |
| 单线最大吞吐 | 50 Mbps | 1064 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 的电平和延时没配好。
四线模式并不是所有阶段都用四线。典型的读取命令分四个阶段:
- 命令阶段:发送 8 位指令,通常用单线(IO0)发出。
- 地址阶段:发送 24 位或 32 位地址,可以配置为单线或四线。
- 空周期(Dummy):等 Flash 准备好数据,通常需要 4~8 个时钟周期。
- 数据阶段:四线同时读取数据。
命令、地址、数据时序
下面这张表列出了几条最常用的 QSPI 读取指令的格式。注意看模式字段:
| 指令名称 | 指令码 | 地址模式 | 数据模式 | 空周期 |
|---|---|---|---|---|
| Fast Read Quad I/O | 0xEB | 四线 | 四线 | 6 |
| Fast Read Dual I/O | 0xBB | 双线 | 双线 | 6 |
| Quad Input Page Program | 0x32 | 单线 | 四线 | 0 |
| Read Status Register | 0x05 | 无 | 单线 | 0 |
举例说,最常用的 0xEB(Fast Read Quad I/O)时序是这样的:
- 片选拉低
- 在时钟上升沿发送 0xEB(8 位)
- 接着发送 24 位地址(四线模式下,每拍 4 位,共 6 拍)
- 然后空跑 6 个时钟周期(什么都不发,但四条线全高阻)
- 之后每拍从四条线同时读取 4 位数据,直到片选拉高
有人会问:空周期到底干嘛用?其实就是给 Flash 内部解码和寻址的时间。我记得调试一块 IS25LP064 时,它的规格书要求空周期至少 6 个,但我偷懒只设了 4 个,结果读回来的数据全是乱码。后来老老实实设回 6,一切正常。
QSPI 读取流程的核心逻辑
为了帮你快速建立整体概念,我画了一张流程图。把命令、地址、空周期、数据四个阶段的时序串起来:
这张图画得很直白了。你跟着箭头走一遍,就知道 QSPI 的读取时序是怎么样的。其实核心就四个块:片选、发命令、发地址、等一会、收数据。跟我用标准 SPI 时的思路一模一样,只是数据线变成了四根。
时序图里的几个要命细节
光看流程图还不够,实际调试时还要注意下面几个点:
- 时钟极性(CPOL)和相位(CPHA):QSPI 通常工作在模式 0(CPOL=0, CPHA=0)或模式 3。我遇到过一次明明是模式 0 的 Flash,结果 MCU 的 QSPI 控制器默认配成了模式 3,数据全部错位。所以上电后先读一下状态寄存器里的默认值。
- 双倍数据速率(DDR):有的 QSPI 芯片支持 DDR,也就是时钟上升沿和下降沿都采数据。这样吞吐再翻倍。但前提是你的主控也支持,我就被坑过,主控手册说支持 DDR,结果工程样片不支持。
- 连续读(Continuous Read):很多 QSPI Flash 支持连续读模式。一旦进入连续读,后续操作不需要再发指令和地址,直接收数据就行。退出时需要发特殊指令或拉高片选。我调试时没注意退出条件,导致后续读错误,折腾了好几个小时。
常见误区与避坑指南
最后聊几个我踩过的大坑,你以后遇到了能少走弯路:
- 引脚复用配置漏了:很多 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 协议基础就先聊这么多。记住一条核心原则:命令用单线,地址和数据用四线,空周期看手册。搞懂了时序图的四个阶段,后面读取异常排查才会有方向。