IO软件的设计与实现
1、引言
随着嵌入式系统应用领域的不断扩大,系统复杂性也在不断提高。闪存作为广泛使用的嵌入式存储设备,其管理技术和访问方式经历了一个由开发员直接控制到由操作系统的I/O软件间接控制的过程。然而目前现有的这些闪存管理方案都不能提供一种方便、统一且移植性好的I/O软件接口,增加了嵌入式产品的研发周期。因此,本文旨在针对一般的嵌入式应用,设计并实现一种更合理的闪存I/O软件。该软件遵循策略与机制分离的原则,采用分层的体系结构,能够更好得适应底层硬件的变化,可大大提高代码的可移植性。
2、闪存设备管理技术的现状及存在的问题
闪存设备不同于一般的非易失性存储设备,它有很多特殊的存取特性,其中最主要的在执行写入操作之前必须先擦除目标单元的内容[1]。因此,闪存设备的管理最基本也应该包含对读、写操作以及擦除操作的控制。
而对于那些配置了操作系统的复杂嵌入式系统(例如嵌入式Linux系统),闪存设备的管理则主要是通过操作系统中的I/O软件来实现。该I/O软件遵循Linux通用设备的管理方法[3],实现了字符访问与块访问的接口,为应用程序访问闪存提供了一个通用接口。但问题是,该方案在设计软件结构时没有很好地遵循策略与机制分离的原则,从而使得软件结构的层次不够分明,模块化程度不高。
另外,在嵌入式Linux系统中还有一种与使用闪存相关的技术,即Ramdisk[4]技术。准确地说,该技术不涉及闪存的管理问题,而是一种通过将计算机的 RAM 用作设备来创建和挂装文件系统的机制。本文在此提及该技术的原因是它能够帮助只含闪存和RAM的嵌入式系统使用文件系统(主要指ext2fs类型),并且该技术的存在大大降低了嵌入式系统对闪存的访问操作,从而简化了系统对闪存的管理。但是,由于Ramdisk技术不能直接在闪存上使用文件系统,使得修改后的数据不能立刻保存到闪存中,所以在系统异常时容易造成数据的丢失。
接着闪存设备层代码在低层软件分区的基础上,用字符设备和块设备两种方式来使用闪存原始设备。具体说,该层主要实现字符设备与块设备的通用接口例程,即文件操作的通用方法,如打开、关闭、定位、读、写等。
最后,闪存设备节点层是为了方便应用程序以文件形式访问闪存设备而创建的设备节点。它的实现并不
需要软件代码。
4、闪存设备I/O软件的实现
嵌入式开发一般都采用主机与目标板相结合的交叉开发方式。因此我们的目标板采用的是Motorola公司基于PowerPC860T处理器的一个网络通信设备开发板(以下简称为NE860)。NE860板上配备有4M NOR型闪存和16M RAM作为存储器,其中闪存采用的是两片Intel TE28F160B3T的芯片。主机是一台运行Redhat 7.2 的PC机,该主机上还安装有Montavista 嵌入式Linux(以下简称MVL)作为实现闪存I/O软件的载体。具体实现过程如下:
(1) 硬件驱动层
由于NOR型闪存芯片的接口不同与一般基于端口的外部设备,不能够被清晰地划分为几个不同用途的端口寄存器;该接口只包括了几条控制信号线,一组数据线和一组地址线。这样一来,闪存的数据读写操作以及命令写入和状态查询操作都需要在同一组数据线上进行。同时由于完备的地址线能够让系统对芯片内的每个字节进行寻址,于是闪存的擦除、写入等基本操作就可以通过向特定地址写入特定命令序列[6]的方式来实现的。因此我们的系统在遵循各种操作的特定指令序列[6]基础上,结合特定芯片的物理信息(保存在专用数据结构struct cfi_private中)实现了闪存的读、写、擦除和同步操作。
(2)原始设备层
原始设备层的主要功能是在硬件基础上把闪存芯片抽象为设备。为了实现这一目标,系统首先要把所有的闪存芯片抽象为一个闪存主原始设备,然后再根据用户的分区划分要求(通过管理配置模块获得)把主原始设备从软件上划分为多个分区设备。这样一来,分区设备的大部分参数信息实际上都来自于主原始设备,并且分区设备的操作函数也都来自于主原始设备的操作函数。而这些操作的实现是通过调用底层的基本操作完成的。
(3)设备层
闪存设备层主要用来实现字符设备与块设备的通用接口例程,其中字符设备的各种操作都比较容易实现。这里我们着重介绍一下块设备的实现。在Linux中,由于块设备的读写请求都是基于扇区(512字节)的,而闪存设备却不存在物理上的扇区结构,只有擦出块的概念。况且在通常情况下擦除块的尺寸都小于512字节,这样一来就存在一个如何把基于扇区的读写操作映射到适当的擦除块上的问题。由于块设备主要是为了支持在闪存上创建文件系统,所以该问题的解决我们就借用了JFFS文件系统中有关的设计思想(由于篇幅所限这里不详述)。
5、系统测试及数据分析
(1)闪存I/O软件可移植性的验证
从理论上讲,只有硬件设备驱动层的一部分代码是与设备相关的,而原始设备层和设备层代码都是设备无关的。于是,我们得出如下(表1)的统计结果。在新的I/O软件实现方案下,闪存设备相关代码为35KB,占总代码量的24.1%;设备无关代码为110KB,占总代码量的75.9%。由此可见,我们的实现方案具有很好的移植性,能够有效地提高嵌入式产品的开发速度和质量。
![](http://www.gkong.com/Editor/UploadFiles/learns03/2012113014490651.jpg)
? (2)闪存I/O软件有效性的验证
I/O软件的一个重要性能指标是设备的数据吞吐率。当应用程序访问闪存设备文件时,由于每次读/写请求的数据度不同,使得设备的瞬时吞吐率也不同。由于我们的I/O系统实现了闪存设备的两种管理方式:字符设备和块设备,因此下面我们首先针对字符设备方式测试它的读/写吞吐率(见图2 和图3)。
![字符设备读吞吐率](http://www.gkong.com/Editor/UploadFiles/learns03/2012113014491194.jpg)
通过分析图2、图3的数据我们发现,当系统从闪存设备中读取或写入小块数据时,吞吐率会随着请求数据长度的增加而增大;但是当请求数据长度超过某一临界值时,读/写吞吐率近似都稳定在一个固定值上。
为了进一步验证上述规律,我们又按照33%的写请求和67%的读请求比例,对各种请求数据长度进行了10次读/写混合操作测试,其结果如图4所示。由此可看出,在请求数据长度大于512KB之后,读写混合的数据吞吐率稳定在3.59MB/S上,这一结果与图2和图3所示结果完全一致。并且该吞吐率变化规律符合常见嵌入式应用中闪存的读、写特性.
文章版权归西部工控xbgk所有,未经许可不得转载。