2、Flash硬件接口详解:SPI接口协议、QSPI与Octal SPI、ONFI与Toggle接口标准
做Flash驱动,第一关就是搞懂硬件接口。说白了,你得知道芯片怎么跟你“说话”。
我刚开始接触Flash时,以为接口就是几个引脚拉一拉。后来踩了坑才明白——接口协议选不对,后面全是白干。今天咱们就把主流的几种接口掰开揉碎讲清楚。
2.1 SPI接口协议:最经典的串行总线
SPI,全称Serial Peripheral Interface。这玩意儿在嵌入式领域太常见了。我敢说,十个工程师里九个都用过。
它用四根线:
- SCLK:时钟线,由主机提供
- MOSI:主机输出,从机输入
- MISO:主机输入,从机输出
- CS:片选线,低电平有效
SPI是全双工的。什么意思?就是发数据和收数据可以同时进行。这一点比I2C强不少。
核心要点:SPI的时钟极性(CPOL)和时钟相位(CPHA)可以配置。一共四种模式。我见过不少新手在这上面翻车——主设备和从设备模式不匹配,数据全读错。
实际项目中,SPI的速率通常在几十MHz。比如我常用的W25Q系列,支持最高104MHz的时钟。但要注意,频率越高,PCB走线要求也越高。我曾经在一块两层板上跑80MHz,结果数据老是错位。后来发现是信号反射问题,加了个22Ω的串联电阻才搞定。
个人经验:SPI的CS引脚一定要用GPIO控制,别图省事直接接地。否则多个设备挂在同一总线上时,你会后悔的。
2.2 QSPI与Octal SPI:从1位到多位的进化
标准SPI一次只能传1位数据。对于大容量Flash来说,这太慢了。于是有了QSPI。
QSPI(Quad SPI),说白了就是把数据线从1根变成4根。它保留了原来的SCLK和CS,但把MOSI和MISO变成了双向的IO0~IO3。
这样一来,一个时钟周期就能传4位数据。速度直接翻了四倍。我当年做一款摄像头固件存储,用标准SPI读固件要3秒,换成QSPI后不到1秒。用户体验提升很明显。
QSPI有两种工作模式:
- 单线模式:兼容标准SPI,用于发送命令和地址
- 四线模式:数据阶段用4根线并行传输
再往上走,就是Octal SPI。8根数据线,一个时钟周期传8位。这速度已经接近并行接口了。
| 接口类型 | 数据线数量 | 理论峰值速率(@100MHz) | 典型应用 |
|---|---|---|---|
| 标准SPI | 1 | 100 Mbps | 小容量存储、配置芯片 |
| Dual SPI | 2 | 200 Mbps | 较少见 |
| QSPI | 4 | 400 Mbps | NOR Flash、代码执行 |
| Octal SPI | 8 | 800 Mbps | 高性能NOR Flash |
注意:Octal SPI的引脚更多,PCB布局更复杂。而且不是所有MCU都支持。选型时一定要确认硬件外设是否兼容。
嗯,这里要提一句。QSPI和Octal SPI都支持DDR(双倍数据速率)模式。也就是时钟的上升沿和下降沿都采样数据。这样一来,等效速率又翻倍。但DDR模式对时序要求更严格,我建议新手先跑通SDR模式再说。
2.3 ONFI与Toggle接口标准:NAND Flash的专属协议
前面讲的SPI、QSPI,主要用在NOR Flash上。但如果你做的是大容量存储,比如SSD、eMMC、U盘,那就要跟NAND Flash打交道了。这时候,ONFI和Toggle就是绕不开的标准。
ONFI(Open NAND Flash Interface),是英特尔、美光、海力士等公司搞出来的开放标准。它定义了NAND Flash的物理接口、命令集和时序参数。
ONFI接口的特点:
- 异步模式:数据由RE#和WE#信号控制,没有独立时钟
- 同步模式:有DQS时钟信号,速率更高
- NV-DDR模式:双倍数据速率,目前主流
我最早接触ONFI是在做一款工业级SSD时。当时选了一颗美光的NAND,按照ONFI 3.0标准,理论速率能到400MT/s。结果实际测试时,读速度只有标称的六成。查了半天,发现是驱动里时序参数配错了。ONFI标准里有个参数叫tRC(读周期时间),我设得太保守了。
Toggle接口,是三星和东芝推的标准。跟ONFI类似,但细节上有差异。比如Toggle用DQS的双沿采样,而ONFI早期版本用单沿。
两者对比一下:
| 特性 | ONFI | Toggle |
|---|---|---|
| 发起方 | 英特尔、美光等 | 三星、东芝 |
| 同步时钟 | 有(DQS) | 有(DQS) |
| DDR支持 | NV-DDR模式 | Toggle DDR模式 |
| 命令集 | 标准化 | 略有差异 |
| 兼容性 | 多厂商互通 | 偏封闭 |
避坑指南:我曾经在项目中混用过ONFI和Toggle的NAND。结果发现,虽然物理引脚兼容,但初始化序列完全不同。上电后芯片根本不响应。后来老老实实按数据手册重新配了寄存器才搞定。所以——别想当然,一定要看数据手册。
最后说一句。不管用哪种接口,时序约束都是关键。我习惯在驱动里加上时序校准函数,上电后自动测量并调整参数。这样能适应不同批次的芯片,提高产品良率。
好了,接口协议就讲这么多。下一章咱们聊聊Flash的存储单元结构——为什么同样是Flash,NOR和NAND差别这么大?到时候见。