Flash名称的由来,Flash的擦除操做是以block块为单位的,与此相对应的是其余不少存储设备,是以bit位为最小读取/写入的单位,Flash是一次性地擦除整个块:在发送一个擦除命令后,一次性地将一个block,常见的块的大小是128KB/256KB,所有擦除为1,也就是里面的内容所有都是0xFF了,因为是一会儿就擦除了,相对来讲,擦除用的时间很短,能够用一闪而过来形容,因此,叫作Flash Memory。因此通常将Flash翻译为 (快速)闪存。算法
NAND Flash 在嵌入式系统中有着普遍的应用,负载平均和坏块管理是与之相关的两个核心议题。Uboot 和 Linux 系统对 NAND 的操做都封装了对这两个问题的处理方法。 本文首先讲述Nandflash基础知识,而后介绍现有的几类坏块管理(BBM)方法,经过分析典型嵌入式系统的 NAND 存储表,指出了轻量级管理方法的优点所在,分析了当前普遍使用的轻量级管理方法,指出其缺陷所在并详细说明了改进方法。sql
基础知识 编程
Flash的硬件实现机制缓存
Flash的内部存储是MOSFET,里面有个悬浮门(Floating Gate),是真正存储数据的单元。安全
在Flash以前,紫外线可擦除(uv-erasable)的EPROM,就已经采用了Floating Gate存储数据这一技术了。服务器
典型的Flash内存物理结构 性能
数据在Flash内存单元中是以电荷(electrical charge) 形式存储的。存储电荷的多少,取决于图中的外部门(external gate)所被施加的电压,其控制了是向存储单元中冲入电荷仍是使其释放电荷。而数据的表示,以所存储的电荷的电压是否超过一个特定的阈值Vth来表示,所以,Flash的存储单元的默认值,不是0(其余常见的存储设备,好比硬盘灯,默认值为0),而是1,而若是将电荷释放掉,电压下降到必定程度,表述数字0。加密
NandFlash的简介
Nand flash成本相对低,说白了就是便宜,缺点是使用中数据读写容易出错,因此通常都须要有对应的软件或者硬件的数据校验算法,统称为ECC。但优势是,相对来讲容量比较大,如今常见的Nand Flash都是1GB,2GB,更大的8GB的都有了,相对来讲,价格便宜,所以适合用来存储大量的数据。其在嵌入式系统中的做用,至关于PC上的硬盘,用于存储大量数据。
SLC和MLC
Nand Flash按照内部存储数据单元的电压的不一样层次,也就是单个内存单元中,是存储1位数据,仍是多位数据,能够分为SLC和MLC。那么软件如何识别系统上使用过的SLC仍是MLC呢?
Nand Flash设计中,有个命令叫作Read ID,读取ID,读取好几个字节,通常最少是4个,新的芯片,支持5个甚至更多,从这些字节中,能够解析出不少相关的信息,好比此Nand Flash内部是几个芯片(chip)所组成的,每一个chip包含了几片(Plane),每一片中的页大小,块大小,等等。在这些信息中,其中有一个,就是识别此flash是SLC仍是MLC。 spa
oob / Redundant Area / Spare Area翻译
每个页,对应还有一块区域,叫作空闲区域(spare area)/冗余区域(redundant area),而Linux系统中,通常叫作OOB(Out Of Band),这个区域,是最初基于Nand Flash的硬件特性:数据在读写时候相对容易错误,因此为了保证数据的正确性,必需要有对应的检测和纠错机制,此机制被叫作EDC(Error Detection Code)/ECC(Error Code Correction, 或者 Error Checking and Correcting),因此设计了多余的区域,用于放置数据的校验值。
Oob的读写操做,通常是随着页的操做一块儿完成的,即读写页的时候,对应地就读写了oob。
关于oob具体用途,总结起来有:
Bad Block Management坏块管理
Nand Flash因为其物理特性,只有有限的擦写次数,超过那个次数,基本上就是坏了。在使用过程当中,有些Nand Flash的block会出现被用坏了,当发现了,要及时将此block标注为坏块,再也不使用。于此相关的管理工做,属于Nand Flash的坏块管理的一部分工做。
Wear-Leveling负载平衡
Nand Flash的block管理,还包括负载平衡。
正是因为Nand Flash的block,都是有必定寿命限制的,因此若是你每次都往同一个block擦除而后写入数据,那么那个block就很容易被用坏了,因此咱们要去管理一下,将这么屡次的对同一个block的操做,平均分布到其余一些block上面,使得在block的使用上,相对较平均,这样相对来讲,能够更能充分利用Nand Flash。
ECC错误校验码
Nand Flash物理特性上使得其数据读写过程当中会发生必定概率的错误,因此要有个对应的错误检测和纠正的机制,因而才有此ECC,用于数据错误的检测与纠正。Nand Flash的ECC,常见的算法有海明码和BCH,这类算法的实现,能够是软件也能够是硬件。不一样系统,根据本身的需求,采用对应的软件或者是硬件。
相对来讲,硬件实现这类ECC算法,确定要比软件速度要快,可是多加了对应的硬件部分,因此成本相对要高些。若是系统对于性能要求不是很高,那么能够采用软件实现这类ECC算法,可是因为增长了数据读取和写入先后要作的数据错误检测和纠错,因此性能相对要下降一些,即Nand Flash的读取和写入速度相对会有所影响。
其中,Linux中的软件实现ECC算法,即NAND_ECC_SOFT模式,就是用的对应的海明码。
而对于目前常见的MLC的Nand Flash来讲,因为容量比较大,动辄2GB,4GB,8GB等,经常使用BCH算法。BCH算法,相对来讲,算法比较复杂。
笔者因为水平有限,目前仍未彻底搞懂BCH算法的原理。
BCH算法,一般是由对应的Nand Flash的Controller中,包含对应的硬件BCH ECC模块,实现了BCH算法,而做为软件方面,须要在读取数据后,写入数据以前,分别操做对应BCH相关的寄存器,设置成BCH模式,而后读取对应的BCH状态寄存器,得知是否有错误,和生成的BCH校验码,用于写入。
其具体代码是如何操做这些寄存器的,因为是和具体的硬件,具体的nand flash的controller不一样而不一样,没法用同一的代码。若是你是nand flash驱动开发者,天然会获得对应的起nand flash的controller部分的datasheet,按照手册说明,去操做便可。
不过,额外说明一下的是,关于BCH算法,每每是要从专门的作软件算法的厂家购买的,可是Micron以前在网上放出一个免费版本的BCH算法。
位反转
Nand Flash的位反转现象,主要是由如下一些缘由/效应所致使:
漂移效应指的是,Nand Flash中cell的电压值,慢慢地变了,变的和原始值不同了。
此现象有时候也叫作,过分编程效应(over-program effect)。
对于某个页面的编程操做,即写操做,引发非相关的其余的页面的某个位跳变了。
此效应是,对一个页进行数据读取操做,却使得对应的某个位的数据,产生了永久性的变化,即Nand Flash上的该位的值变了。
以上两种类型的位反转,其实对于从Nand Flash读取出来的数据来讲,解决其中的错误的位的方法,都是同样的,即经过必定的校验算法,常称为ECC,去检测出来,或检测并纠正错误。
若是只是单独检测错误,那么若是发现数据有误,那么再从新读取一次便可。
实际中更多的作法是,ECC校验发现有错误,会有对应的算法去找出哪位错误而且纠正过来。
其中对错误的检测和纠正,具体的实现方式,有软件算法,也有硬件实现,即硬件Nand Flash的控制器controller自己包含对应的硬件模块以实现数据的校验和纠错的。
咱们写驱动,是写Nand Flash 控制器的驱动,而不是Nand Flash 芯片的驱动,由于独立的Nand Flash芯片,通常来讲,是不多直接拿来用的,多数都是硬件上有对应的硬件的Nand Flash的控制器,去操做和控制Nand Flash,包括提供时钟信号,提供硬件ECC校验等等功能,咱们所写的驱动软件,是去操做Nand Flash的控制器
而后由控制器去操做Nand Flash芯片,实现咱们所要的功能。
因为Nand Flash读取和编程操做来讲,通常最小单位是页,因此Nand Flash在硬件设计时候,就考虑到这一特性,对于每一片(Plane),都有一个对应的区域专门用于存放,将要写入到物理存储单元中去的或者刚从存储单元中读取出来的,一页的数据,这个数据缓存区,本质上就是一个缓存buffer,可是只是此处datasheet里面把其叫作页寄存器page register而已,实际将其理解为页缓存,更贴切原意。
而正是由于有些人不了解此内部结构,才容易产生以前遇到的某人的误解,觉得内存里面的数据,经过Nand Flash的FIFO,写入到Nand Flash里面去,就觉得马上实现了实际数据写入到物理存储单元中了,而实际上只是写到了这个页缓存中,只有当你再发送了对应的编程第二阶段的确认命令,即0x10,以后,实际的编程动做才开始,才开始把页缓存中的数据,一点点写到物理存储单元中去。
具体标记的地方是,对于如今常见的页大小为2K的Nand Flash,是块中第一个页的oob起始位置的第1个字节(旧的小页面,pagesize是512B甚至256B的Nand Flash,坏块标记是第6个字节),若是不是0xFF,就说明是坏块。相对应的是,全部正常的块,好的块,里面全部数据都是0xFF的。
对于坏块的标记,本质上,也只是对应的flash上的某些字节的数据是非0xFF而已,因此,只要是数据,就是能够读取和写入的。也就意味着,能够写入其余值,也就把这个坏块标记信息破坏了。对于出厂时的坏块,通常是不建议将标记好的信息擦除掉的。
uboot中有个命令是
nand scrub
就能够将块中全部的内容都擦除了,包括坏块标记,不管是出厂时的,仍是后来使用过程当中出现而新标记的。
nand erase
只擦除好的块,对于已经标记坏块的块,不要轻易擦除掉,不然就很难区分哪些是出厂时就坏的,哪些是后来使用过程当中用坏的了。
NAND 坏块管理都是基于坏块表(BBT)的,经过这张表来标识系统中的全部坏块。因此,不一样的管理方法之间的差别能够经过如下几个问题来找到答案。
Uboot 是目前使用最为普遍的 bootloader,它提供了两种轻量级坏块管理方法,可称之为基本型和改进型。经过下表,咱们能够看到二者的差别。
虽然 uboot 的改进型坏块管理方法的作了一些改进,但它仍然有三个主要的缺点。
针对现有管理方法的缺陷,本文提出了一种更加安全高效的管理方法,将从如下三个方面阐述其实现原理。
首先,使用一个统一的备用好块池,为全部存放在 NAND 中的模块提供可替换的好块。这样,就不须要在每一个模块后面放置一个保留区,提升了 NAND 的空间利用率。
共用好块池示意图
为了实现共用好块池,须要创建一个从坏块到好块的映射,因此,除了 BBT 以外,还需定义一个替换表(SBT)。这样一来,当读第 i 个块的数据时,若是发现 BBT 中记录该块为坏块,就去 SBT 中查询其替换块;若是写第 i 个块出错,须要在 BBT 中标记该块为坏块,同时从好块池中获取一个新的好块,假设其序号为 j,而后将此好块的序号 j 写入 SBT 中的第 i 个字节,并且 SBT 的第 j 个字节写序号 i。SBT 中的这种双向映射可确保数据的可靠性。此外,好块池中的块也有可能成为坏块,若是扫描时发现是坏块,则将 SBT 中的对应位置标记为 0x00,若是是在写的过程当中出错,则除了在 SBT 对应位置标记 0x00 以外,还要更新双向映射数据。
BBT/SBT 映射示意图
传统方法仅检查 BBT 所在块的签名,将读到的前几个字节和一个特征字符串进行比较,若是一致,就认为当前块的数据为 BBT,而后读取接下来的 BBT 数据,但并不对 BBT 的数据作校验。若是 BBT 保存在 NAND 中,数据的有效性是能够获得验证的,由于 NAND 控制器或驱动通常都会对数据作 ECC 校验。可是,大多数控制器使用的 ECC 算法也仅仅能纠正一个 bit、发现 2 两个 bit 的错误。若是 BBT 保存在其余的没有 ECC 校验机制的存储体中,好比 NOR Flash,没有对 BBT 的数据进行校验显然是不安全的。
为了更加可靠和灵活地验证 BBT/SBT 数据,定义下面这个结构体来描述 BBM 信息。
BBM 头信息
typedef struct {
UINT8 acSignature[4];/* BBM 签名 */
UINT32 ulBBToffset;/* BBT 偏移 */ UINT32 ulSBToffset;/* SBT 偏移 */ UINT16 usBlockNum;/* BBM 管理的 block 数目 */ UINT16 usSBTstart;/* SBT 所在位置的起始 block 序号 */ UINT16 usSBtop;/* SBT top block */ UINT16 usSBnum;/* SBT number */ UINT32 ulBBTcrc;/* BBT 数据 CRC 校验码 */ UINT32 ulSBTcrc;/* SBT 数据 CRC 校验码 */ UINT32 ulHeadcrc;/* BBM 头信息 CRC 校验码 */ } BBM_HEAD
BBT/SBT 的保存形式
使用三重 CRC 校验机制,不管 BBT 保存在哪一种存储体中,均可以更加严格地验证数据的有效性。
传统的方法仅保存一份 BBT 数据,若是在写 BBT 时系统掉电,则 BBT 丢失,系统将可能没法正常启动或工做。为安全起见,本文所述方法将同时保留三个备份,若是在写某个备份时掉电,则还有两个无缺的备份。最坏的状况是,若是在写第一个备份时掉电,则当前最新的一个坏块信息丢失。
读取坏块表时,顺序读取三个备份,若是发现三个备份的数据不一致,用记录的坏块数最多的备份为当前的有效备份,同时马上更新另外两备份。
本文介绍了NandFlash基础知识和几类 NAND 坏块管理方法,指出了 uboot 的轻量级管理方法的缺陷,提出了一种改进的方法,提升了 NAND 的利用率及坏块管理的安全性,可对嵌入式开发起到有很好的借鉴做用。