姓名:陈方园 学号:19020100239 学院:电子工程学院
转自:
https://max.book118.com/html/2021/0122/6011000144003053.shtm
【嵌牛导读】嵌入式Linux开发的一大挑战性源自大多数嵌入式系统的物理资源非常有限。虽然你的台式电脑会拥有酷睿2双核处理器和500 GB大小的硬盘,但很难找到拥有如此巨大硬盘容量的嵌入式系统。多数情况下,硬盘通常被更小和更便宜的非易失性存储设备所取代。硬盘不仅笨重,包含旋转部件,对物理震动敏感,并且要求提供多种供电电压,因此并不适合用在许多嵌入式系统中。
【嵌牛鼻子】闪存
【嵌牛提问】什么是闪存?其类型存储方式为何?
【嵌牛正文】
2.3.1 闪存
几乎所有人都对消费电子设备,比如数码相机和PDA(这两者都是很好的嵌入式系统的例子)中广泛使用的Compact Flash卡和SD卡很熟悉。这些基于闪存技术的模块可以看做是固态硬盘,它们能够在很小的空间内存储许多兆甚至几吉字节的数据。它们内部没有活动的部件,相对坚固,只需一种供电电压。
生产闪存的厂家有好几家。闪存的类型多种多样,电气规格、物理封装形式以及容量各有不同。只拥有小到4MB或8MB非易失性存储容量的嵌入式系统并不罕见。嵌入式Linux系统对存储容量的典型需求是16MB~256MB。越来越多的嵌入式Linux系统拥有数吉字节的非易失性存储空间。
闪存可以在软件的控制下写入和擦除数据。采用旋转硬盘驱动器技术的普通硬盘仍然是最快的可写入存储媒介。虽然和普通硬盘相比,闪存的写入和擦除仍然相当慢,但与以前相比,其写入和擦除速度已经有了显著提高。了解硬盘驱动器和闪存技术的根本区别才能正确地使用相应技术。
闪存的存储空间被分割成相对较大的可擦除单元,称为擦除块(erase block)。闪存的一个显著特征就是闪存中的数据写入和擦除的方式。在典型的NOR型[7]闪存芯片中,数据可以在软件的控制下,使用直接向某个存储单元地址写入的简单方法将其从二进制1改为二进制0。然而,要将数据从0改回1,则要擦除整个擦除块,,在擦除时需要向闪存芯片写入一串特别的控制指令序列。
典型的NOR型闪存包含多个擦除块。例如,一个4MB容量的闪存芯片可能包含64个擦除块,每块大小为64KB。市面上也有擦除块大小不一致的闪存,以便灵活存放数据。这种闪存常常被称为引导块(boot block)或引导扇区(boot sector)闪存。通常,引导加载程序存储在较小的块中,内核和其他必要的数据则存放在更大的块中。图2-3说明了一个典型的顶部引导(top boot)闪存芯片的块大小布局。
为了修改存储在闪存阵列中的数据,必须完全擦除待修改数据所在的块。即使只修改某个块中的一个字节,都必须擦除并重新写入整个块[8]。相比于传统硬盘的扇区,闪存的块大小相对较大。相对而言,一个典型的高性能硬盘的可写扇区大小为512 B或1024 B。结果显而易见:更新闪存中的数据所耗费的写入时间会是硬盘驱动器的很多倍,部分原因就是每次更新数据时都有相对大量的数据需要被擦除和写回。在最坏的情况下,一个写周期会耗费几秒钟的时间。
关于闪存,另一个需要考虑的限制是存储单元的写寿命(write lifetime)。NOR型闪存存储单元的可写入次数是有限制的,超出次数限制后写入就会失败。虽然这个次数的数值比较大(典型的写入次数限制是每块100 000次),但不难想象一个设计很差的闪存存储算法(甚至是一个软件故障)会迅速毁坏闪存设备。显然,应该避免配置你的系统日志输出到闪存。
2.3.2 NAND型闪存
NAND型闪存使用一种相对较新的闪存技术。当NAND型闪存投放市场时,前一节介绍的传统闪存就被称为了NOR型闪存。它们之间的区别与闪存存储单元的内部架构有关。NAND型闪存设备通过提供更小的块尺寸改进了传统(NOR型)闪存的一些限制,它可以更快更有效地进行写操作,同时大大提高了闪存阵列的使用效率。
NOR型闪存为微处理器提供的接口方式与很多微处理器外围设备的做法类似。也就是说,它们有并行的数据和地址总线,直接[9]连接到微处理器的数据/地址总线上。闪存阵列的每个字节或字(word)可以随机寻址。相反,NAND型闪存设备是通过复杂的接口串行访问的,而且这些接口因厂商而异。NAND型闪存设备的操作模式更类似于传统的硬盘驱动器加上附带的控制器。数据是以串行突发(burst)方式访问的,每次突发访问的数据量远远小于NAND型闪存的块大小。相比于NOR型闪存,虽然NAND型闪存的写入时间要少很多,但其写寿命却比NOR型闪存高出一个数量级。
总的来说,NOR型闪存可以被微处理器直接访问,甚至于代码可以直接在NOR型闪存中执行。(然而,因为性能方面的原因,很少有人这样做,除非系统资源极其匮乏。)实际上,很多处理器都不能像对待DRAM一样缓存(cache)访问闪存的指令。这进一步降低了代码的执行速度。相反,NAND型闪存更适合于以文件系统的格式大容量存储数据,而不是撇开文件系统,直接存储二进制可执行代码和数据。
2.3.3 闪存的用途
有多种闪存布局和使用方法可供嵌入式系统的设计者选择。在最简单的系统中,资源没有过度受限,可以将原始的二进制数据(可能是压缩过的)存储在闪存设备中。系统引导时,存储在闪存中的文件系统镜像被读入Linux内存磁盘(ramdisk)块设备中。这个块设备由Linux挂载为一个文件系统,并且只能从内存中访问。当闪存中的数据几乎不需要更新时,这种方式通常是很好的选择。相比于内存磁盘的容量,需要更新的数据量是很少的。但是,当系统重启或断电时,对内存磁盘中文件的修改会丢失,务必牢记这一点。
图2-4说明了一个简单嵌入式系统中的典型闪存组织结构。在这个系统中,动态数据对非易失性存储的需求很少且更新不频繁。
引导加载程序通常存放在闪存阵列的顶部或底部。引导加载程序之后的存储空间被分配给Linux内核和内存磁盘文件系统镜像[10],这个镜像中包含了根文件系统。一般来说,Linux内核和ramdisk文件系统镜像都被压缩过,并由引导加载程序在系统引导时解压。 可以在闪存中专门开辟一小块区域,或者使用其他类型的非易失性存储设备[11]来存放那些重启或掉电后仍需保留的动态数据。对于需要保存配置数据的嵌入式系统,这种方式很常见。例如,针对消费者市场的无线接入点设备可能采用这种方式。
2.3.4 闪存文件系统
刚才描述的简单闪存布局策略有局限性,但可以通过使用闪存文件系统来克服。闪存文件系统以类似于硬盘驱动器组织数据的方式来管理闪存设备中的数据。早期针对闪存设备的文件系统包含简单的块设备层,这个块设备层模拟了普通硬盘驱动器的扇区布局,扇区大小为512B。这些简单的模拟层允许以文件格式而不是无格式的大容量存储方式来访问数据,但是它们有一些性能上的局限。
对闪存文件系统的一个主要改进就是引入了耗损均衡(wear leveling)算法。如前所述,闪存块的写寿命是有限的。耗损均衡算法用来将写操作均匀分布到闪存的各个物理擦除块上,以延长闪存芯片的寿命。
闪存架构带来的另一个限制是系统掉电或意外关机后存在数据丢失的风险。闪存的块尺寸相对较大,而写入的文件的平均大小相对于块尺寸通常小很多。从前面的内容我们知道闪存块必须一次写入一整块。因此,为了写入一个8KB的小文件,必须擦除和重写整个闪存块,而这个块的大小可能是64KB或128KB;在最坏的情况下,这个写入会花费几秒钟才能完成。这极大增加了系统掉电后丢失数据的风险。
目前比较受欢迎的一种闪存文件系统是JFFS2,或称为第二代日志闪存文件系统最新的JFFS2文件系统的最重要改进包括完善耗损均衡、压缩和解压缩(将更多的数据挤进有限的闪存空间),以及对Linux硬连接(hard link)的支持。