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”
四线模式与 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。
命令集与指令格式
QSPI Flash 的指令集遵循统一的 JEDEC 标准,但各家厂商会扩展私有指令。这里挑最常见的几条命令,你想想看,读数据、写数据、擦除——这三条占了 95% 的调用次数。
| 指令 | 操作码 | 说明 |
|---|---|---|
| READ | 0x03 | 标准单线读,时钟速率受限 |
| FAST_READ | 0x0B | 带 dummy cycle,支持更高频率 |
| QUAD_READ | 0x6B | 四线读,4 dummy cycles 后输出 |
| QUAD_OUTPUT_READ | 0xEB | 四线读,地址和数据都在四线 |
| PAGE_PROGRAM | 0x02 | 标准写,每页 256 字节 |
| QUAD_PAGE_PROGRAM | 0x32 | 四线写,地址用四线传输 |
| SECTOR_ERASE | 0x20 | 4KB 扇区擦除 |
| BLOCK_ERASE_64K | 0xD8 | 64KB 块擦除 |
每条指令的时序结构大致分为三个阶段:
- 命令阶段:CS 拉低,主机在 CLK 上升沿输出 1 字节操作码
- 地址阶段:主机输出 3 或 4 字节地址(高位在前)
- 数据阶段:读操作这里会插入若干 dummy cycle(等待 Flash 内部准备好),然后主机/从机开始传输数据
举个例子,QUAD_READ(0x6B)的完整时序:
- CS↓ → 发送 0x6B(单线) → 发送 3 字节地址(单线) → 4 个 dummy clock(期间 IO 置高阻) → 从机从 IO0~IO3 同时输出数据
读写时序详解
读写时序的差异主要在 dummy cycle 和数据线宽上。下面这张 QSPI 四线读操作流程 清晰地展示了从模式配置到数据输出的完整路径:
写时序和读类似,区别在于:
- 没有 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 优化铺好路。