基于mtd的nand驱动开发本科学位论文.docx

上传人:b****4 文档编号:24906598 上传时间:2023-06-02 格式:DOCX 页数:61 大小:124.43KB
下载 相关 举报
基于mtd的nand驱动开发本科学位论文.docx_第1页
第1页 / 共61页
基于mtd的nand驱动开发本科学位论文.docx_第2页
第2页 / 共61页
基于mtd的nand驱动开发本科学位论文.docx_第3页
第3页 / 共61页
基于mtd的nand驱动开发本科学位论文.docx_第4页
第4页 / 共61页
基于mtd的nand驱动开发本科学位论文.docx_第5页
第5页 / 共61页
点击查看更多>>
下载资源
资源描述

基于mtd的nand驱动开发本科学位论文.docx

《基于mtd的nand驱动开发本科学位论文.docx》由会员分享,可在线阅读,更多相关《基于mtd的nand驱动开发本科学位论文.docx(61页珍藏版)》请在冰豆网上搜索。

基于mtd的nand驱动开发本科学位论文.docx

基于mtd的nand驱动开发本科学位论文

基于MTD的NAND驱动开发

说明

 

大约用了两个礼拜不到的时间为公司的IPcamera系统写了基于MTD的NAND驱动(linux-2.6.22.10内核),目前已可以在该驱动的支持下跑cramfs和jffs2文件系统,另外,该驱动也可以同时支持smallpage(每页512Byte)和bigpage(每页2048Byte)两种NAND芯片。

在此整理一下与NAND驱动相关的概念,结构体,驱动框架和流程,同时分析一下基于MTD的NAND驱动的部分函数,尤其是其中的nand_scan()函数。

(涉及到具体NAND芯片时,若不做说明,将以smallpage的NAND芯片为例。

 

注:

个人理解,有误难免!

——笔者:

曹荣荣

 

 

MTD驱动程序是专门针对嵌入式Linux的一种驱动程序,相对于常规块设备驱动程序(比如PC中的IDE硬盘)而言,MTD驱动程序能更好的支持和管理闪存设备,因为它本身就是专为闪存设备而设计的。

具体地讲,基于MTD的FLASH驱动,承上可以很好地支持cramfs,jffs2和yaffs等文件系统,启下也能对FLASH的擦除,读写,FLASH坏块以及损耗平衡进行很好的管理。

所谓损耗平衡,是指对NAND的擦写不能总是集中在某一个或某几个block中,这是由NAND芯片有限的擦写次数的特性决定的。

总之,在现阶段,要为FLASH设备开发Linux下的驱动程序,那么基于MTD的开发将几乎是省时又省力的唯一选择!

 

一、NAND和NOR的区别

 

Google“NandFlash和NorFlash的区别”。

 

简单点说,主要的区别就是:

 

1、 NAND比NOR便宜;NAND的容量比NOR大(指相同成本);NAND的擦写次数是NOR的十倍;NAND的擦除和写入速度比NOR快,读取速度比NOR稍慢;

 

2、 NAND和NOR的读都可以以字节为单位,但NAND的写以page为单位,而NOR可以随机写每一个字节。

NAND和NOR的擦除都以block为单位,但一般NAND的block比NOR的block小。

另外,不管是NAND还是NOR,在写入前,都必须先进行擦除操作,但是NOR在擦除前要先写0;

 

3、 NAND不能在片内运行程序,而NOR可以。

但目前很多CPU都可以在上电时,以硬件的方式先将NAND的第一个block中的内容(一般是程序代码,且也许不足一个block,如2KB大小)自动copy到ram中,然后再运行,因此只要CPU支持,NAND也可以当成启动设备;

 

4、 NAND和NOR都可能发生比特位反转(但NAND反转的几率远大于NOR),因此这两者都必须进行ECC操作;NAND可能会有坏块(出厂时厂家会对坏块做标记),在使用过程中也还有可能会出现新的坏块,因此NAND驱动必须对坏块进行管理。

 

二、内核树中基于MTD的NAND驱动代码的布局

 

在Linux内核中,MTD源代码放在linux-2.6.22.10/driver/mtd目录中,该目录中包含chips、devices、maps、nand、onenand和ubi六个子目录。

 

其中只有nand和onenand目录中的代码才与NAND驱动相关,不过nand目录中的代码比较通用,而onenand目录中的代码相对于nand中的代码而言则简化了很多,它是针对三星公司开发的另一类Flash芯片,即OneNANDFlash。

我尚未对OneNandFLASH有过研究,只是通过网上资料得知,OneNandFLASH克服了传统NANDFlash接口复杂的缺点,具有接口简单、读写速度快、容量大、寿命长、成本低等优点,因此应该是一种较常用NAND先进的FLASH吧,只是目前似乎普及率并不高,本文也将不做讨论。

 

因此,若只是开发基于MTD的NAND驱动程序,那么我们需要关注的代码就基本上全在linux-2.6.22.10/drivers/mtd/nand目录中了,而该目录中也不是所有的代码文件都与我们将要开发的NAND驱动有关,除了Makefile和Kconfig之外,其中真正与NAND驱动有关的代码文件只有6个,即:

 

1、 nand_base.c:

定义了NAND驱动中对NAND芯片最基本的操作函数和操作流程,如擦除、读写page、读写oob等。

当然这些函数都只是进行一些default的操作,若你的系统在对NAND操作时有一些特殊的动作,则需要在你自己的驱动代码中进行定义,然后Replace这些default的函数。

 

2、 nand_bbt.c:

定义了NAND驱动中与坏块管理有关的函数和结构体。

 

3、 nand_ids.c:

定义了两个全局类型的结构体:

structnand_flash_devnand_flash_ids[]和structnand_manufacturersnand_manuf_ids[]。

其中前者定义了一些NAND芯片的类型,后者定义了NAND芯片的几个厂商。

NAND芯片的ID至少包含两项内容:

厂商ID和厂商为自己的NAND芯片定义的芯片ID。

当NAND驱动被加载的时候,它会去读取具体NAND芯片的ID,然后根据读取的内容到上述定义的nand_manuf_ids[]和nand_flash_ids[]两个结构体中去查找,以此判断该NAND芯片是那个厂商的产品,以及该NAND芯片的类型。

若查找不到,则NAND驱动就会加载失败,因此在开发NAND驱动前必须事先将你的NAND芯片添加到这两个结构体中去(其实这两个结构体中已经定义了市场上绝大多数的NAND芯片,所以除非你的NAND芯片实在比较特殊,否则一般不需要额外添加)。

值得一提的是,nand_flash_ids[]中有三项属性比较重要,即pagesize、chipsize和erasesize,驱动就是依据这三项属性来决定对NAND芯片进行擦除,读写等操作时的大小的。

其中pagesize即NAND芯片的页大小,一般为256、512或2048;chipsize即NAND芯片的容量;erasesize即每次擦除操作的大小,通常就是NAND芯片的block大小。

 

4、 nand_ecc.c:

定义了NAND驱动中与softewareECC有关的函数和结构体,若你的系统支持hardwareECC,且不需要softwareECC,则该文件也不需理会。

 

5、 nandsim.c:

定义了Nokia开发的模拟NAND设备,默认是ToshibaNAND8MiB1,8V8-bit(根据ManufactureID),开发普通NAND驱动时不用理会。

 

6、 diskonchip.c:

定义了片上磁盘(DOC)相关的一些函数,开发普通NAND驱动时不用理会。

 

除了上述六个文件之外,nand目录中其他文件基本都是特定系统的NAND驱动程序例子,但本人看来真正有参考价值的只有cafe_nand.c和s3c2410.c两个,而其中又尤以cafe_nand.c更为详细,另外,nand目录中也似乎只有cafe_nand.c中的驱动程序在读写NAND芯片时用到了DMA操作。

 

综上所述,若要研究基于MTD的NAND驱动,其实所需阅读的代码量也不是很大。

 

另外,在动手写NAND驱动之前,也许需要读一下以下文档:

1、 LinuxMTD源代码分析:

该文档可以让我们对MTD有一个直观而又相对具体的认识,但它似乎主要是针对NORFLASH的,对于实际开发NAND驱动的帮助并不是很大。

2、 MTDNANDDriverProgrammingInterface:

http:

//www.aoc.nrao.edu/~tjuerges/ALMA/Kernel/mtdnand/

该文档中关于ECC的说明很有帮助。

3、 MTD的官方网站:

http:

//www.linux-mtd.infradead.org/

 

三、NAND相关原理

 

在我们开始NAND驱动编写之前,至少应该知道:

数据在NAND中是怎样存储的,以及以怎样的方式从NAND中读写数据时。

 

1、 NAND的存储结构和操作方式

 

这方面的资料可以从任意一种NAND的datasheet中得到,因为基本上每一种NAND的datasheet都会介绍NAND的组成结构和操作命令,而且事实上,大多数的NANDdatasheet都大同小异,所不同的大概只是该NAND芯片的容量大小和读写速度等基本特性。

 

这里以每页512字节的NANDFLASH为例简单说明一下:

每一块NAND芯片由n个block组成->每一个block由m个page组成->每一个page由256字节大小的column1(也称1sthalfpage)、256字节大小的column2(也称2ndhalfpage)和16字节大小的oob(out-of-band,也称sparearea)组成。

至于m和n的大小可以查看特定NAND的datasheet。

相应的,若给定NAND中的一个字节的地址,我们可以根据这个地址算出block地址(即第几个block)、page地址(即该block中的第几个page)和column地址(即1sthalfpage,或2ndhalfpage,或oob中的第几个字节)。

 

在擦除NAND时,必须每次至少擦除1个block;在写NAND时,必须每次写1个page(有些NAND也支持写不足一个page大小的数据);在读NAND时,分为三种情况(对应三种不同的NAND命令),即读column1、读column2和读oob,那么为什么要分这三种情况呢?

假如知道NAND怎样根据给定的地址确定它的存储单元,那么自然也就能明白原因了,其实也并不复杂,主要是因为给定地址中的A8并不在NAND的视野范围之内(也许表达并不准确)。

 

事实上,在写基于MTD的NAND驱动时,我们并不需要实现精确到读写某一个byte地址的函数(除了读oob之外),这是因为:

 

基于MTD的NAND驱动在读写NAND时,可以分两种情况,即:

(1)不进行ECC检测时,一次读写一整个page中的MAIN部分(也就是那真实存储数据的512字节);

(2)进行ECC检测时(不管是hardwareECC还是softwareECC),一次读写一整个page(包括16字节的oob部分)。

所以部分NAND所支持的写不足一个page大小数据的功能,对MTD来说是用不着的。

 

那么,如果只需要读写不足一个page大小的数据怎么办?

这是MTD更上层的部分需要处理的事。

也就是说,对于NAND驱动来说,它只会读写整整一个page的数据!

 

最后值得一提的是,NAND驱动有可能只去读oob部分,这是因为除了ECC信息之外,坏块信息也存储在oob之中,NAND驱动需要读取oob中描述坏块的那个字节(通常是每个block的第一个page的oob中的第六个字节)来判断该block是不是一个坏块。

所以,我们只有在读oob时,才需要实现精确到读某一个byte地址的函数。

 

由此,我们也可以额外知道一件事,那就是NAND驱动中用到的column地址只在读oob时才有用,而在其他情况下,column地址都为0。

 

2、 ECC相关的结构体

structnand_ecclayout{

         uint32_teccbytes;

         uint32_teccpos[64];

         uint32_toobavail;

         structnand_oobfreeoobfree[MTD_MAX_OOBFREE_ENTRIES];

};

这是用来定义ECC在oob中布局的一个结构体。

 

前面已经提及过,oob中主要存储两种信息:

坏块信息和ECC数据。

对与smallpage的NAND芯片来说,其中坏块信息占据1个字节(一般固定在第六个字节),ECC数据占据三个字节。

所以sturctnand_ecclayout这个结构体,也就是用来告诉那些与ECC操作无关的函数,Nand芯片的oob部分中,哪些字节是用来存储ECC的(即不可用作它用的),哪些字节是空闲的,即可用的。

 

其实之所以有这个结构体,主要是因为硬件ECC的缘故。

以写数据为例,在使用硬件ECC的情况下,那三个字节的ECC数据是由硬件计算得到,并且写到NAND芯片的oob中去的,同时也是由硬件决定写到oob的哪三个字节中去。

这些都是由硬件做的,而NAND驱动并不知道,所以就需要用这个结构体来告诉驱动了。

 

所以,在写NAND驱动时,就有可能需要对这个结构体进行赋值。

这里说“有可能”,是因为MTD对这个结构体有一个默认的赋值,假如这个赋值所定义的ECC位置与你的硬件一致的话,那就不必在你的驱动中手动赋值了。

其实对大多数硬件(这里所说的硬件,不是指NAND芯片,而是NAND控制器)来说,是不必手动赋值的,但也有许多例外。

 

值得一提的是,这个结构体不仅仅用来定义ECC布局,也可以用来将你的驱动在oob中需要额外用到的字节位置保护起来。

 

现在对structnand_ecclayout这个结构体进行一下说明。

 

uint32_teccbytes:

ECC的字节数,对于512B-per-page的NAND来说,eccbytes=3,如果你需要额外用到oob中的数据,那么也可以大于3.

uint32_teccpos[64]:

ECC数据在oob中的位置,这里之所以是个64字节的数组,是因为对于2048-per-page的NAND来说,它的oob有64个字节。

而对于512B-per-page的NAND来说,可以而且只可以定义它的前16个字节。

uint32_toobavail:

oob中可用的字节数,这个值不用赋值,MTD会根据其它三个变量自动计算得到。

structnand_oobfreeoobfree[MTD_MAX_OOBFREE_ENTRIES]:

显示定义空闲的oob字节。

 

四、基于MTD的NAND驱动架构

 

1、platform_device和platform_driver的定义和注册

 

对于我们的NANDdriver,以下是一个典型的例子:

 staticstructplatform_drivercaorr_nand_driver={

               .driver={

                                .name="caorr-nand",

                                .owner=THIS_MODULE,

                },

                .probe=caorr_nand_probe,

                .remove=caorr_nand_remove,

 };

 staticint__initcaorr_nand_init(void)

 {

                printk("CAORRNANDDriver,(c)2008-2009.\n");

                returnplatform_driver_register(&caorr_nand_driver);

 }

 staticvoid__exitcaorr_nand_exit(void)

 {

                platform_driver_unregister(&caorr_nand_driver);

 }

 module_init(caorr_nand_init);

 module_exit(caorr_nand_exit);

 

与大多数嵌入式Linux驱动一样,NAND驱动也是从module_init宏开始。

caorr_nand_init是驱动初始化函数,在此函数中注册platformdriver结构体,platformdriver结构体中自然需要定义probe和remove函数。

其实在大多数嵌入式Linux驱动中,这样的套路基本已经成了一个定式

 

至于module_init有什么作用,caorr_nand_probe又是何时调用的,以及这个driver是怎么和NAND设备联系起来的,就不再多说了,这里只提三点:

 

A、以上代码只是向内核注册了NAND的platform_driver,即caorr_nand_driver,我们当然还需要一个NAND的platform_device,要不然caorr_nand_driver的probe函数就永远不会被执行,因为没有device需要这个driver。

 

B、向Linux内核注册NAND的platform_device有两种方式:

其一是直接定义一个NAND的platform_device结构体,然后调用platform_device_register函数注册。

作为例子,我们可以这样定义NAND的platform_device结构体:

 structplatform_devicecaorr_nand_device={

         .name="caorr-nand",

         .id=-1,

         .num_resources=0,

          .resource=NULL,

          .dev={

              .platform_data=&caorr_platform_default_nand,

          }

 };

 platform_device_register(&caorr_nand_device);

其中num_resources和resource与具体的硬件相关,主要包括一些寄存器地址范围和中断的定义。

caorr_platform_default_nand待会儿再说。

需要注意的是,这个platform_device中name的值必须与platform_driver->driver->name的值完全一致,因为platform_bus_type的match函数是根据这两者的name值来进行匹配的。

其二是用platform_device_alloc函数动态分配一个platform_device,然后再用platform_device_add函数把这个platform_device加入到内核中去。

具体不再细说,Linux内核中有很多例子可以参考。

相对来说,第一种方式更加方便和直观一点,而第二种方式则更加灵活一点。

 

C、在加载NAND驱动时,我们还需要向MTDCore提供一个信息,那就是NAND的分区信息,caorr_platform_default_nand主要就是起这个作用,更加详细的容后再说。

 

2、MTD架构的简单描述

 

MTD(memorytechnologydevice存储技术设备)是用于访问memory设备(ROM、flash)的Linux的子系统。

MTD的主要目的是为了使新的memory设备的驱动更加简单,为此它在硬件和上层之间提供了一个抽象的接口。

MTD的所有源代码在/drivers/mtd子目录下。

MTD设备可分为四层(从设备节点直到底层硬件驱动),这四层从上到下依次是:

设备节点、MTD设备层、MTD原始设备层和硬件驱动层。

A、Flash硬件驱动层:

硬件驱动层负责驱动Flash硬件。

 

B、MTD原始设备:

原始设备层有两部分组成,一部分是MTD原始设备的通用代码,另一部分是各个特定的Flash的数据,例如分区。

用于描述MTD原始设备的数据结构是mtd_info,这其中定义了大量的关于MTD的数据和操作函数。

mtd_table(mtdcore.c)则是所有MTD原始设备的列表,mtd_part(mtd_part.c)是用于表示MTD原始设备分区的结构,其中包含了mtd_info,因为每一个分区都是被看成一个MTD原始设备加在mtd_table中的,mtd_part.mtd_info中的大部分数据都从该分区的主分区mtd_part->master中获得。

在drivers/mtd/maps/子目录下存放的是特定的flash的数据,每一个文件都描述了一块板子上的flash。

其中调用add_mtd_device()、del_mtd_device()建立/删除mtd_info结构并将其加入/删除mtd_table(或者调用add_mtd_partition()、del_mtd_partition()(mtdpart.c)建立/删除mtd_part结构并将mtd_part.mtd_info加入/删除mtd_table中)。

 

C、MTD设备层:

基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。

MTD字符设备的定义在mtdchar.c中实现,通过注册一系列fileoperation函数(lseek、open、close、read、write)。

MTD块设备则是定义了一个描述MTD块设备的结构mtdblk_dev,并声明了一个名为mtdblks的指针数组,这数组中的每一个mtdblk_dev和mtd_table中的每一个mtd_info一一对应。

 

D、设备节点:

通过mknod在/dev子目录下建立MTD字符设备节点(主设备号为90)和MTD块设备节点(主设备号为31),通过访问此设备节点即可访问MTD字符设备和块设备。

 

E、根文件系统:

在Bootloader中将JFFS(或JFFS2)的文件系统映像jffs.image(或jffs2.img)烧到flash的某一个分区中,在/arch/arm/mach-your/arch.c文件的your_fixup函数中将该分区作为根文件系统挂载。

 

F、文件系统:

内核启动后,通过mount命令可以将flash中的其余分区作为文件系统挂载到mountpoint上。

 

以上是从网上找到的一些资料,我只是断断续续地看过一些code,没有系统地研究过,所以这里只能讲一下MTD原始设备层与FLASH硬件驱动之间的交互。

 

一个MTD原始设备可以通过mtd_part分割成数个MTD原始设备注册进mtd_table,mtd_table中的每个MTD原始设备都可以被注册成一个MTD设备,有两个函数可以完成这个工作,即add_mtd_device函数和add_mtd_partitions函数。

 

其中add_mtd_device函数是把整个NAND FLASH注册进MTDCore,而add_mtd_partitions函数则是把NAND FLASH的各个分区分别注册进MTDCore。

 

add_mtd_partitions函数的原型是:

intadd_mtd_partitions(structmtd_info*master,

            consts

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 图表模板

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1