Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

2.2 NOR与NAND——存储世界的两条路

你面前有两条路,你必须选一条

想象你是一个存储架构师,坐在会议室的白板前。白板上写着你的设计约束:512KB的NOR Flash,128个4KB块,Cortex-R5 MCU,FreeRTOS,AUTOSAR。你要在这上面跑一个文件系统。

你先不考虑文件系统——你先看看你手里的这块NOR Flash和隔壁部门用的那块NAND Flash有什么区别。

你同事小李做存储卡的,他用的是64GB的TLC NAND。你问他:读写速度多少?他说:顺序读500MB/s,顺序写200MB/s。你又问:你查过坏块表没有?他说:出厂就有2%的坏块,跑着跑着还会新增,反正靠ECC纠错。

你沉默了。你的Flash上,一个坏块就意味着512KB里面少了4KB——0.8%的容量没了,而且你的文件系统在设计时根本没考虑坏块管理这件事。

这就是NOR和NAND的分岔路口。一个走可靠性路线,一个走成本路线。

1970年代末,Intel发明了EPROM。1984年东芝的舛冈富士雄在EPROM基础上发明了Flash——同时提出了NOR和NAND两种可能的连接方式。起初NOR Flash占据了嵌入式市场,因为它跟CPU的接口像SRAM一样简单。1990年代末,三星和东芝大幅推动了NAND Flash的商业化,因为它更适合SSD和存储卡这种大容量场景。

从那时起,两条路越走越远,越走越深。它们的差异,比高速公路和铁路的差异还大。


NOR Flash:每个单元都有自己的门牌号

NOR Flash的架构名称来自布尔逻辑中的“NOR“门。但别被名字吓到——理解它的架构只需要一个直觉:每个浮栅晶体管都直接挂在位线上。

NOR Flash单元阵列——每个单元独立可寻址
============================================

                         Bit Line 0     Bit Line 1     Bit Line 2
                            │              │              │
  Word Line 0 ──────────────┼──────┬───────┼──────┬───────┼──────
                            │    ┌─┴─┐     │    ┌─┴─┐     │
                            └────┤FG ├─────┴────┤FG ├─────┘
                                 │   │          │   │
                             ┌───┤   ├────┬─────┤   ├───┐
  Word Line 1 ──────────────┼───┤   │    │     │   │   │
                             │   └─┬─┘    │     └─┬─┘   │
                             │   ┌─┴─┐    │     ┌─┴─┐   │
                             └───┤FG ├────┴─────┤FG ├───┘
                                 │   │          │   │
                             ┌───┤   ├────┬─────┤   ├───┐
  Word Line 2 ──────────────┼───┤   │    │     │   │   │
                             │   └───┘    │     └───┘   │
                             │     │      │       │     │
                             Source Lines (按扇区块共用)
  
  选中一个单元:WL0 + BL1 → 交点处那个FG直接导通/截止 → 读出放大
  这就是随机访问。不需要读邻居,不需要翻页,直接定位。

关键特征:

  • 每个单元的漏极独立接到一条位线上。 你想读哪个单元,字线选中那一行,位线选中那一列,交点那个单元就直接输出信号——不要经过任何其他单元。

  • 每个字节都有一个地址。 NOR Flash和CPU之间的接口是地址总线和数据总线。CPU把地址放到总线上,几十纳秒后数据就回来了。这和SRAM的接口是一模一样的。

  • 以字节为最小访问单位。 你不需要“翻一页“。你要读第456个字节?地址总线输出0x1C8,70ns后数据回来。就这么简单。

这就是为什么NOR Flash可以做XIP(eXecute In Place)——CPU直接从Flash取指执行,不需要先把代码复制到RAM。在嵌入式系统里,这意味着你可以省掉宝贵的SRAM(Cortex-R5通常只有几百KB到几MB的SRAM)。

NOR Flash与CPU的连接(简化)
=============================

  CPU                              NOR Flash
 ┌──────────┐                    ┌───────────┐
 │          │─── Address[18:0]──→│地址解码器   │→ 选字线/位线
 │          │                    │           │
 │          │←── Data[15:0] ────│读出放大器   │← 选中单元输出
 │          │                    │           │
 │          │─── /CE (片选) ────→│           │
 │          │─── /OE (输出使能) ─→│           │
 │          │─── /WE (写使能) ──→│           │
 └──────────┘                    └───────────┘
 
  接口像SRAM,不像磁盘。
  CPU发地址 → Flash返回数据。不需要"读页"命令。

这不是磁盘的访问模式。这是内存的访问模式。NOR Flash的随机读取延迟是70纳秒级别——和SRAM一个数量级。CPU把地址放到总线上,几十纳秒后指令就回来了,直接送入流水线执行。

这就是为什么NOR Flash可以做 XIP(eXecute In Place,原地执行)——CPU直接从Flash取指执行,不需要先把代码复制到SRAM。在嵌入式系统里,这意味着你可以省掉宝贵的SRAM(Cortex-R5通常只有几百KB到几MB),固件镜像可以直接跑在Flash上。你的汽车ECU、WiFi路由器、智能手表——它们的代码都这样跑着。

也正因为每个字节独立可寻址,早期单片机程序员可以直接在Flash上修改一个字节然后跳过去执行——这在NAND上是完全不可想象的。


NAND Flash:一串糖葫芦上的山楂

NAND Flash的架构完全不同。它不叫“NAND“是因为逻辑门,而是因为它的连接方式让你想到串联——每一列的单元是串联在一起的,像一串糖葫芦。

NAND Flash单元阵列——一串串的串联结构
=========================================

                   Bit Line 0        Bit Line 1        Bit Line 2
                       │                 │                 │
     String Select ────┼──────┬──────────┼──────┬──────────┼──────
     (SST)              │    ┌─┴─┐        │    ┌─┴─┐        │
                        └────┤FG ├────────┴────┤FG ├────────┘
                             │   │             │   │
     Word Line 0 ────────────┤FG ├─────────────┤FG ├────────────
                             │   │             │   │
     Word Line 1 ────────────┤FG ├─────────────┤FG ├────────────
                             │   │             │   │
     Word Line 2 ────────────┤FG ├─────────────┤FG ├────────────
                             │   │             │   │
     ...                   (一连串32-128个单元串联)
                             │   │             │   │
     Word Line 31 ───────────┤FG ├─────────────┤FG ├────────────
                             │   │             │   │
     Ground Select ─────┼───┤   ├────┼────────┤   ├───┼────
     (GST)              │   └───┘    │        └───┘   │
                        │     │      │          │     │
                        └─────┘      └──────────┘     └─────
                                Source Line (共地)
  
  一"串"里有32-128个单元。要读其中一个,必须让其他所有单元强制导通,
  然后读出放大器感应这个选中的单元是导通还是截止。

NAND Flash的存储单元不是一个个独立的。一列32到128个浮栅晶体管被串联成一个“串(String)“——这大大节省了位线接触孔的数量,让每个单元的面积从NOR的~10F²缩小到~4F²(F是特征尺寸)。这就是NAND比NOR便宜的物理根源。

但便宜有便宜的代价。

要读一串中某一个单元的数值,你必须把其他所有单元强制导通——在它们的控制栅上加一个足够高的电压(叫Vpass,通常是6-8V),让不管它们浮栅里有没有电子,沟道都全部导通。然后,只对被选中的那个单元的控制栅加Vread,看它导通还是不导通。

NAND读取操作
==============

  选中单元:该单元CG加Vread (~3V)
  其他单元:CG加Vpass  (~7V) → 不管它们浮栅状态如何,全部强制导通
  读出放大器:敏感总电流 → 判断选中单元是导通(1)还是截止(0)
  
  不是"读一个",是"读一整串"然后只关心其中一个。

所以你不可能在NAND上做随机字节访问。 你必须读一整页(通常是4KB到32KB),然后把你需要的那一个字节从这个页里挑出来。NAND的寻址不是以字节为单位的——是以页(Page) 为单位的。

这就是为什么NAND不能XIP。你要在NAND上执行代码?先把整页数据都读到一块SRAM buffer里,然后CPU从buffer拿指令。这就不是“直接执行“了,这是“先加载后执行“。


NOR vs NAND:一张决定命运的对比表

特性NOR FlashNAND Flash
读取延迟~70ns(字节随机访问)~25µs(页读取,第一字节延迟)
读取粒度1字节1页(4KB-32KB)
最大读取带宽~100-200MB/s(突发模式)~500MB/s-4GB/s(顺序读)
写入粒度1字节(需先擦除整扇区)1页(需先擦除整块)
编程时间(单个单位)~10µs/字节~200-500µs/页
擦除粒度扇区(4KB-64KB)块(128KB-16MB)
擦除时间~100ms/扇区~2ms/块
擦除速度(折算)~0.04MB/s~64MB/s
擦写寿命~10万次(SLC)SLC:10万次, MLC:3000-1万, TLC:500-3000
坏块率(出厂)接近0%2%-5%(出厂时就可能有)
坏块管理不需要(嵌入式场景)必须(FTL/ECC/Bad Block Table)
最大容量≤2GB≤1TB+(单片),堆叠可达16TB+
每位成本高(~10F²/bit)低(~4F²/bit,3D可达更小)
耐温范围-40°C ~ +125°C0°C ~ +70°C(消费级)
抗辐射
ECC要求低(1-bit ECC即可,甚至不需要)必须(4-120 bit ECC/每页)
XIP支持✓ 支持✗ 不支持(必须加载到RAM)
典型应用汽车ECU、MCU固件、BIOS/UEFISSD、U盘、手机存储、SD卡

这张表里藏着一个残酷的经济学真相:NOR Flash的单位面积成本是NAND的2.5倍——不是你买这颗芯片贵,而是“做同样的容量,NOR需要2.5倍的硅面积“。

因为NAND的串联结构省掉了大量的接触孔和隔离区。一个NAND单元在硅片上占的面积是~4F²(F是特征尺寸)。而一个NOR单元需要~10F²——因为每个单元的漏极都需要独立的接触孔,每个位线都需要隔离。

面积对比(简化示意图)

  NOR单元:大约10F²                    NAND单元:大约4F²
  ┌──────────────────┐                 ┌──────────────┐
  │ ┌────┐   ┌────┐  │                 │ ┌──┐ ┌──┐ ┌──┐│
  │ │ FG │   │ FG │  │ ← 独立接触孔    │ │FG│ │FG│ │FG││
  │ │    │   │    │  │    隔离区        │ └──┘ └──┘ └──┘│
  │ └────┘   └────┘  │                 │  ← 串联,省接触孔 │
  │  ↑接触   ↑接触    │                 └──────────────┘
  │  ↓孔     ↓孔      │                     面积 = ~4F²
  └──────────────────┘
       面积 = ~10F²

F²在这里不是开玩笑的数量级。对于一个16nm工艺(F=16nm),10F²=2560 nm²,4F²=1024 nm²。1平方毫米可以塞入约39万个NOR单元,或者约97万个NAND单元。

这意味着同样一片300mm晶圆,NAND的容量是NOR的2.5倍。而这个倍数,在3D NAND的世界里变成了几十倍甚至几百倍——因为你可以往上堆叠。


NOR的垂直困境 vs NAND的3D腾飞

在很长一段时间里,NOR和NAND都在2D平面工艺上前进——把尺寸做小、把单元塞得更密。但到了16nm左右,NOR Flash遇到了一个物理瓶颈:

浮栅晶体管必须保持那个8nm的隧道氧化层。 这个厚度不能再薄了——更薄意味着更大的泄漏、更短的保持时间、更差的可靠性。而且NOR需要独立接触孔和隔离区,这些结构的尺寸不能无限缩小——缩小了接触电阻变大、隔离失效。

所以NOR Flash在16nm节点后就基本停止了微缩。目前主流嵌入式NOR Flash是45nm-55nm工艺——而且这个工艺对NOR来说已经是“成熟“到不能再成熟了。

NAND这边呢?

NAND不需要每个单元独立可寻址——所以它可以在Z轴方向堆叠。这就是3D NAND:在同一个硅片上垂直堆叠多层存储单元。

3D NAND结构(概念示意)
==========================

          Z轴 ↑  堆叠层数:2013年24层 → 2025年232层+
          │
     ┌────┴────┐ ← 第N层  (最高层)
     │  FG FG  │
     │  FG FG  │ ← 第N-1层
     │  FG FG  │
     │  FG FG  │ ← 第N-2层
     │  FG FG  │
     │  ...    │ ← ... 232层堆叠
     │  FG FG  │
     │  FG FG  │ ← 第2层
     │  FG FG  │
     └────┬────┘ ← 第1层 (靠近衬底)
          │
     外围控制电路 (在衬底上,或放在存储阵列下方——CMOS Under Array)

每一层都是一整面的存储单元阵列。这些层像千层饼一样堆叠在一起,通过垂直通道(Vertical Channel)——一个从顶部贯穿到底部的多晶硅柱——把所有层串起来。一个Vertical Channel穿过232层后,这个“串“就有232个单元串联在一起。

这带来了几个惊人的结果:

  1. 容量密度的爆炸:232层 × 每层面积不变 = 容量是2D时代的232倍。一块300mm晶圆可以产出1TB以上的NAND Flash。

  2. 工艺倒退式的进步:3D NAND不需要最先进的EUV光刻。因为每一层的特征尺寸可以放得比较大(20-30nm,甚至更大),靠层数来弥补密度。这反而降低了光刻成本。

  3. NOR彻底跟不上:因为NOR需要每个单元独立可寻址的位线——如果也做232层,垂直方向上的位线怎么走?在3D结构里,每一层都需要独立的位线接触吗?物理上几乎不可能。所以NOR Flash至今几乎没有3D版本。


为什么汽车电子选择了NOR

你现在知道为什么你的汽车ECU里使用的是NOR Flash而不是NAND了。

第一,可靠性。 汽车的Flash存储了发动机控制、刹车系统、安全气囊的控制代码。如果存储的数据出错——哪怕只是一个比特——后果可能是灾难性的。NOR Flash出厂几乎零坏块,10万次擦写寿命,不需要复杂的ECC纠错。NAND出厂就有2%-5%坏块,需要强大的ECC(BCH/LDPC)来纠错,擦写寿命在MLC和TLC上只有几千次。

第二,XIP(原地执行)。 汽车ECU的SRAM非常宝贵。Cortex-R5可能只有256KB到1MB的SRAM,而固件镜像可能有2MB到16MB。如果使用NAND,CPU不能直接从NAND取指——你必须先把代码加载到SRAM再执行。这意味着你至少需要和固件一样大的SRAM。而用NOR Flash,CPU直接从Flash取指,SRAM只用来跑栈和堆,省掉一大块成本。

第三,抗辐射和宽温。 汽车引擎舱的工作温度范围从-40°C到+125°C,还伴随着电磁干扰和高能粒子辐射。NOR Flash在这种环境下的数据保持能力远好于NAND——因为它的单元结构更简单、电荷量更大(SLC vs MLC/TLC)。NAND在极端温度和辐射下,电荷泄漏速度会急剧加快。

第四,确定性。 NOR Flash的擦除是扇区级的——你知道擦一个4KB扇区需要大约100ms。NAND的擦除是块级的——你擦一个4MB的块可能需要3ms,但加上坏块管理、磨损均衡、垃圾回收、写放大,实际的延迟抖动很大。对于汽车这种实时系统来说,确定性比平均性能更重要。

汽车ECU使用NOR Flash的典型场景
==================================

  ECU上电 → CPU从NOR Flash取Reset Vector → 开始执行固件
  (不需要从Flash复制到RAM,直接取指执行)

  固件存储区(NOR Flash)
  ┌─────────────────────────┐
  │ Bootloader   (64KB)     │ ← 一级引导
  ├─────────────────────────┤
  │ Application  (2MB)      │ ← 主应用程序 (XIP)
  ├─────────────────────────┤
  │ Calibration  (256KB)    │ ← 校准参数 (读写)
  ├─────────────────────────┤
  │ Log/Data     (512KB)    │ ← 运行时数据记录
  └─────────────────────────┘
  
  全部在NOR Flash上。无须外部RAM加载。

为什么手机和U盘选择了NAND

反过来看,你的手机、你的U盘、你的SSD——它们选NAND的理由同样充分。

第一,便宜。 1GB NOR Flash的成本可能是1GB NAND的2-3倍。一个128GB的手机用NOR?成本翻3倍,手机卖不出去。

第二,密度。 3D NAND可以堆叠200+层,在同样的芯片面积里做出几百倍的容量。NOR做不到。

第三,写入吞吐量。 NAND按页写入(16KB一页),一页只需200微秒——虽慢,但一页数据量大。总体写入带宽远高于NOR的逐字节编程。

第四,应用场景不需要随机字节访问。 手机里的照片、U盘里的文件——从来不需要“随机读第35467字节“。它们总是按块读写。NAND的页访问模型完美匹配这类场景:该读多少读多少,不够再加一页。

第五,软件层掩盖了硬件缺陷。 NAND的坏块、磨损、电荷泄漏——这些“缺陷“都被FTL(Flash Translation Layer) 掩盖了。FTL是一层软件/固件,它维护逻辑页到物理页的映射表、跟踪坏块、做磨损均衡、做垃圾回收。上层的应用和文件系统看到的是一块“完美“的块设备——而不知道下面是一块“千疮百孔“的NAND。

NAND 软硬件堆栈
=================

  应用层:    照片、视频、文件
  文件系统层:  FAT32/exFAT/ext4/f2fs
  FTL层:      逻辑块↔物理块映射  ← 掩盖坏块、磨损均衡、GC
  闪存控制器层: ECC纠错、坏块管理、命令调度
  物理层:      TLC NAND Die × N通道 × M芯片

FTL是NAND的“遮羞布“。也是它的“翻译官“。没有FTL,NAND就是一块到处坏块的破布。有了FTL,它就是一块完美的块设备。而FTL本身的实现复杂度,比本文讨论的整个KnotFS文件系统还要大好几倍。


这本书只讲NOR

你面前的这本书,最终只讲了一条路:NOR Flash上的嵌入式文件系统。

不是因为我们觉得NAND不重要。而是因为我们关心的场景——汽车MCU、实时嵌入式系统、资源极度有限的Cortex-R5——和NAND毫无交集。

一个NAND系统的FTL需要几十KB甚至几百KB的SRAM来维护映射表。但我们的MCU总共只有512KB SRAM,FTL的开销就占了10%甚至更多。

一个NAND系统的ECC引擎需要硬件支持(BCH编码器和解码器)。但我们的MCU没有硬件ECC,纯软件CRC32校验已经是我们在计算资源上的极限了。

一个NAND系统的擦除块是128KB到16MB。而我们的Flash总共才512KB——一个擦除块就占25%到3000%。没有磨损均衡的空间,没有垃圾回收的余地。

所以NOR是唯一的路。也正因为是唯一的路,才有我们后面要讲的KnotFS——一个专门为 NOR Flash 设计的嵌入式文件系统,从 64KB 的教学规模开始,理解它如何在真实的车载环境中扩展到完整的 Flash 管理。

你手里那个16MB的NOR Flash,按照它的工艺节点、容量和成本,在消费电子世界里已经算是“博物馆文物“了。但在嵌入式实时系统里,它是标配。你的汽车、你的路由器、你的智能电表、你的无人机飞控——都靠它存储代码和数据。

这是一条大多数人不会走的路。但走这条路的人,造你家汽车的刹车、你头顶上那架飞机的飞控、你手腕上那块手表的固件更新系统。

这是一条窄路。但它的每一条指令、每一个比特,都在保护你的安全。


下集预告

NOR 选定,赛道确定。但你手里的这颗 NOR Flash 到底能存多少个比特?同样是浮栅晶体管,为什么有的芯片标着“SLC“能擦写十万次,有的芯片标着“TLC“几千次就废了?

决定 Flash 寿命和可靠性的,不是 NOR 还是 NAND——而是每个存储单元里塞了几个比特。

下一节,我们走进 SLC/MLC/TLC/QLC 的世界,看看“越多越不靠谱“的物理根源。

悬念留给:一个晶体管存 4 个比特是什么概念?你需要把 3.3V 的电压窗口切成 16 份——每份只有 0.2V。温度高一点,电子漏几个,0 就变成了 1。