QSPI 协议基础

QSPI 的全称是 Queued Serial Peripheral Interface,本质上是对传统 SPI 的“四条腿”升级版。传统 SPI 只有一条 MOSI 和一条 MISO,每次只能传 1 bit;QSPI 把 MOSI 和 MISO 扩展成四根数据线 IO0~IO3,一个时钟就能传 4 bit。我在早期一个数据采集板项目里,就因为用传统 SPI 读 Flash 太慢,被迫把时钟拉到 60 MHz 才勉强够用,换了 QSPI 后时钟降到 30 MHz 就把带宽翻了一倍——说白了,线宽比频率更值钱。

电气特性

QSPI 的电气特性和常规 SPI 基本保持一致,但多了一些线驱动和时序约束。下面是我总结的几个关键点:

  • 信号线定义:
    • CS(片选):低电平有效,单端 CMOS 电平
    • CLK(时钟):主设备输出,从设备输入
    • IO0~IO3(数据线):双向三态,用于四线模式
  • 电平标准:
    • 3.3V 是主流,1.8V 常见于低功耗芯片
    • 我遇到过 5V 容忍度的 Flash,但大部分 MCU 的 QSPI 控制器不支持 5V,需要电平转换
  • 驱动能力:
    • 四线同时翻转时,瞬态电流比单线 SPI 大 4 倍,PCB 走线长度建议控制在 5cm 以内
    • 串接 22Ω~33Ω 电阻能有效抑制反射——这个习惯我一直保留
  • 时钟极性/相位(CPOL/CPHA):
    • QSPI 通常工作在 Mode 0(CPOL=0, CPHA=0)或 Mode 3(CPOL=1, CPHA=1)
    • 大多数 Flash 芯片默认 Mode 0,手册里会写明“Data is captured on rising edge”
💡 实际测量提示:时钟频率超过 50 MHz 后,建议在 Flash 端就近放一个 0.1μF 去耦电容,我因为这个疏忽吃过一次眼图闭合的亏。

四线模式与 IO 复用

QSPI 有几种工作模式,我习惯把它们分成三类:

模式数据线典型场景
标准 SPI(1-1-1)IO0=MOSI, IO1=MISO兼容旧设备、配置寄存器
双线模式(2-2-2)IO0/IO1 双向读数据中等带宽
四线模式(4-4-4)IO0~IO3 双向高性能读写,主流选择

四线模式下的 IO 复用需要特别注意:Flash 芯片上电后默认是标准 SPI 模式,主机必须先发“Enable Quad”指令(通常 0x38 或 0x35),把 IO2 和 IO3 从 WP# 和 HOLD# 引脚切换成数据线。我在一个国产 Flash 平台上就踩过坑——发完 0x38 后没等 tSH(切换时间)就直接读状态寄存器,结果 IO2 还是高阻态,数据全是 0xFF。

⚠️ 踩坑警告:我曾经只加了一个 10ms 延时“保证没问题”,结果高温老化后部分芯片切换失败。正确的做法是:发完 4QE 指令后,回读状态寄存器的 Quad Enable 位确认置 1,再切换模式。

命令集与指令格式

QSPI Flash 的指令集遵循统一的 JEDEC 标准,但各家厂商会扩展私有指令。这里挑最常见的几条命令,你想想看,读数据、写数据、擦除——这三条占了 95% 的调用次数。

指令操作码说明
READ0x03标准单线读,时钟速率受限
FAST_READ0x0B带 dummy cycle,支持更高频率
QUAD_READ0x6B四线读,4 dummy cycles 后输出
QUAD_OUTPUT_READ0xEB四线读,地址和数据都在四线
PAGE_PROGRAM0x02标准写,每页 256 字节
QUAD_PAGE_PROGRAM0x32四线写,地址用四线传输
SECTOR_ERASE0x204KB 扇区擦除
BLOCK_ERASE_64K0xD864KB 块擦除

每条指令的时序结构大致分为三个阶段:

  1. 命令阶段:CS 拉低,主机在 CLK 上升沿输出 1 字节操作码
  2. 地址阶段:主机输出 3 或 4 字节地址(高位在前)
  3. 数据阶段:读操作这里会插入若干 dummy cycle(等待 Flash 内部准备好),然后主机/从机开始传输数据

举个例子,QUAD_READ(0x6B)的完整时序:

  • CS↓ → 发送 0x6B(单线) → 发送 3 字节地址(单线) → 4 个 dummy clock(期间 IO 置高阻) → 从机从 IO0~IO3 同时输出数据
⚡ 窍门:dummy cycle 个数不是固定的,部分芯片允许通过读状态寄存器 1 的 Bit[3:2] 配置。我习惯先读 SFDP 表获取默认值,而不是硬编码。

读写时序详解

读写时序的差异主要在 dummy cycle 和数据线宽上。下面这张 QSPI 四线读操作流程 清晰地展示了从模式配置到数据输出的完整路径:

QSPI 四线读操作流程 上电缺省模式 标准 SPI 发送 4QE 指令 0x35 / 0x38 读取状态寄存器 确认 QE=1 发送读指令 FAST_READ / QUAD_READ 发送 24 位地址 四线地址模式可选 Dummy Cycle 4 个时钟 IO0~IO3 同时输出数据 每个时钟 4 bit,带宽提升 4x ⚠️ 关键时序约束 • CS 保持低电平直到全部数据读完 • 读指令后必须跟随 CPU 等待(如 DMA 完成中断)

写时序和读类似,区别在于:

  • 没有 dummy cycle:写操作是同步的,主机在输出完地址后立即从 IO0~IO3 输出数据
  • 写使能(WREN)前置:每次写之前必须先发 0x06 写使能指令,否则 Flash 会忽略后续数据
  • 状态寄存器检查(WIP):Flash 内部编程需要时间,读状态寄存器 1 的 Bit[0](WIP)直到为 0 才能进行下一次操作
📌 性能关键:
- 四线读模式下,带宽 = 时钟频率 × 4(bit/s)
- 但实际有效带宽要扣除指令、地址和 dummy cycle 的开销
- 例如 80 MHz 时钟、4 dummy cycles,读 256 字节数据:开销约占 15%~20%

个人避坑清单

这部分我直接列出来,你在做驱动层或者 DMA 适配前最好先对照一遍:

  • CS 复位后必须高电平配置:有些 MCU 的 QSPI 控制器在系统复位时 CS 默认输出低,Flash 会误认为被选中,导致后续通信紊乱。我习惯在 GPIO 初始化阶段先把 CS 拉高,再切到 QSPI 外设模式。
  • 四线写不能用太快时钟:Flash 内部写操作受限于页编程时间(通常 0.5~5 ms),和时钟频率无关。我试过把 QUAD_PAGE_PROGRAM 的时钟拉到 100 MHz,带宽提升完全被编程时间抵消——白费功夫。
  • 多 Die Flash 切换注意 Bank 地址:大容量 QSPI Flash(比如 1 Gbit)内部包含多个 Die,切换 Die 需要发送 Bank Address 指令(0xB9 之类)。我遇到过一个项目交叉读写两个 Die,没处理切换,结果读出来的数据全是乱的,排查了两天才发现是 bank 没切。
  • DMA 与 QSPI 的接口对齐:稍后几章会专门讲 DMA,但这里提前提一句——QSPI 的 FIFO 深度通常只有 8~16 字节,如果你用 DMA 做大量数据传输,触发阈值设置不合理会导致频繁中断,反而降低性能。我习惯把 DMA 传输长度设成 FIFO 深度的整数倍。

好了,关于 QSPI 协议本身,上面这些够你上手写了。记住一点:电气特性决定了信号能不能传对,命令集决定了 Flash 听不听得懂,时序决定了传得快不快——这三样咬合起来,才能给 DMA 优化铺好路。