说说NAND FLASH以及相关ECC校验方法

 

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具体用途,总结起来有:

  1. 标记是不是坏快
  2. 存储ECC数据
  3. 存储一些和文件系统相关的数据。如jffs2就会用到这些空间存储一些特定信息,而yaffs2文件系统,会在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的位反转现象,主要是由如下一些缘由/效应所致使:

  1. 漂移效应(Drifting Effects)

    漂移效应指的是,Nand Flash中cell的电压值,慢慢地变了,变的和原始值不同了。

  2. 编程干扰所产生的错误(Program-Disturb Errors)

    此现象有时候也叫作,过分编程效应(over-program effect)。

    对于某个页面的编程操做,即写操做,引发非相关的其余的页面的某个位跳变了。

  3. 读操做干扰产生的错误(Read-Disturb Errors)

    此效应是,对一个页进行数据读取操做,却使得对应的某个位的数据,产生了永久性的变化,即Nand Flash上的该位的值变了。

对应位反转的类型,Nand Flash位反转的类型和解决办法,有两种:

  1. 一种是nand flash物理上的数据存储的单元上的数据,是正确的,只是在读取此数据出来的数据中的某位,发生变化,出现了位反转,即读取出来的数据中,某位错了,原本是0变成1,或者原本是1变成0了。此处能够成为软件上位反转。此数据位的错误,固然能够经过必定的校验算法检测并纠正。
  2. 另一种,就是nand flash中的物理存储单元中,对应的某个位,物理上发生了变化,原来是1的,变成了0,或原来是0的,变成了1,发生了物理上的位的数据变化。此处能够成为硬件上的位反转。此错误,因为是物理上发生的,虽然读取出来的数据的错误,能够经过软件或硬件去检测并纠正过来,可是物理上真正发生的位的变化,则没办法改变了。不过我的理解,好像也是能够经过擦除Erase整个数据块Block的方式去擦除此错误,不过在以后的Nand Flash的使用过程当中,估计此位仍是极可能继续发生一样的硬件的位反转的错误。

以上两种类型的位反转,其实对于从Nand Flash读取出来的数据来讲,解决其中的错误的位的方法,都是同样的,即经过必定的校验算法,常称为ECC,去检测出来,或检测并纠正错误。

若是只是单独检测错误,那么若是发现数据有误,那么再从新读取一次便可。

实际中更多的作法是,ECC校验发现有错误,会有对应的算法去找出哪位错误而且纠正过来。

其中对错误的检测和纠正,具体的实现方式,有软件算法,也有硬件实现,即硬件Nand Flash的控制器controller自己包含对应的硬件模块以实现数据的校验和纠错的。

Nand Flash的一些typical特性

  1. 页擦除时间是200us,有些慢的有800us
  2. 块擦除时间是1.5ms
  3. 页数据读取到数据寄存器的时间通常是20us
  4. 串行访问(Serial access)读取一个数据的时间是25ns,而一些旧的Nand Flash是30ns,甚至是50ns
  5. 输入输出端口是地址和数据以及命令一块儿multiplex复用的
  6. Nand Flash的编程/擦除的寿命:即,最多容许10万次的编程/擦除,达到和接近于以前常见的Nor Flash,几乎是一样的使用寿命了。
  7. 封装形式:48引脚的TSOP1封装 或 52引脚的ULGA封装

Nand Flash控制器与Nand Flash芯片

咱们写驱动,是写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

只擦除好的块,对于已经标记坏块的块,不要轻易擦除掉,不然就很难区分哪些是出厂时就坏的,哪些是后来使用过程当中用坏的了。

Uboot 的轻量级坏块管理方法

NAND 坏块管理都是基于坏块表(BBT)的,经过这张表来标识系统中的全部坏块。因此,不一样的管理方法之间的差别能够经过如下几个问题来找到答案。

  • 如何初始化和读取坏块表?
  • 产生新的坏块时,如何标记并更新坏块表?
  • 如何保存坏块表?是否有保存时断电保护机制?
  • 对 NAND 写入数据时,若是当前块是坏块,如何找到可替换的好块?

Uboot 是目前使用最为普遍的 bootloader,它提供了两种轻量级坏块管理方法,可称之为基本型和改进型。经过下表,咱们能够看到二者的差别。

虽然 uboot 的改进型坏块管理方法的作了一些改进,但它仍然有三个主要的缺点。

  1. 出现坏块,则将数据顺序写入下一个好块。若是 NAND 中存放了多个软件模块,则每一个模块都须要预留一个较大的空间做为备用的好块,这会浪费较多的 NAND 空间。一般,每一个模块预留的备用好块数为 NAND 芯片所容许的最大坏块数,该值因不一样的芯片而有所不一样,典型值为 20 或 80。假设 NAND 是大页类型,总共有 N 个模块,则总共须要预留的空间大小为 N*80*128KB。
  2. 读取 BBT 时仅检查签名,没有对 BBT 的数据作校验。
  3. 没有掉电保护机制。若是在保存 BBT 时断电,BBT 将丢失。

针对现有管理方法的缺陷,本文提出了一种更加安全高效的管理方法,将从如下三个方面阐述其实现原理。

共用好块池机制

首先,使用一个统一的备用好块池,为全部存放在 NAND 中的模块提供可替换的好块。这样,就不须要在每一个模块后面放置一个保留区,提升了 NAND 的空间利用率。

共用好块池示意图

共用好块池示意图

为了实现共用好块池,须要创建一个从坏块到好块的映射,因此,除了 BBT 以外,还需定义一个替换表(SBT)。这样一来,当读第 i 个块的数据时,若是发现 BBT 中记录该块为坏块,就去 SBT 中查询其替换块;若是写第 i 个块出错,须要在 BBT 中标记该块为坏块,同时从好块池中获取一个新的好块,假设其序号为 j,而后将此好块的序号 j 写入 SBT 中的第 i 个字节,并且 SBT 的第 j 个字节写序号 i。SBT 中的这种双向映射可确保数据的可靠性。此外,好块池中的块也有可能成为坏块,若是扫描时发现是坏块,则将 SBT 中的对应位置标记为 0x00,若是是在写的过程当中出错,则除了在 SBT 对应位置标记 0x00 以外,还要更新双向映射数据。

 BBT/SBT 映射示意图

 

安全的 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 的保存形式

BBT/SBT 的保存形式

使用三重 CRC 校验机制,不管 BBT 保存在哪一种存储体中,均可以更加严格地验证数据的有效性。

安全的掉电保存机制

传统的方法仅保存一份 BBT 数据,若是在写 BBT 时系统掉电,则 BBT 丢失,系统将可能没法正常启动或工做。为安全起见,本文所述方法将同时保留三个备份,若是在写某个备份时掉电,则还有两个无缺的备份。最坏的状况是,若是在写第一个备份时掉电,则当前最新的一个坏块信息丢失。

读取坏块表时,顺序读取三个备份,若是发现三个备份的数据不一致,用记录的坏块数最多的备份为当前的有效备份,同时马上更新另外两备份。

总结

本文介绍了NandFlash基础知识和几类 NAND 坏块管理方法,指出了 uboot 的轻量级管理方法的缺陷,提出了一种改进的方法,提升了 NAND 的利用率及坏块管理的安全性,可对嵌入式开发起到有很好的借鉴做用。

ECC定义

ECC校验是一种内存纠错原理,它是比较先进的内存错误检查和更正的手段。 ECC内存即纠错内存,简单的说,其具备发现错误,纠正错误的功能,通常多应用在高档台式电脑/服务器及 图形工做站上,这将使整个电脑系统在工做时更趋于安全稳定。
 

技术原理

内存是一种电子器件,在其工做过程当中不免会出现错误,而对于稳定性要求高的用户来讲,内存错误可能会引发致命性的问题。内存错误根据其缘由还可分为 硬错误和软错误。硬件错误是因为硬件的损害或缺陷形成的,所以数据老是不正确,此类错误是没法纠正的;软错误是随机出现的,例如在内存附近忽然出现 电子干扰等因素均可能形成内存软错误的发生。
为了能检测和纠正内存软错误,在 ECC技术出现以前,首先出现的是内存“ 奇偶校验(Parity)”。内存中最小的单位是比特,也称为“位(bit)”,位有只有两种状态分别以1和0来标示,每8个连续的比特叫作一个字节(byte)。不带奇偶校验的内存每一个字节只有8位,若是其某一位存储了错误的值,就会致使其存储的相应数据发生变化,进而致使应用程序发生错误。而奇偶校验就是在每一字节(8位)以外又增长了一位做为错误检测位。在某字节中存储数据以后,在其8个位上存储的数据是固定的,由于位只能有两种状态1或0,假设存储的数据用位标示为一、一、一、0、0、一、0、1,那么把每一个位相加(1+1+1+0+0+1+0+1=5),结果是奇数。对于 偶校验,校验位就定义为1,反之则为0;对于 奇校验,则相反。当CPU读取存储的数据时,它会再次把前8位中存储的数据相加,计算结果是否与 校验位相一致。从而必定程度上能检测出内存错误, 奇偶校验只能检测出错误而没法对其进行修正,同时虽然双位同时发生错误的几率至关低,奇偶校验却没法检测出双位错误。
经过上面的分析咱们知道 Parity内存是经过在原来 数据位的基础上增长一个数据位来检查当前8位数据的正确性,但随着数据位的增长Parity用来检验的数据位也成倍增长,就是说当数据位为16位时它须要增长2位用于检查,当数据位为32位时则需增长4位,依此类推。特别是当数据量很是大时,数据出错的概率也就越大,对于只能纠正简单错误的奇偶检验的方法就显得力不从心了,正是基于这样一种状况,一种新的内存技术应允而生了,这就是 ECC(错误检查和纠正),这种技术也是在原来的数据位上外加校验位来实现的。不一样的是二者增长的方法不同,这也就致使了二者的主要功能不太同样。它与 Parity不一样的是若是 数据位是8位,则须要增长5位来进行ECC错误检查和纠正,数据位每增长一倍,ECC只增长一位检验位,也就是说当数据位为16位时ECC位为6位,32位时ECC位为7位,数据位为64位时ECC位为8位,依此类推,数据位每增长一倍,ECC位只增长一位。总之,在内存中 ECC可以允许错误,并能够将错误更正,使系统得以持续正常的操做,不致因错误而中断,且ECC具备自动更正的能力,能够将Parity没法检查出来的错误位查出并将错误修正。

示例

ECC(Error Checking and Correcting,错误检查和纠正)内存,它一样也是在 数据位上额外的位存储一个用 数据加密的代码。当数据被写入内存,相应的ECC代码与此同时也被保存下来。当从新读回刚才存储的数据时,保存下来的 ECC代码就会和读数据时产生的ECC代码作比较。若是两个代码不相同,他们则会被解码,以肯定数据中的哪一位是不正确的。而后这一错误位会被抛弃, 内存控制器则会释放出正确的数据。被纠正的数据不多会被放回内存。假如相同的错误数据再次被读出,则纠正过程再次被执行。重写数据会增长处理过程的开销,这样则会致使系统性能的明显下降。若是是随机事件而非内存的缺点产生的错误,则这一 内存地址的错误数据会被再次写入的其余数据所取代。
相关文章
相关标签/搜索