QSPI 基础:什么是 QSPI,与 SPI 的区别及优势
1.1 什么是 QSPI?
QSPI 的全称是 Quad SPI,说白了就是传统 SPI 的「四通道加强版」。它保留了 SPI 的主从架构、时钟线(CLK)、片选线(CS),但数据线从原来的两条(MOSI / MISO)扩展到了四条(IO0 ~ IO3)。
我最初接触 QSPI 是在一个需要高速读取外部 Flash 的项目里。当时传统的 SPI Flash 读取速度撑死几十兆字节每秒,但系统需要实时加载字库和波形数据,瓶颈非常明显。改用 QSPI 后,同样的时钟频率下带宽直接翻了两番 —— 嗯,这个数字让我印象很深。
1.2 SPI 与 QSPI 关键区别
很多人以为 QSPI 只是把引脚数翻倍,其实没那么简单。你想想看,传统 SPI 每条数据线是单向的(发送或接收),而 QSPI 的 4 条数据线是 双向 的 —— 根据命令字的不同,可以同时用来发送地址和数据。这背后涉及 多点复用 和 命令-地址-数据 的时序分层。
| 对比项 | 传统 SPI | QSPI(四线) |
|---|---|---|
| 数据线数量 | 2 条(MOSI, MISO) | 4 条(IO0~IO3) |
| 最大带宽(@60MHz) | 60 Mbps | 240 Mbps |
| 双向传输 | 否(单向固定) | 是(根据命令切换方向) |
| 命令集复杂度 | 简单 | 需要扩展命令(如 FAST_READ_QUAD) |
| XIP 支持 | 极少见 | 原生支持(内存映射模式) |
| 引脚复用 | 通常独立 | 可与 GPIO 或 JTAG 复用 |
我个人习惯在选型表里把 QSPI 的“四线模式”和“双倍数据率(DDR)模式”分开看。很多芯片支持 QSPI 但只支持 SDR(单数据率),这时候带宽其实只比普通 SPI 快一倍,而非四倍。
1.3 QSPI 的核心优势
为什么我们要从 SPI 迁移到 QSPI?核心原因只有一个:带宽瓶颈。我曾经在调试一个 LCD 驱动时,SPI 的速率已经顶到 80MHz,但刷一帧 480×272 的图片仍然要 30 多毫秒。换成 QSPI 后,同样的时钟频率下刷新时间直接压到 8 毫秒以内 —— 这个差距在实时性要求高的场景里是决定性的。
- 更高的吞吐量:四倍数据线,配合流水线命令,持续读取速度接近理论极限。
- 更少的引脚:相比于并行 Flash(需要 24 条以上引脚),QSPI 只用了 6 条核心引脚(CLK, CS, IO0~IO3)。
- 支持 XIP:这是 QSPI 最实用的延伸。XIP(Execute in Place)允许 CPU 直接像访问内部 RAM 一样读取 QSPI Flash 中的代码,不用先把代码复制到 SRAM。这一点在内存受限的 MCU 上至关重要。
1.4 QSPI 与 XIP 的关系
XIP 并不是 QSPI 强制拥有的功能,而是 QSPI 控制器提供的 内存映射模式。当 QSPI 配置成内存映射后,CPU 发出读地址,控制器自动解析成 QSPI 命令序列(发送命令→地址→dummy cycles→读数据),整个过程对 CPU 透明。换句话说,你直接用指针访问外部 Flash 就行。
我记得第一次看到 QSPI 内存映射成功时,用调试器查看那个 0x90000000 地址段,里面直接显示了 Flash 里的数据,那种感觉就像把外部存储器「挂载」到了系统总线上一样。当然,这里有个坑 —— 我曾经因为没有配置 dummy cycles 导致高位数据总是错位,逻辑分析仪抓了半天才意识到 Flash 需要额外的等待周期才能切换方向。
1.5 一个简单的 QSPI 读命令序列
下面是一个针对 W25Q64(QSPI Flash)的四通道快速读命令(0xEB)的时序伪代码。实际编程中需要配置控制器的 FIFO 和 dummy 周期数。
// 伪代码:QSPI 四通道读模式(SDR)
// 配置 QSPI 控制器为四线模式
QSPI_Config(QuadMode, SDR, DummyCycles = 4);
// 发送命令字节 0xEB
QSPI_Write(0xEB); // 占用 IO0(单线)
// 发送 24 位地址(MSB 先)
QSPI_Write(0x00); // 地址高位
QSPI_Write(0x10); // 地址中位
QSPI_Write(0x00); // 地址低位
// 4 个 dummy 周期(用于方向切换)
QSPI_Dummy(4);
// 开始读取数据(从 IO0~IO3 同时接收)
for (i = 0; i < 256; i++) {
buffer[i] = QSPI_Read(); // 每次读取 4 字节
}
看到这段代码你可能想问:为什么地址传输还是单线?嗯,这里有个设计细节 —— 命令和地址阶段通常保持单线或双线模式,目的是兼容更老的 Flash 芯片。只有后面的数据阶段才切换到四线。我最早就是在这个阶段栽过跟头:我以为整个序列都是四线,结果 Flash 根本不响应。后来用逻辑分析仪一量,才发现地址字节只出现在了 IO0 上。