2. SPI Flash 硬件接口:SPI协议时序、四线/双线/单线模式、片选与写保护引脚、硬件设计要点

好,咱们今天聊聊SPI Flash的硬件接口。说实话,这玩意儿看着简单,但坑是真不少。我刚开始做嵌入式那会儿,觉得SPI不就是四根线嘛,接上就能用。结果呢?板子打回来,死活读不到ID,查了三天才发现是时序问题。嗯,从那以后,我对SPI Flash的硬件设计就再也不敢马虎了。

2.1 SPI协议时序:别被那些波形图吓到

SPI协议,说白了就是主从设备之间的一种同步串行通信方式。它需要四根线:SCK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。你想想看,这就像两个人对话,SCK是节拍器,MOSI是你说的话,MISO是对方回的话,CS就是你要跟谁说话。

时序上,最核心的就是时钟极性(CPOL)和时钟相位(CPHA)。CPOL决定时钟空闲时是高电平还是低电平,CPHA决定数据是在时钟的上升沿还是下降沿采样。SPI Flash通常支持Mode 0和Mode 3,也就是CPOL=0, CPHA=0和CPOL=1, CPHA=1。我个人习惯用Mode 0,因为大多数MCU的SPI外设默认就是这个模式。

关键点:SPI Flash的读操作和写操作时序略有不同。读操作时,主机先发指令和地址,然后Flash在MISO上返回数据;写操作时,主机发完指令和地址后,还要继续发数据。注意,写操作完成后,需要等待内部编程完成,通过读状态寄存器来查询。

我在项目中遇到过一个问题:某款Flash在高速时钟下(比如50MHz)读数据时,偶尔会出现数据错位。后来发现是PCB走线太长,导致时钟和数据之间的延迟超过了时序容限。解决办法就是缩短走线,或者在时钟线上加一个小的串联电阻来抑制过冲。

2.2 四线/双线/单线模式:速度与引脚的权衡

SPI Flash的接口模式,说白了就是怎么用那几根数据线。标准SPI是单线模式,也就是MOSI和MISO各用一根线,数据一位一位地传。双线模式呢,把MOSI和MISO都变成双向数据线,一次传两位。四线模式更猛,除了MOSI和MISO,还多了两根IO线(IO2和IO3),一次传四位。

你想想看,同样的时钟频率下,四线模式的速度是单线模式的四倍。但代价呢?需要多两根IO线,而且MCU的SPI外设得支持Quad SPI模式。很多低端MCU只有标准SPI,那就只能用单线模式了。

模式 数据线数量 每时钟传输位数 典型应用
单线(Standard SPI) 2(MOSI, MISO) 1 通用,兼容性好
双线(Dual SPI) 2(IO0, IO1) 2 提升读取速度
四线(Quad SPI) 4(IO0-IO3) 4 高速读取,如代码执行

我的经验:如果只是存配置参数,单线模式完全够用。但如果要在Flash上跑代码(XIP,即片内执行),那必须用四线模式,否则CPU会频繁等待Flash读取,性能大打折扣。我曾经在一个项目里,把单线模式改成四线模式后,系统启动时间从3秒降到了0.8秒。

这里要注意,四线模式通常只在读取数据时启用。写操作和指令发送还是用单线模式。为什么呢?因为写操作本身就很慢(毫秒级),用四线模式也快不了多少,反而增加复杂度。

2.3 片选与写保护引脚:别小看这两个脚

片选(CS)引脚,是SPI通信的开关。CS拉低,表示主机选中了这个Flash,可以开始通信;CS拉高,表示通信结束,Flash进入待机状态。嗯,这里有个坑:CS必须在整个操作过程中保持低电平,不能中途拉高。否则Flash会认为操作被中断,数据可能出错。

写保护(WP)引脚,是用来防止Flash被意外写入的。当WP拉低时,Flash的某些保护区域(比如状态寄存器)就不能被修改了。这个功能在工业环境中特别有用,防止电磁干扰导致Flash内容被篡改。

警告:有些Flash的WP引脚内部有上拉电阻,悬空时默认为高电平(不保护)。但有些Flash没有内部上拉,悬空时电平不确定。我曾经在一个项目中,WP引脚没接,结果在强电磁干扰下,Flash的状态寄存器被意外修改,导致整个系统无法启动。从那以后,我习惯把WP引脚通过10kΩ电阻上拉到VCC,确保它始终处于非保护状态,除非需要保护时才拉低。

另外,HOLD引脚(有些Flash有)也是需要注意的。HOLD拉低时,Flash会暂停当前操作,忽略时钟信号。这个功能在多主机共享SPI总线时有用,但大多数情况下我们用不到。如果不用,记得把它上拉到VCC,否则悬空会导致Flash莫名其妙地暂停。

2.4 硬件设计要点:细节决定成败

硬件设计上,我总结了几个要点,都是血泪教训换来的:

  • 去耦电容不能省:Flash的VCC引脚旁边必须放一个0.1μF的陶瓷电容,尽量靠近引脚。Flash在写入时电流会突然增大,没有去耦电容会导致电压跌落,引起写入失败。
  • 走线长度要匹配:SCK、MOSI、MISO这三根线的长度尽量一致,特别是高速时钟(超过20MHz)时。长度差太大会导致信号延迟不同,时序出错。
  • 避免信号交叉:SPI信号线不要和电源线、大电流信号线平行走线,否则会引入串扰。我见过一个案例,SPI时钟线和PWM信号线挨着走,结果Flash读取数据时总是出现随机错误。
  • 上拉电阻要选对:CS、WP、HOLD这些控制引脚,如果需要上拉,电阻值一般在4.7kΩ到10kΩ之间。太小了会增加功耗,太大了抗干扰能力差。
  • 考虑电平匹配:如果MCU是3.3V,Flash也是3.3V,那直接连就行。但如果MCU是1.8V,Flash是3.3V,就需要电平转换。别想着用电阻分压,那玩意儿在高速下根本不行。

避坑指南:我曾经在一个项目里,为了省成本,把Flash的CS引脚直接连到MCU的GPIO上,没加任何保护。结果有一次上电瞬间,MCU的GPIO输出高阻态,CS引脚电平不确定,Flash误以为被选中,进入了奇怪的状态。后来我在CS引脚上加了一个10kΩ上拉电阻,问题就解决了。

最后,说一个很多人忽略的点:Flash的电源纹波。Flash对电源质量比较敏感,特别是写入操作时。如果电源纹波超过100mV,写入错误率会显著增加。所以,如果系统中有电机、继电器这类大电流设备,最好给Flash单独供电,或者加一个LC滤波器。

嗯,关于SPI Flash的硬件接口,今天就聊这么多。下一章咱们会深入讲Flash的指令集和驱动编写,到时候再结合硬件设计一起分析。记住,硬件设计是基础,基础打不好,软件写得再漂亮也白搭。