第四章:Flash存储器工作原理

说到 QSPI Flash 的引导加载,你得先搞明白 Flash 本身是怎么工作的。很多人一上来就调时序、配寄存器,结果连 Flash 为什么要先擦除再写都没弄懂——这坑我当年也踩过。

Flash 存储器,说白了是一种非易失性存储器。断电不丢数据,这是它最核心的价值。但它的读写规则和 RAM 完全不同,你得顺着它的脾气来。

4.1 NOR Flash vs NAND Flash

嵌入式系统里用的 QSPI Flash,绝大多数是 NOR 结构。为什么不用 NAND?我直接给你列个对比,看完就明白。

特性 NOR Flash NAND Flash
读取速度 快(随机读,字节级) 较慢(页读,需先加载到缓存)
写入速度 慢(字节/字编程) 快(页编程,批量写入)
擦除速度 较慢(扇区/块擦除) 快(块擦除)
可靠性 高(坏块少) 低(需要坏块管理)
接口方式 SRAM-like,有独立地址/数据线 命令/地址/数据复用
典型容量 1Mb ~ 512Mb 1Gb ~ 1Tb+
QSPI 适用性 ✅ 非常适合(XIP 执行) ❌ 不适合(不支持随机 XIP)
关键认知:NOR Flash 支持随机读取,代码可以直接在上面跑(XIP 模式)。NAND 需要先把代码拷贝到 RAM 再执行——这就是为什么 QSPI Flash 几乎清一色都是 NOR 结构。

4.2 存储单元的核心:浮栅晶体管

Flash 的存储单元是一个特殊的三极管——浮栅晶体管。你可以把它想象成一个带「暗格」的开关。

常规 MOSFET 只有控制栅(Control Gate)。浮栅晶体管在控制栅下面多了一层浮栅(Floating Gate),这层浮栅被氧化物绝缘层包裹着。电子一旦进入浮栅,无路可逃,于是阈值电压就变了。

我当年在学校第一次听这个,觉得玄乎。后来在项目里调一块 Flash 死活写不进去,查了一圈,发现是浮栅编程电压没给够——嗯,纸上得来终觉浅。

浮栅中是否有电子,决定了存储单元代表 1 还是 0:

  • 无电子(低阈值)→ 读出来是 1(默认状态,擦除后的状态)
  • 有电子(高阈值)→ 读出来是 0(编程后的状态)
一个小习惯:我个人记 NOR Flash 的空状态是 1,因为擦除后全片是 0xFF。你想想,如果空状态是 0,那代码读出来全零,PC 直接跑飞。所以设计上,擦除态 = 1,编程把 1 写成 0。

4.3 三种基本操作:读、写、擦

Flash 的核心操作就三个:读(Read)、写(Program)、擦除(Erase)。但它们的电气条件和耗时天差地别。

4.3.1 读取操作

读取最简单。给控制栅加一个读电压(通常 4.5V ~ 5V),检测沟道是否导通。

  • 浮栅无电子 → 阈值电压低 → 晶体管导通 → 读出 1
  • 浮栅有电子 → 阈值电压高 → 晶体管截止 → 读出 0

读操作不改变浮栅状态,所以没有损耗。读一万次和读一次,寿命一样。

4.3.2 编程(写)操作

编程用的是「沟道热电子注入」效应。给控制栅加高压(约 10V ~ 12V),漏极加中压(约 5V ~ 6V)。电子在沟道中获得足够能量,越过氧化层势垒,注入浮栅。

这个过程需要时间。一个字节的编程,典型耗时 10μs ~ 50μs。你没看错,写一个字节要比读慢几百倍。

避坑指南:我曾经在一个批量产测项目里,按字节轮询写 4MB 数据,结果单片编程就花了将近 7 秒。后来改成页编程(Page Program,一次写 256 字节),时间缩到 30ms。记住了——别逐字节写,用页连续写。

4.3.3 擦除操作

擦除正好反过来。用「Fowler-Nordheim 隧穿效应」,在衬底和源极加高压,把浮栅中的电子「吸」出来。

擦除以扇区(Sector)或块(Block)为单位。一个扇区通常 4KB 或 64KB,擦除耗时 100ms ~ 1s 不等。嗯,你没听错,擦一个扇区可能要几百毫秒。

我简单列一下三种操作的对比:

操作 单位 典型耗时 电压要求 对寿命的影响
读(Read) 字节 / 页 50ns ~ 100ns(页读) 低 (4.5V ~ 5V) 无损耗
编程(Program) 字节 / 页 10μs ~ 5ms(页编程) 高 (10V ~ 12V) 每次编程轻微磨损
擦除(Erase) 扇区 / 块 100ms ~ 1s 高 (12V ~ 20V) 磨损最大
核心结论:擦除 > 编程 > 读取,这是 Flash 操作的速度铁律。QSPI 引导加载时,我们只做读取,所以才能跑到几十 MHz。如果启动过程中要擦写 Flash,那 Boot 时间就彻底崩了。

4.4 Flash 的写入限制:为什么不能覆盖写?

这是新手最容易掉进去的坑。Flash 编程只能把 1 改成 0,不能把 0 改成 1。要把 0 还原成 1,唯一的办法是擦除——整片整扇区地擦。

为什么会这样?因为编程只能注入电子(设 0),不能抽出电子。抽出电子需要高电压隧穿,那就是擦除操作了。

所以 Flash 的写入模式是:

  1. 先擦除:把目标扇区全部变成 0xFF(全是 1)
  2. 再编程:把需要改 0 的位逐个写进去
经验之谈:我建议你在设计引导加载方案时,预留一个「擦除进度条」的接口。因为擦除一个 64KB 的扇区可能要 500ms,如果 Bootloader 在这期间没有任何反馈,客户会以为板子死机了。实际上——它只是在老老实实地擦 Flash。

4.5 Flash 的寿命:擦除次数有限

每次擦除都会对氧化层造成不可逆的损伤。NOR Flash 的擦写寿命通常是 10 万次(数据手册标称值),但实际工程中,为了留余量,我习惯按 5 万次来设计。

这意味着什么?

  • 如果你的 Boot 代码天天原地擦写,不出一年就到寿限了
  • QSPI Flash 引导加载通常只读不写,所以寿命不成问题
  • 但如果你用 Flash 存日志——建议搭配磨损均衡(Wear Leveling)

4.6 本章知识体系图

下面这张图梳理了 Flash 存储器的核心工作原理,从浮栅晶体管到操作流程,你看一遍就能把知识串起来。

Flash 存储器工作原理 浮栅晶体管 控制栅 + 浮栅 + 源/漏 浮栅存电子 ↔ 阈值变化 存储状态 无电子 → 1(擦除态) 有电子 → 0(编程态) 读 (Read) 低电压 · 无损 · 最快 写 (Program) 高电压 · 1→0 · 中等 擦 (Erase) 高电压隧穿 · 0→1 · 最慢 NOR vs NAND NOR:随机读 · XIP · 小容量 NAND:页读 · 大容量 · 坏块 QSPI 引导加载 → 选 NOR ⚠️ 写流程铁律:先擦除 → 再编程 擦除以扇区为单位,编程以字节/页为单位 NOR Flash 擦写寿命 ≈ 10 万次 引导加载场景 → 只读不写,寿命无忧

4.7 这些原理怎么落到 QSPI 引导加载上?

知道了 Flash 的工作方式,我们来对齐到 QSPI 引导加载这个场景:

  • BootROM 通过 QSPI 接口发读命令(Read Command),Flash 返回数据
  • 读操作不需要高压,功耗低,速度快——适合启动场景
  • QSPI Flash 内部有页缓冲区(Page Buffer),连续读时可以按页突发
  • XIP 模式下,读操作直接映射到 CPU 地址空间,像读 RAM 一样读 Flash
一句话总结:Flash 的原理决定了 QSPI 引导加载只能做读操作。任何写或擦的动作都必须放到 Bootloader 阶段由软件显式触发,不能由硬件自动完成。设计启动方案时,记住这个边界,能帮你省掉很多调试时间。

Flash 的工作原理,是理解 QSPI 引导加载的地基。地基建稳了,后面调协议、配时序、做优化,你才知道每一步在干什么。搞嵌入式就是这样——底层逻辑通了,上层怎么搭都不怕倒。