2024年2月10日发(作者:)

什么是NOR和NAND闪存?

NOR和NAND是现在市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NORflash技术,紧接着,1989年,东芝公司 发表了NAND flash结构。NAND

flash的单元尺寸几乎是NOR器件的一半,由于生产过程更为简单,NAND结构可以在给定的模具尺寸内提供更高的容量,也就相应地降低了产品的价格。而且,它的写入和擦除速度很快,因此,其主要功能是存储资料,例如在CompactFlash、Secure Digi-tal、PCCards和MMC存储卡市场上所占份额最大。

NOR的传输效率很高,在小容量时具有很高的成本效益,更加安全,不容易出现数据故障,因此,主要应用以代码存储为主,多与运算相关。

目前,NAND闪存主要用在数码相机闪存卡和MP3播放机中,这两个市场的增长非常迅速。而NOR芯片主要用在手机和机顶盒中,这两个市场的增长速度相对较慢。

NOR和NAND Flash存储器的区别

NOR和NAND是现在市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面。紧接着,1989年,东芝公司发表了NAND flash结构,强调降低每比特的成本,更高的性能,并且象磁盘一样可以通过接口轻松升级。但是经过了十多年之后,仍然有相当多的硬件工程师分不清NOR和NAND闪存。 相“flash存储器”经常可以与相“NOR存储器”互换使用。许多业内人士也搞不清楚NAND闪存技术相对于NOR技术的优越之处,因为大多数情况下闪存只是用来存储少量的代码,这时NOR闪存更适合一些。而NAND则是高数据存储密度的理想解决方案。 NOR的特点是芯片内执行(XIP, eXecute In Place),这样应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中。 NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。 NAND结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快。应用NAND的困难在于flash的管理和需要特殊的系统接口。 性能比较 flash闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。任何flash器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。NAND器件执行擦除操作是十分简单的,而NOR则要求在进行擦除前先要将目标块内所有的位都写为0。 由于擦除NOR器件时是以64~128KB的块进行的,执行一个写入/擦除操作的时间为5s,与此相反,擦除NAND

器件是以8~32KB的块进行的,执行相同的操作最多只需要4ms。 执行擦除时块尺寸的不同进一步拉大了NOR和NADN之间的性能差距,统计表明,对于给定的一套写入操作(尤其是更新小文件时更多的擦除操作必须在基于NOR的单元中进行。这样,当选择存储解决方案时,设计师必须权衡以下的各项因素。 ● NOR的读速度比NAND稍快一些。 ● NAND的写入速度比NOR快很多。 ● NAND的4ms擦除速度远比NOR的5s快。 ● 大多数写入操作需要先进行擦除操作。

● NAND的擦除单元更小,相应的擦除电路更少。接口差别 NOR flash带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每一个字节。 NAND器件使用复杂的I/O口来串行地存取数据,各个产品或厂商的方法可能各不相同。8个引脚用来传送控制、地址和数据信息。 NAND读和写操作采用512字节的块,这一点有点像硬盘管理此类操作,很自然地,基于NAND的存储器就可以取代硬盘或其他块设备。 容量和成本 NAND flash的单元尺寸几乎是NOR器件的一半,由于生产过程更为简单,NAND结构可以在给定的模具尺寸内提供更高的容量,也就相应地降低了价格。 NOR flash占据了容量为1~16MB闪存市场的大部分,而NAND

flash只是用在8~128MB的产品当中,这也说明NOR主要应用在代码存储介质中,NAND适合于数据存储,NAND在CompactFlash、Secure Digital、PC Cards和MMC存储卡市场上所占份额最大。 可靠性和耐用性 采用flahs介质时一个需要重点考虑的问题是可靠性。对于需要扩展MTBF的系统来说,Flash是非常合适的存储方案。可以从寿命(耐用性)、位交换和坏块处理三个方面来比较NOR和NAND的可靠性。 寿命(耐用性) 在NAND闪存中每个块的最大擦写次数是一百万次,而NOR的擦写次数是十万次。NAND存储器除了具有10比1的块擦除周期优势,典型的NAND块尺寸要比NOR器件小8倍,每个NAND存储器块在给定的时间内的删除次数要少一些。 位交换所有flash器件都受位交换现象的困扰。在某些情况下(很少见,NAND发生的次数要比NOR多),一个比特位会发生反转或被报告反转了。 一位的变化可能不很明显,但是如果发生在一个关键文件上,这个小小的故障可能导致系统停机。如果只是报告有问题,多读几次就可能解决了。当然,如果这个位真的改变了,就必须采用错误探测/错误更正(EDC/ECC)算法。位反转的问题更多见于NAND闪存,NAND的供应商建议使用NAND闪存的时候,同时使用EDC/ECC算法。 这个问题对于用NAND存储多媒体信息时倒不是致命的。当然,如果用本地存储设备来存储操作系统、配置文件或其他敏感信息时,必须使用EDC/ECC系统以确保可靠性。 坏块处理 NAND器件中的坏块是随机分布的。以前也曾有过消除坏块的努力,但发现成品率太低,代价太高,根本不划算。 NAND器件需要对介质进行初始化扫描以发现坏块,并将坏块标记为不可用。在已制成的器件中,如果通过可靠的方法不能进行这项处理,将导致高故障率。易于使用 可以非常直接地使用基于NOR的闪存,可以像其他存储器那样连接,并可以在上面直接运行代码。 由于需要I/O接口,NAND要复杂得多。各种NAND器件的存取方法因厂家而异。 在使用NAND器件时,必须先写入驱动程序,才能继续执行其他操作。向NAND器件写入信息需要相当的技巧,因为设计师绝不能向坏 块写入,这就意味着在NAND器件上自始至终都必须进行虚拟映射。 软件支持 当讨论软件支持的时候,应该区别基本的读/写/擦操作和高一级的用于磁盘仿真和闪存管理算法的软件,包括性能优化。 在NOR器件上运行代码不需要任何的软件支持,在NAND器件上进行同样操作时,通常需要驱动程序,也就是内存技术驱动程序(MTD),NAND和NOR器件在进行写入和擦除操作时都需要MTD。 使用NOR器件时所需要的MTD要相对少一些,许多厂商都提供用于NOR器件的更高级软件,这其中包括M-System

的TrueFFS驱动,该驱动被Wind River System、Microsoft、QNX Software System、Symbian和Intel等厂商所采用。 驱动还用于对DiskOnChip产品进行仿真和NAND闪存的管理,包括纠错、坏块处理和损耗平衡。

uClinux是近几年兴起的一个嵌入式Linux的变种。它主要用于微控制领域的一些没有MMU(Memory Management Unit)的系列CPU。近来在消费类电子产品中也得到了广泛的应用。

目前uClinux可以稳定的运行在ARM,MIPS,Powrepc等系列CPU上。因为没有MMU单元的CPU相较而言更为便宜,因此国内也有大批的爱好者自己制作开发板来进行uClinux的开发。作为此类的嵌入式系统一般采用Flash作为存储设备。本文主要讨论在uClinux系统中启动,运行时使用Flash的理论和实践方法。

本文首先要介绍一下常用的Flash以及uClinux系统在Flash中如何进行存储。接着会阐述一下Flash在内核中被如何驱动,同时介绍一下常用根文件系统的选择。

本文在理论上分析,阐述了怎样使用,选择根文件系统以及它们在Flash上的实现。并且给出了一个例子。但是真正的嵌入式系统中如何使用Flash将和使用的硬件相关。欢迎大家和我讨论这个问题。

1,Flash的简介

在过去的20年里,嵌入式系统一直使用ROM(EPROM) 作为它们的存储设备。然而近年来Flash 全面代替了ROM(EPROM)在嵌入式系统中的地位。因为相较ROM而言,Flash有成本低,可*,容易改写等优点。

目前Flash主要有两种 NOR Flash 和 NADN Flash 它们在应用上有所不同因此也用于不同的场合。

读取NOR Flash和读取我们常见的SDRAM是一样的。它的所有地址都是可见的,你可以读取它任意随机地址的值。同时它和SDRAM一样你可以直接运行装载在NOR FLASH里面的代码,这就是作谓的XIP(Execute-In-Place)技术。因为NOR

Flash有这种特性,所以它非常适用于小型嵌入式系统。你可以把你的代码装载到Flash中,在系统启动的时候直接运行它,而减少SRAM的容量从而节约了成本。

从这种意义上来说,NOR FLASH已经可以代替原先我们一直使用的标准的ROM。并且还具有ROM所没有的特性。

目前市面上的FLASH 主要来自Intel,AMD,Fujitsu,和Toshiba。常用的容量一般在128K到64M之间。

NAND Flash 没有采取内存的随机读取技术。它的读取是以一次读取一快的形式来进行的,通常是一次读取512个字节。采用这种技术的Flash比较廉价。但是和所有块设备一样,NAND

Flash 比较容易出现怀位。这需要我们采用软件来避免使用这些位。这样以来就增加了软件的复杂度。你不能直接运行NAND Flash上的代码。因此好多使用NAND Flash的开发板除了使用NAND Flah以外,还作上了一块小的NOR Flash来运行启动代码。这样作会增加系统的复杂度。不过最近这种现象有

所改观。三星最近生产的一批采用ARM Core的CPU,采用了一个内部的缓冲来存放NAND Flash里读取的东西。以此来直接运行NAND FLASH里面启动代码。比如基于Arm920T和新的S3c2410芯片。

另外,我们最常见的NAND FLASH的应用是嵌入式系统采用的DOC(Disk

On Chip)和我们通常用的“闪盘”。

目前生产NAND Flash的主要厂家有Samsung 和Toshiba。最大容量已经突破了1G位。写Flash和写SRAM截然不同。它是通过一系列指令才能完成一个写操作的。而我们同用的RAM直接写入即可。无论是NOR Flash 还是NAND

Flash都有一个“扇区”的概念。这个“扇区”从8K到256K不等。在写操作中它将作为一个整体来操作。 要向某个地址里面写如一个值得先看一下这个地址原先的值是不是全为“1“。如果全为“1”,那么通过一系列指令可以将这个值写如。反之,则先要进行擦除使其全部变为“1”。擦除操作是不能用一个地址来操作的。擦除必须一次擦除一个“扇区“。把这个“扇区”所有的值都变为“1”,然后才能进行写操作。

不同型号的Flash的操作指令不同。具体操作的时候需要自习阅读你所使用产品的产品说明书。

关于Flash的话题还有很多,但是本文着重谈论Flash在uClinux系统中的应用。对Flash本身感兴趣的读者可以自行阅读其他相关资料

2,基于Flash的uClinux系统

传统意义上嵌入式系统的存储系统通常由Flash和RAM组成。Flash的成本通常又高于RAM的成本。因此系统的存储系统由多大容量的RAM多大容量的FLASH组成,通常根据产品的需求和成本的考虑来决定。

在基于uClinux的嵌入式系统中,Flash是整个系统代码和数据的储存器件。通常的做法是将uClinux核心的起始代码放在处理器加电所运行的地址处。这个地址必定是在FLASH中的。因为NOR Flash里面的代码可以直接执行。在很多的应用中采用了不使用RAM,直接让uClinux在Flash里面运行。而出于速度和成本的考虑更多的做法是将uClinux系统存放在Flash中根据系统运行的情况把要执行的部分拷贝到RAM中执行。

为了实现上述思想我们通常把Flash分区。当然这里分区的概念和我们给硬盘分区的含义大不一样。这里的分区十分简单,就是把Flash按照地址分成不同的区间在特定的区间中放入不同的代码或者数据。使得整个系统比较有序和容易调试开发。

一个典型的例子,比如:

块号 地址 用途

0 0x0—0x? 启动代码

1

2 0x….. uClinux 核心

3

4 0x… 根文件系统

5

在这个例子中第0个分区,也就是Flash的起始位置我们放置了系统启动代码。第1个分区我们可以放置一些配置数据之类的数据。接下来的一个分

区我们存放着uClinux的核心。并且我们用另外的一些分区来放置系统的根文件系统。

以此可见,我们完全可以根据自己的需要把Flash分成不同的区来使用。在以后的讨论中我们可以直到uClinux的块设备驱动支持我们这样的操作。因此我们的焦点将集中在如何划分不同的区域来达到我们的应用。

通过上面的介绍我们知道Flash的擦写需要根据Flash的扇区来进行。一次擦写至少要擦除一个扇区内所有的内容。因此我们给Flash分区的时候最先要确定的是每个分区需要多少个Flash的扇区。从第几个到第几个,这样以后的操作才可*简单。

从上面的例子来看,uClinux的内核和根文件系统并不在一个分区。内核放在一个特定的地址。要访问内核必须从某个地址开始整个的访问。而不同于我们同用的桌面版或者服务器版的Linux可以把内核作为一个文件来存放在文件系统中。

那么这两种方法有什么不同呢?

在我们的例子,把内核单独放在一个分区中。这需要启动的时候启动程序把整个内核拷贝到RAM里面然后运行它。或者采用我们前面提到的XIP

技术在Flash里面运行。而传统的Linux则需要启动程序来确定内核的位置和需要把内核的那部分加载到RAM里面来运行(类似于台式机Linux系统上的LILO或者GRIUB)。

那么如何选择Flash的分区,以及各个分区存放的内容呢?我想这个要根据各自产品的特点和开发的周期来考虑。接下来我们列出在uClinux系统中常用的几种分区方法并且讨论它们各自的优劣。

a) 内核和根文件系统都在固定的分区固定的地址

b) 内核在根文件系统之后或者之前

c) 压缩的内核作为根文件系统下的一个文件

a的优势在与系统主要的组成部分都有各自固定的地址。启动程序可以直到内核所在的地址,而内核直到根文件系统的地址。这样启动程序加载内核或者内核挂装根文件系统的时候所进行的操作比较简单。并且我们可以很方便的升级这些组成部分。缺点就是将不可避免的造成内核和根文件系统之间Flash的浪费。

b的做法节约了一部分Flash的空间。但是它把内核同根文件系统一快编译成了一个二进制文件。这样你必须同时升级内核和根文件系统。不过这样作的好处是编译选项比较简单。容易维护。初次开发建议使用这种方法。

c的做法由于使用了压缩的核心所有节约了大量的空间。但是必须需要一个启动程序来把内核解压缩到RAM中。这样就需要一个比较充裕的RAM空间。启动程序增加了复杂度。不过一旦你写好这个驱动程序,你就可以不再修改它而将所有精力放在uClinux核心和根文件系统的开发上。

当然,根据产品需要我们不排除使用多个文件系统的选择。原因很简单,比如你需要对你的某个分区进行读/写操作而对其他一个区只要进行只读操作。由于Flash的读/写特性您就要作比较复杂的设计。对于这种情况,下文有所提及。

3,uClinux系统的bootloader

作为系统的启动程序,最先要考虑的是CPU在加电的时候运行那个地

址的代码。有些CPU比如X86,ARM在加电的时候运行固定地址的代码;也有些CPU比如m68k, ColdFire,在加电的时候读取一个固定的地址,然后用这个地址的值作为最先执行代码的的地址。在现有的系统中这个地址是在Falsh里面的。

那么我们要考虑的就是在这个地址里面放入我们的代码,以便CPU加电后就执行这行代码。

我们允许CPU加电后直接运行uClinux的内核代码。这时候uClinux的代码需要作一系列的事情。比如初始化硬件,比如初始化RAM;把uClinux内核中的数据段拷贝到RAM中去;清空BSS段等。不过最重要的还是将它的首行代码放到合适的地方。

使用BootLoader我们就可以做根多的事情。比如我们可以初始化硬件,比如RAM和系统的I/O设备等。同时它还可以装载写在Flash上的不同内核,或者通过外部设备传输过一个内核并且装载运行它。

在现阶段的开发板上,很多都采用了这种方式通过串口或者网口加载Pc机上编译好的uClinux内核或者根文件系统。

除此以外,一个好的bootloader还能够保证内核影像的正确执行,防止新传输来的内核影像不完整等等。一般情况下bootloader 都是固定的烧写在Flash上面并且一般采用锁定的方法防止被擦除。 目前有很多成数的bootloader 可以在互联网上自由下载。它们支持各种开发板上的uClinux的开发。比较著名的有CoLilo, My Right Boot (MRB), PPCboot and Motorola dBUG。它们功能强大并且可以很方面的移植到你自己的开发板上。

4,uClinux内核的块设备驱动

对于uClinux 的根文件系统,目前有三种块设备的驱动可以选择它们分别是:

a) Blkmem 驱动

b) MTD 驱动

c) RAM disk 驱动

Blkmem 驱动是专门为uClinux 开发的一种块设备驱动。是uClinux系统中最为古老和通用块设备驱动。它原理相对简单但是配置比较复杂,需要根据你即的Flash的分区使用情况来修改代码。当然修改的结果是它可以对一些NOR型的Flash进行读写操作。不过目前支持的Flash类型不够多。如果新加入对一种Flash的支持需要作的工作量比较大。

Linux的MTD驱动是标准Linux的Flash驱动。它支持大量的设备,有足够的功能来定义Flash的分区,进行地址映射等等。使用MTD你可以在一个系统中使用不同类型的Flash。它可以将不同的Flash组合成一个线性的地址让你来使用。在标准的Linux

2.4内核中MTD有一系列的选相,你可以根据个人系统的需要来选择,定制。

另外一种选择就是RAM disk 驱动。在PC上它经常用于没有硬盘的Linux的启动过程。它和Flash没有直接的关系。不过当Flash上启动的是经过压缩的内核时。RAM disk 可以作为根文件系统。MTD 驱动提供了对Flash强大的支持,你通过它甚至可以在Flash上运行一个可以读写的真正的文件系统,比如JFFS2。而Blkmem驱动则望尘莫及。

5,uClinux的文件系统

在uClinux下根文件系统有集中选择。 ROMfs是最常用的一种。它的特点是紧凑,只读。它把所有的文件按照一个文件的次序组合成一定的次序。并且它可以让它的应用程序直接在FLAH里面运行(XIP)。这样以来就减少了运行时对RAM尺寸的要求。在目前基于AMR和ColdFire等CPU的uClinux开发中绝大多数使用这种文件系统作为根文件系统。

Cramfs是在Linux内核2.4版本以后出现的新的文件系统,它的特点是把只读的文件系统进行压缩。从而可以在Flash上存储更多的应用程序。不过因为压缩它不能本地执行应用程序,而必须解压到RAM中运行。要求比较多的RAM。

在一些系统中需要可以读写的根文件系统。在uClinux系统中利用MTD驱动,我们可以实现一些基于Flash的日志文件系统比如JFFS 或者 JFFS2。这个文件系统的优点在于它可以避免突然断电对系统存储的影响(在标准Linux中ETX2文件系统掉电会造成数据丢失)。同时因为它们是和为Flash设计它可以保证在Flash中实现读写。如果你使用RAM disk 那么ETX2 就成为首选的文件系统。因为它是标准Linux的文件系统。所以很多操作非常方面。不过缺点是ETX2文件系统不是为嵌入式操作系统所作,所以并没有考虑存储空间的问题。由于RAM

disk的特性你在该文件系统上所作的改动下次启动后将不会再有。

当然Linux支持很多文件系统,你可以根据你的喜好随意选择。不过以上说说的是uClinux系统中最常用的。

那么我们怎么在Flash上建立一个根文件系统呢?

通常的做法是先在开发机上(通常是PC)作好这个文件系统的镜像。然后通过烧写Flash的工具直接烧写到Flash中去。也可以通过阅读一些文件系统自带的工具来进行构建。这里不一一赘述。

6,uClinux 的Flash工具

在uClinux的源码包中带有一些对Flash操作的应用程序。当你采用MTD的时候这些工具变得非常有用,它们分别是:

erase -- 擦除Flash的某些扇区

eraseall -- 擦除整个Flash

lock -- 锁住Flash(写不进去)

unlock -- 解锁

-- 建立一个目录结构的JFFS2文件系统

2 – 建立一个目录结构的JFFS2文件系统的镜像

除此之外,还有一些更为复杂的程序是和其他应用相关的。比如和JTAG相关,Net相关等等。可以根据这个工具的说明来加以应用。

7,应用实例

现在我们看一个实例。首先说一下我们的硬件平台。这个平台是基于ARM940T核心的CPU+2M的AMD Flash + 4M SDRAM。在这个平台上我们运行uClinux 2.4 的内核,采用MTD驱动。因为我们不需要对Flash进行读写操作,所以选择了ROMfs。这样使得开发和维护想对比较简单。AMD的Flash,

我所选用的是可启动型的。因为ARM的CPU在加电的时候从零地址开始运行。因此Flash的地址分配为从0X0 到0X1FFFFF。根据这个Flash的扇区大小,我们把整个Flash的分区如下:

2M Flash ---MTD 6

启动代码 (16K)MTD1

启动所需参数 (8K)MTD2

设备配置信息(8K)MTD3

备用空间(32K)MTD4

系统运行参数表(64K)MTD5

内核和根文件系统(1984K)MTD6

在内核的MTD驱动的选项中,我们根据所需要的分区信息对代码进行配置。运行的时候,MTD驱动会找到这个设备,并且按照以上我们的分区方案对Flash的地址进行分配。一些详细的信息和细节,在MTD驱动的代码部分有详细的描述。

完成了这个分区,我们就可以利用我们手头的工具,把我们事先做好的系统启动程序和内核,根文件系统写入Flash。

常用的方法有:

1)建立整个Flash的影像,使用烧录工具烧到Flash中

2)书写一个Bootloader,使用系统所带的外部接口将内核还有根文件系统传送到系统RAM中,然后写入Flash。常用的有通过串口和网口的。此类的程序有很多比如netflash等等,具体的用法请参照各命令的手册。

运行完这些,uClinux系统已经在我们的开发板上安装好了。