ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

搞懂NAND Flash基础:从存储单元到页/块结构解析

搞懂NAND Flash基础:从存储单元到页/块结构解析 写在前面为什么说搞懂 NAND Flash 是存储行业的“基本功”NAND Flash 这颗芯片看起来只是手机、U盘、SSD 里的一个黑盒子但它几乎决定了现代存储行业的底层逻辑。不管是做嵌入式开发、固件调试、硬件设计还是数据恢复、元器件贸易只要跟存储沾边早晚要面对它。我最早接触 NAND Flash 是在做一款工控板卡的时候板载 eMMC 频繁出现坏块当时被“页、块、plane、die”这些概念绕得头大后来花了两周时间把《Inside NAND Flash Memories》第2章啃完才终于把整条链路串起来。这次要拆解的就是这本书第2章的 2.1 到 2.2.1 部分。别看只是开篇章节它讲的是 NAND Flash 的器件原理、阵列结构、页和块的组织方式以及 NAND 与 NOR 在架构层面的根本差异。这些内容不是简单的概念堆砌而是后续理解 ECC、坏块管理、FTLFlash Translation Layer闪存转换层、磨损均衡的基础。一句话概括这章的核心NAND 为什么被设计成“按页读写、按块擦除”的结构以及这种结构在物理层面是怎么实现的。这篇文章适合三类人一是刚入行的嵌入式软件工程师和存储固件工程师需要系统梳理 NAND 基础二是硬件工程师想搞懂芯片手册里那些时序图、引脚定义背后的物理意义三是数据恢复或维修从业者想在操作编程器之外理解“为什么会坏”。我会把书里的原理、我自己实验中的验证过程、以及实际工程里踩过的坑一起讲尽量做到既讲原理又能直接用在工作中。1. 内容整体设计与思路拆解NAND 为什么是今天这个模样1.1 看芯片先看“需求”非易失、高密度、低成本是最终目标要理解 NAND Flash 的设计得先退一步看看整个存储金字塔的需求。计算机系统里需要各种各样的存储器SRAM 最快但太贵DRAM 容量大但要持续刷新掉电即失硬盘便宜但机械结构速度慢。中间存在一个需求空白需要一种掉电不丢数据的、容量足够大的、成本尽可能低的半导体存储器。NAND Flash 就是冲着这个需求来的。它跟内核态、驱动层的软件设计不同NAND 的每一个“怪脾气”——比如不能按字节写、写之前必须擦除、颗粒会坏块——从芯片设计的第一天起就是主动选择的结果。既然目标是高密度、低成本那么在制造工艺上就尽可能简化存储单元的尺寸用最少的晶体管存最多的比特。这样做的代价就是牺牲随机访问能力、牺牲寿命上限、牺牲存储单元可靠性。这是一笔极其划算的“交易”因为实际使用中绝大多数存储需求都是顺序读写大块数据而不是像内存那样随机访问每个字节。1.2 跟 NOR 的路线之争为什么 NAND 最后统治了大容量市场提到 NAND 就绕不开它的“老对手” NOR Flash。在学习这章的时候如果把 NAND 和 NOR 对比着看很多设计逻辑会变得非常清晰。NOR Flash 的设计理念是“更像内存”。它的存储单元并联在位线上可以按字节随机读取读取速度快。NOR 这样做的代价是单元面积大同样的晶圆面积做不出大容量单位容量的成本很高。所以 NOR 最终只能守在固件存储、代码执行这类容量要求低但随机读取性能要求高的场景。NAND Flash 的设计理念则是“更像磁盘”。它把存储单元串联成串也就是“NAND 串”像一个链条一样连接这样每个单元占用的面积非常小可以做到很高的容量和很低的单位成本。代价是按字节随机读做不到必须按“页”为单位读取和写入擦除则必须按“块”为单位。所以在 2.1 和 2.2.1 这部分作者其实是在回答一个问题你怎么把尽可能多的“比特”塞进一颗芯片里同时还要保证能写、能读、能擦除。答案就是“以字符串联的方式组织存储单元”而这个选择像多米诺骨牌一样决定了后面所有的行为特征。1.3 从应用场景倒推手机、SSD、U盘的需求推动架构定型NAND 不是工程师凭空画出来的而是被应用场景推着走的。最早的闪存市场需求是“替代软盘”后来是“手机存储”再后来是“企业级 SSD”。场景不断升级对容量的要求越来越高对成本的要求越来越苛刻于是 NAND 架构不断往“单元更小、串更长、层数更多”的方向演进。从 SLC 到 MLC、TLC、QLC一个存储单元能保存的比特数越来越多但可靠性越来越差。这正好解释了为什么我们现在做 NAND 相关系统设计时必须把 ECC纠错能力和坏块管理能力摆到核心位置。用书里的逻辑看NAND 的制造目标就是“在保持可用性的前提下尽量降低每比特成本”这跟很多初学者以为的“NAND 就应该完美无缺”完全不同。2. 核心细节解析与实操要点存储单元、阵列和层级结构2.1 存储单元的核心物理浮栅晶体管到底在做什么2.1 前半部分最重要的概念就是“存储单元”。一个 NAND 存储单元本质上是一个特殊的 MOSFET跟普通场效应管不同的是它多了一层被绝缘层包裹的“浮栅”Floating Gate或者说在现代 3D NAND 里是一个电荷捕获层CTFCharge Trap Flash。我试着用一个生活化的类比来解释。普通 MOSFET 的栅极就像一扇可以开关的门通过控制电压决定源极和漏极之间是否导通。而浮栅晶体管的浮栅就像门里藏了一个“保险箱”电子可以穿过绝缘层被关进保险箱里保险箱里的电荷量会改变晶体管的阈值电压Vt即让晶体管导通所需的最低栅极电压。“保险箱里有电子”和“保险箱里没有电子”就对应了 1 和 0 两种状态。写入Program操作的物理机制是“FN隧穿”Fowler-Nordheim Tunneling或热电子注入。简而言之在控制栅和衬底之间加一个高电压让电子获得足够能量隧穿通过绝缘层进入浮栅。擦除Erase则反过来把电压反接让电子从浮栅中隧穿回衬底。读取Read是给控制栅加一个参考电压检测晶体管的导通电流大小从而判断浮栅里有没有电荷、电荷量大概是多少。如果只看书里 2.1 的公式和能带图可能觉得离工程很远但如果做过量产测试或者器件调试就知道弄懂这个基本原理对理解“为什么擦除需要高压”“为什么写多了会磨损”至关重要。磨损的根源说白了就是每次隧穿都会对绝缘层造成不可逆的损伤电荷可能被“困”在绝缘层里导致阈值电压偏移最终无法正确区分 0 和 1。所以“寿命有限”不是 NAND 的缺陷而是它的物理宿命。2.2 阵列结构字符串联是怎么把面积压下来的2.2 的重点是 NAND 阵列的结构。理解了它你就理解了为什么 NAND 叫“NAND”——它的逻辑结构其实就是“与非门”NAND的电气实现一列存储单元串联在一条位线Bit Line和公共源极Common Source之间所有单元必须同时导通这一列才能读出某个单元的状态就像与非门“全1才为0”的逻辑在电流层面上的体现。这种串联结构是 NAND 容量优势的根源。一组存储单元共享源极和漏极不需要每个单元都有独立的接触孔Contact省下了大量芯片面积。打个比方NOR 就像一个每个人住独栋别墅的小区每栋都要单独接水电NAND 就像一个公寓楼一条管线串到底每户只有一个简单接口。公寓楼挤但省地皮能装更多人这就是 NAND 用面积换密度的典型设计。但串联也带来麻烦不能随机访问任意一个单元。要读某一页的某个单元必须先把同一串里的其他单元都“打开”给它们的控制栅加一个通过电压让它们无论有没有电荷都处于导通状态只给要读取的单元加一个参考电压这样整串的导通与否就取决于目标单元的阈值电压了。这个过程决定了 NAND 的最小访问粒度是“一页”因为一次必须同时操作同一字线上的所有单元。2.3 页、块、plane、die芯片里的“行政层级”书里的 2.2.1 会明确区分“页”Page和“块”Block这两个概念这是 NAND 的世界观基础我做一个表把它们的关系整理清楚层级大小常见消费级 TLC作用工程影响Page页16KB ~ 32KB含备用区最小读写单位读和写必须按页操作没有按字节写的自由Block块几百页通常 4MB ~ 64MB最小擦除单位擦除必须整块擦块内部分页无效也不能单独擦Plane平面多个块组成的区域并行操作单位同一时间可对多个 plane 下发命令以提高吞吐Die裸片包含完整阵列和周边电路芯片级操作单位多 die 之间可用片选信号 CE 区分实现交错我最早看 datasheet 时总搞不清这些层级有什么实际意义后来做性能优化才明白其中要害。比如写操作的最小单位是页所以如果你只改了文件系统里几十字节的数据固态盘主控也不得不把整页读出来、修改、再整页写到一个新位置。这既解释了写放大Write Amplification的由来也解释了为什么 NAND 不能像硬盘那样原地覆盖写。另一个容易忽略的点是备用区Spare Area也叫冗余区。每页除了用户数据区之外还有一小块额外的空间专门放 ECC 校验值、坏块标记、逻辑地址映射信息。对这个备用区的理解在后续学习坏块管理和 FT L时很关键。3. 实操过程与核心环节实现NAND 和 NOR 的对比、三种基本操作与实验验证3.1 NAND 与 NOR 的“性格”差异一张表看清全貌这章最强的一个知识锚点就是“NAND vs NOR”对比。我把自己在实际调试中会用到的对比维度整理成表格比书里的表格更适合结合项目来看对比维度NOR FlashNAND Flash存储单元连接方式并联每个单元独立连接位线串联存储单元组成 NAND 串读方式随机字节读类似 ROM按页读需要命令序列写方式可字节/字编程通常按字节只能按页编程擦除方式按扇区/块擦除块较小按块擦除块较大典型容量1Mb ~ 512Mb1Gb 少见1Gb ~ 1Tb 以上一颗 die 就能做到很大单位成本高低可靠性寿命较好读干扰较小寿命相对有限需 ECC 和坏块管理典型应用BIOS/UEFI 固件、微控制器代码存储U盘、SSD、eMMC、SD卡、大数据存储是否需要 FTL通常不需要XIP 执行必须因为不能原地覆盖、有坏块这张表背后的工程含义很深。NOR 适合“代码存储、直接执行”是因为它支持随机读取微控制器可以从 NOR 里取指执行而 NAND 则不适合 XIPExecute in Place原地执行因为按页读取延迟太大不支持随机字节取指所以 NAND 上的代码必须先被搬运到 RAM 里才能执行。很多嵌入式新手在这上面栽过跟头把程序烧进 NAND 就以为能直接跑结果上电后完全没反应——原理上讲就是访问粒度不匹配。从热搜词里也能看出很多人搜“nor flash和nand flash的区别”说明这确实是入门的第一道坎。我建议学的时候别死记表格而是去理解一个核心问题NOR 的结构给了它随机读的能力但也限制了它的密度NAND 的结构给了它密度但夺走了随机访问的自由。所有其他差异几乎都是这个核心差异推出来的。3.2 读、写、擦除三种操作的“物理动作拆解”书里 2.1 末尾和 2.2 开头围绕电压、阈值、电流讲了很多我把它落地成三种操作的物理动作这样你在看 datasheet 时序图时更容易对应起来读操作。给选中的字线加一个参考电压 Vref给同串其他字线加高电压 Vpass通过电压让它们的存储单元强制导通然后检测位线上的电流。电流大说明目标单元阈值低于 Vref逻辑为“1”默认态电流小说明阈值高于 Vref逻辑为“0”编程态。注意NAND 的默认态未编程是“1”编程后变成“0”这在逻辑设计上跟很多人的直觉相反。这里有个实际工程技巧因为擦除后全部是 1所以“坏块标记”通常写在备用区里固定位置连带一些“0”特征检测时只要读到这些 0 就知道是坏块。写操作编程。编程不是像写 RAM 那样直接灌数据而是通过一系列电压脉冲把电子注入浮栅/电荷捕获层。现代 NAND 用的是“增量步进脉冲编程”ISPPIncremental Step Pulse Programming先加一个较低的编程电压脉冲然后验证Program Verify如果没写到位再提高一点电压重复直到单元达到目标阈值为止。这一步解释了为什么 NAND 写比读慢得多——写的过程包含多次“验证”循环而读只需要一次电压比较。擦除操作。把块里所有存储单元的浮栅电荷全部拉出来让阈值电压回到最低的“1”态。这一动作需要很大的电压差而且对整个块的所有字线同时进行。所以擦除时间通常比写一页的时间更长。表现在系统上就是掉电时正在擦除一个块如果做到一半断电这个块可能处于“半擦除”的不确定状态。实际处理中我们在固件里会做标记和擦除重试而不是简单相信硬件一定成功。3.3 用带编程器的颗粒实测从数据手册到系统层的验证光看书上原理你可能还是觉得虚。我建议你拿一颗真正的 NAND 颗粒用编程器比如我在用的 Beeprog2做一轮实测把书里的概念跟实际操作对齐。第一步查出颗粒型号。以常见的 TSOP48 封装 NAND 为例例如镁光 MT29F2G08A 等先看 datasheet确定它的“页大小 备用区大小 块内页数 块总数”。很多新手只看“2Gbit”这类容量数字却忽视了结构参数结果在计算逻辑地址时全部算错。第二步用编程器采集芯片 ID。通电后发送 read ID 命令例如 90h 00h读回 4~8 字节的 ID。前几个字节能唯一确定制造商、容量、内部结构。这个步骤特别重要因为市面上同一个封装里可能装着不同制程的颗粒没有 ID 就无法匹配时序参数。第三步做一次“全片读取”和“空片校验”。如果是一颗旧颗粒读出内容后用编程器统计坏块位置对照 datasheet 里坏块标记的规则验证“页和块”的概念。我实测中常用的几个参数记录如下可以做个参考实验项目实测要点结果与结论空片擦除后读出全片应全为 FF如果某块读出的数据不是全 FF说明该块可能已损坏或标记为坏块页编程验证对某页写 AA55再读回只有目标页变化同块其他页不受影响块擦除验证擦除包含目标页的块块内所有页全部恢复为 FF且页与页之间没有独立擦除的可能读 ID发送 90h/00h 获取 ID与 datasheet 对照确定容量和制程这个过程做完你对“页是读写单位、块是擦除单位”这句话的记忆会比看书深刻得多。我在做存储调试时最常用的命令序列包括reset (FFh)、read ID (90h/00h)、read page (00h 地址 30h)、block erase (60h 地址 D0h)、program page (80h 地址 数据 10h)。每个命令之间还有状态检测70h 读状态。书里 2.2.1 虽然还没有细讲命令序列但理解了阵列结构之后这些命令为什么长这样就很自然了先发命令指明操作类型再发地址指明页/块位置最后再次发命令触发执行。4. 常见问题与排查技巧实录从原理到实践的避坑手册4.1 坏块为什么永远存在物理层的“出厂瑕疵”和管理策略第一个常见问题是“为什么我拿到的新 NAND 就有坏块”。这很正常NAND Flash 芯片出厂时厂家会保证坏块数量不超过一定比例比如 2%并且会在坏块的备用区特定字节写入非 FF 的值作为标记。这是 NAND 用“良率”换“成本”的必然结果。刚接触 NAND 的开发者最容易犯的错误是把 NAND 当成普通存储器直接按连续地址读写不做坏块扫描也不跳过坏块。结果在某个错误位置写入数据后读出来全乱码还误以为自己硬件连错了。正确的做法是上电后先扫描坏块表BBTBad Block Table建立一个“逻辑块 - 物理块”的映射然后在读写时检查目标物理块是否在坏块表中。书里 2.2.1 还没有展开坏块管理但理解了块结构后你至少应该明白一件事为什么坏块必须“整块跳过”而不是“跳过程序擦除失败的页”。因为擦除是按块操作的块里某个页已经物理失效你没法只把这个页屏蔽掉而不影响块内其他页的擦除所以最小失效单位天然就是块。实际工程里我们一般会在系统层维护一张 BBT 映射表避免用到坏块。注意NAND 的坏块标记一般写在块内第一个页Page 0或第二个页Page 1的备用区不同厂商的规则略有不同。在做数据恢复或编程器操作时直接读备用区的坏块标记比“读数据区异常再判断”更高效。4.2 读干扰、写干扰和数据保持为什么“好好的数据会没”即使没有坏块NAND 也面临可靠性问题。读过书里的隧穿机制后就能理解这几类问题的物理本质读干扰Read Disturb。读取某一页时同串其他单元会长期处于 Vpass 高压下Vpass 虽不至于编程但反复加高压会轻微拉动电子进入浮栅导致被读单元的邻居阈值电压缓慢抬高时间久了可能出现误判。所以设计 FTL 时要注意“冷数据”长期存放在某些页不读并不会有问题反而是经常被读的页附近容易累积读干扰。实际做法是在系统空闲时定期做“数据搬移”Read Refresh把这些页的数据读到新块同时整块擦除一遍把干扰清零。写干扰Program Disturb。编程某一页时同一块内的其他页的字线也会受到电场影响尤其是未选中的串里的存储单元可能被轻微编程。所以多次写同一个块的不同页之后那些“被顺带蹭到”的页阈值也会偏。这导致了一个很重要的设计规则在同一个块里尽量避免只反复写少量页尽量按块顺序写入。很多 FTL 采用“顺序追加写”的策略而不是原地更新就是为了把写干扰降到最低。数据保持Data Retention。浮栅里的电荷会随着时间缓慢泄漏温度越高泄漏越快。写进去 0 过了几年可能变成 1。这也是为什么 NAND 不适合做档案级超长期冷存储以及为什么企业级 SSD 要定期做数据刷新Read/Scrub。数据保持问题与编程时的阈值分布宽度也有关系——编程脉冲控制得越准初始阈值分布越窄留出的读窗口越大数据保持时间也越长。4.3 ECC 不是可选项纠错能力与 NAND 寿命的换算关系按照书里的逻辑NAND 从物理层面就不可能保证每比特永远正确所以 ECC纠错码是 NAND 存储系统的必需品。这里结合我的项目经验讲一下选型时的思路。ECC 纠错能力通常用“每 1024 字节最多纠正多少个比特错误”来表示规范的说法是 ECC 强度如 60-bit ECC / 1KB。MLC/TLC 颗粒的原始误比特率RBERRaw Bit Error Rate比 SLC 高所以需要更强的 ECC。在硬件选型时要注意主控支持的 ECC 能力是否大于颗粒的 RBER 期望值。我在一个嵌入式项目里用过一款 TLC NANDdatasheet 要求的 ECC 强度是 72 bit/1KB但主控只支持 40 bit/1KB。当时只测了新品写入读取没问题就以为万事大吉。结果高温老化测试两天后有一批芯片读错误飙升超过主控纠错能力导致数据彻底丢失。后来把主控换成支持 80 bit/1KB 的方案才解决。所以选 ECC 强度时一定要给足余量宁愿超前不能卡线。颗粒类型典型 RBER原始误比特率推荐 ECC 强度项目建议SLC极低1e-9 级别1-4 bit/512B 足够工业级应用首选寿命长MLC中等1e-7 ~ 1e-624-60 bit/1KB消费级 OK车规要严格TLC较高1e-5 ~ 1e-472-120 bit/1KB必须配强 ECC注意温度QLC很高1e-3 级别200 bit/1KB谨慎使用需做好数据刷新这里还有一个小技巧检测 ECC 翻正率时不要只看有没有纠错成功还要记录“纠正了几个错误”。如果错误比特数在持续上升说明颗粒正在老化或者电压配置有问题这时候应该提前告警把数据迁移到新块而不是等到超过 ECC 极限再处理。这个“提前量”在车规和工控产品里是硬指标。4.4 用 Beeprog2 读 NAND 时的几个实战细节最后分享一些用编程器以 Beeprog2 为例操作 NAND 颗粒的实操经验。这些细节书里不会写但很实际选适配器时要注意 TSOP48 和 BGA-63 的 pin 定义完全不同别只看封装外形。BGA 芯片焊接温度比较敏感拆焊时要控制风枪温度一般 300°C 上下加助焊剂避免焊盘脱落。读取前先确认芯片是否加密或标记锁定。个别厂商尤其是带 OTP 或安全特性的颗粒在 ID 之外还有额外状态信息如果读取结果异常先查状态寄存器。做全片读取时先读一次看看坏块分布如果坏块特别多先区分是物理坏块还是编程器接触不良。我用 Beeprog2 碰到过两次“整片全坏”的情况最后发现是适配器针脚氧化导致接触不良。清理后再读就正常了。读出的镜像文件要保留一个“原始副本”再做任何修改实验。因为 NAND 的操作不是幂等的擦错一个块就等于永久丢数据。如果有条件可以再用逻辑分析仪抓一下编程器发出的命令时序跟 datasheet 的时序图做对比。我第一次抓的时候发现编程器在 read page 前会先发 set feature 命令设置 ECC 开关这解释了为什么某些芯片读出的备用区数据跟预期不同——主控的 ECC 引擎可能自动写入了校验数据。写到最后把书里的原理变成手上的手感《Inside NAND Flash Memories》第2章的 2.1 到 2.2.1 看似只是“背景知识”但它是整个 NAND 技术体系中所有后续议题的地基。我个人的体会是如果跳过这一章直接去学 FT L、磨损均衡你会觉得那些策略都是为了克服什么“奇怪的规则”学得越多越混乱反过来先想清楚“存储单元怎么存电荷”“字符串联怎么省面积”“为什么页和块是天然的操作边界”再去看 FTL 里的回写、擦除均衡、坏块映射就会有一种“全是顺理成章”的感觉。这套知识我后来也用来带过几个新人我给他们布置的“作业”不是啃手册而是用编程器实测一颗旧 NAND写一份包含芯片 ID、页/块结构、坏块分布和 ECC 强度推算的实验报告。做完这份报告的同事再去看主控的数据手册和驱动代码基本都能独立上手了。所以如果你也在学 NAND建议别只停留在“看过”这一章。找一颗实际芯片对照 datasheet 的引脚、命令和 ID 表亲手做一次读取和坏块扫描。纸上得来终觉浅这句话用在 NAND 学习上再准确不过。把书里的概念翻译成你手里那颗芯片的实测参数再用这些参数去理解主控为什么会那么设计这套方法论比背下任何一张对比表都管用。
返回列表