李洋 Michael Collier
摘要:随着全球电视数字广播的发展,数字电视已然成为市场的主流,集成模拟和数字电视信源解码和高端后处理能力的SOC核心处理器芯片具有广阔的市场前景。NAND Flash作为一种大容量的存储设备,满足了数字电视嵌入式系统对功耗、体积、成本及抗震性的苛刻要求,因而得到了广泛的应用。该论文主要探讨NAND Flash设备在数字电视中的工作原理以及基于Linux系统框架下的NAND Flash驱动程序的设计与实现。
关键词:数字电视;嵌入式系统;NAND Flash;驱动开发;Linux
中图分类号:TP316文献标识码:A文章编号:1009-3044(2012)01-0070-04
Design and Implementation of NAND Flash Driver in Digital TV
LI Yang,Michael Collier
(College of Information and Electrical Engineering, Shandong University of Science and Technology, Qingdao 266590, China)
Abstract: With the global development of digital broadcasting, digital television has become the mainstream of market, SOC processor chips integrated analog and digital TV source decoder and high capabilities of post-processing has broad market prospects. As a kind of large-capacity storage devices, NAND Flash meets the harsh requirements of power, size, cost and resistance to shock by embedded system, which has been widely used. This paper probes into the principles of the NAND Flash devices in DTV and the design and implementation of NAND Flash driver based on the framework of Linux.
Key words: digital TV; embedded system; NAND Flash; driver development; Linux
在嵌入式系统开发过程中,大容量存储器模块的设计已经成了不可或缺的重要方面。数字电视SOC芯片的NAND Flash支持由两部分组成[1]:NAND Flash控制器和NAND Flash存储芯片(H27U1G8F2B)。当要访问NAND Flash中的数据时,必须通过NAND Flash控制器发送命令才能完成,因此开发一个高效的NAND Flash控制器的驱动程序显得尤其重要。
1 NAND Flash工作原理
1.1 NAND Flash组织结构
该数字电视系统采用的NAND Flash型号为K9F1G08U0B,整个芯片分为1024个块(block),块是擦除的基本单位。每个块又分为64页(page),每个页包含2112字节的容量,其中2K字节用于存放数据,64个字节用来存放ECC校验信息及其他额外数据。用户数据存储区总容量为128MB,额外数据区总容量为4MB。NAND Flash以页为单位读写数据,而以块为单位擦除数据[2]。NAND Flash的存储结构如图1所示。
图1 Nand Flash存储结构图
1.2 NAND Flash寻址方式
按照上述的组织方式可以形成三类地址:
Column Address:列地址
Page Address:页地址
Block Address:块地址
表1 NAND Flash寻址方式表
A0 ~A11是列地址,共12位以保证能寻址到2112的页容量;A12~A17是页地址,共6位,保证能寻址到每个块中的64个页;A18~A27是块地址,共10位,用来寻址1024个块。由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。整个地址传递过程需要如下4步才能完成,称为4-step addressing。
第1步是传递列地址的前8位,也就是A[0:7],不需移位即可传递到I/O[0:7]上;第2步是将NAND_ADDR右移8位,将列地址的后4位A[8:11]传到I/O[0:7]上;第3步将NAND_ADDR再右移8位,将页地址跟块地址的前两位放到I/O[0:7]上;
第4步将NAND_ADDR继续右移8位,将块地址的最后8位放到I/O[0:7]上。
1.3 NAND Flash操作方式
1)擦除操作:
擦除操作时以块为单位进行的,擦除的启动指令为60h,随后的2个时钟周期是块地址。其中只有A17到A27是有效的,而A12到A17是可以忽略的。块地址之后是擦除确认指令D0h,用来开始内部的擦除操作。器件检测到擦除确认命令后,在/WE的上升沿启动内部写控制器,开始执行擦除和擦除校验。内部擦除操作完成后,应该检测写状态位(I/O 0),从而了解擦除操作是否成功完成。
2)写操作:
写入操作以页为单位。写入之前必须在擦除之后,否则写入时将会出现错误。页写入周期中包括以下步骤:
写入串行数据输入指令80h。然后写入4个字节的地址,最后串行写入数据。串行写入的数据最多为2112B。串行数据写入完成后,需要写入“页写入确认”指令10h,这条指令将初始化器件内部写入操作。10h写入之后,NAND Flash的内部写控制器将自动执行内部写入和校验中必要的算法和时序,系统可以通过检测R/B的输出,或读状态寄存器的状态位I/O 0来判断内部写入是否结束。
2 NAND Flash控制器
该NAND Flash控制器的读写擦除都是来自AMBA APB总线的请求。NAND Flash控制器的主要功能是把来自于AMBA APB总线的请求转化为标准的NAND Flash的命令序列。
因为NAND Flash的普通的数字读写都是以页为基础的,所以在NAND Flash控制器中使用了一个2K的数据缓存buffer。
对于数据路径的设计,因为NAND Flash的输入输出总线是一个命令形式的串行总线,地址和数据复用一条总线,所以设计中有必要引入一个多路器。另外,为了提高系统的可靠性,数据通路中引入了可选的ECC功能。
3 NAND Flash驱动程序设计
3.1 LINUX MTD驱动框架
NAND Flash作为boot loader、内核与文件系统的最佳载体,是嵌入式系统中必不可少的一个外设。Linux内核引入了MTD内存技术设备子系统来为NAND Flash、NOR Flash等存储设备提供统一的接口,从而使Flash驱动的设计大大简化。引入MTD框架后,NAND Flash设备驱动可以分为如图3几层。
图3 NAND Flash驱动程序分层结构
1)硬件驱动层
NAND Flash硬件驱动层负责FLASH硬件设备的读、写、擦除,Linux MTD设备的NAND Flash驱动则位于/driver/mtd/nand子目录下。
2) MTD原始设备层:
MTD原始设备层由两部分构成,一部分是MTD原始设备的通用代码(mtdcore.c、mtdpart.c),另一部分是各个特定的FLASH的数据,例如分区等。
3) MTD设备层:
基于MTD原始设备,Linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90),构成设备层。MTD字符设备在mtdchar.c实现,MTD块设备在mtdblock.c实现。
4)设备节点:
通过mknod命令在dev子目录下建立MTD字符设备节点(主设备号为90)和块设备节点(主设备号为31),用户通过访问该设备节点即可访问MTD字符设备和块设备。
3.2 NAND Flash平台驱动结构体
NAND Flash平台驱动结构体定义如下:
static struct platform_driver hiview_nand_driver = {.probe= hiview_nand_probe,
.remove= hiview_nand_remove,
.suspend = hiview_nand_suspend,.resume= hiview_nand_resume,.driver= {
.name = "hiview-nand",.owner = THIS_MODULE,},}; 1) hiview_nand_probe函数是驱动真正开始工作的部分,主要作用是初始化硬件、扫描设备、分配相应的资源等[3]。这部分代码根据具体的NAND Flash器件有关,必须自己去实现。
2) hiview_nand_remove函数与函数hiview_nand_probe相对应,主要完成NAND Flash的反初始化工作,包括释放系统资源及关闭硬件时钟等。
3) suspend和resume主要用于电源管理的相关操作,在没有电源管理的系统中放个空函数即可。
3.3 NAND Flash底层操作函数实现
通过平台驱动中的hiview_nand_probe函数注册之后,相应的函数都挂载完毕,初始化工作也已经做完,此时NAND Flash便可以工作了[4]。上层在访问NAND Flash的时候,通过MTD,一层一层向下调用,最终调用到底层的操作函数。
1) hiview_nand_write_buf和hiview_nand_read_buf:
这是两个最基本的操作函数,其功能就是往NAND Flash控制器的FIFO中读写数据。比如要读取一页的数据,那么在发送完相关的读命令和等待时间之后,就会调用到你底层的read_buf,去NAND Flash的FIFO中,一点点把所需要的数据读取出来,放到内存的缓存中去。写操作也是类似,将我们内存中的数据,写到NAND Flash的FIFO中去。
2) hiview_nand_devready:
NAND Flash的一些操作,比如读1页数据,写入1页数据,擦除1个块,都需要一定的时间,在命令发送完成后,就是硬件开始忙着工作的时候了,而硬件什么时候完成。这些操作,就是通过这个函数去检查状态的。具体实现都是去读硬件的一个状态寄存器,其中某一位是否是1,对应着是处于“就绪”还是“忙”状态。
3) hiview_nand_enable_hwecc:
在硬件支持的前提下,前面设置了硬件ECC的话,要实现这个函数,用于每次在读写操作前,通过设置对应的硬件寄存器的某些位,使得启用硬件ECC,这样在读写操作完成后,就可以去读取硬件校验产生出来的ECC数值了。
4) hiview_nand_correct_data:
当实际操作过程中,读取出来的数据所对应的硬件或软件计算出来的ECC和从OOB中读出来的ECC不一样的时候,就是说明数据有误了,就需要调用此函数去纠正错误[5]。对于常见的ECC算法来说,可以发现2位,纠正1位。更复杂的情况和更加注重数据安全的情况下,一般是需要另外实现更高效和检错和纠错能力更强的ECC算法。
4结束语
在驱动开发结束之后,将此驱动程序编译成模块,并整合到要移植的Linux系统中。经过系统的整机调试,此NAND Flash驱动功能完整,性能稳定,能够很好的支持YAFFS2文件系统,很好地满足了设计需求。参考文献:
[1]宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2008.
[2]汉泽西,吕飞.大容量NAND Flash在嵌入式系统中的应用[J].石油仪器,2006 (2):62-66
[3] Love R. Linux内核设计与实现[M].陈莉君,译.北京:机械工业出版社,2006.
[4]徐君明,陈振林,郭天杰.嵌入式硬件设计[M].北京:中国电力出版社,2007.
[5] Bovetd,Cesati M.深入理解LINUX内核[M].陈莉君,张琼生,张宏伟,译.3版.北京:中国电力出版社,2007.