Eboot中应用NandFlash
注:本文nand flash 是基于K9F1G08U0B ? K9F1G08U0B的阵列结构图如下 ? 图1 Nand flash存储操作特点: 以页为单位进行读写,以block为单位进行擦除 ? 我们基于usb来download镜像的eboot来学习nandflash的应用,download的菜单一般如下所示: ? 图2 基于usb来download内核映像的步骤是:F -> 9 -> U,那么我们先来看F对应的功能 ? 1.?????? 格式化nandflash ? 1.1?? ECC校验 ? nandflash的每一页有两区:main区和spare区,main区用于存储正常的数据,spare区用于存储其他附加信息,其中就包括ECC校验码。当我们在写入数据的时候,我们就计算这一页数据的ECC校验码,然后把校验码存储到spare区的特定位置中,在下次读取这一页数据的时候,同样我们也计算ECC校验码,然后与spare区中的ECC校验码比较,如果一致则说明读取的数据正确,如果不一致则不正确。ECC的算法较为复杂,好在s3c2440能够硬件产生ECC校验码,这样就省去了不少的麻烦事。s3c2443即可以产生main区的ECC校验码,也可以产生spare区的ECC校验码。因为K9F1G08U0B是8位IO口,因此s3c2443共产生4个字节的main区ECC码和2个字节的spare区ECC码。在这里我们规定,在每一页的spare区的第0个地址到第3个地址存储main区ECC,第4个地址和第5个地址存储spare区ECC。产生ECC校验码的过程为:在读取或写入哪个区的数据之前,先解锁该区的ECC,以便产生该区的ECC。在读取或写入完数据之后,再锁定该区的ECC,这样系统就会把产生的ECC码保存到相应的寄存器中。main区的ECC保存到NFMECC0/1中(因为K9F1G08U0B是8位IO口,因此这里只用到了NFMECC0),spare区的ECC保存到NFSECC中。对于读操作来说,我们还要继续读取spare区的相应地址内容,已得到上次写操作时所存储的main区和spare区的ECC,并把这些数据分别放入NFMECCD0/1和NFSECCD的相应位置中。最后我们就可以通过读取NFESTAT0/1(因为K9F1G08U0B是8位IO口,因此这里只用到了NFESTAT0)中的低4位来判断读取的数据是否正确,其中第0位和第1位为main区指示错误,第2位和第3位为spare区指示错误。 ? 1.2 写sector的SectorInfo结构数据到spare field中。 对应于代码的实现部分如下所示: ? 图3 下面我们来看看这部分是如何格式化nand flash的,先看结构体SectorInfo的定义: typedef struct _SectorInfo { ??? DWORD dwReserved1;???? 2???????? // Reserved - used by FAL,为FAL保留的字节 ??? BYTE? bOEMReserved;???? 3??????? // For use by OEM,为OEM保留的字节 ??? BYTE? bBadBlock;? ?????? 1???? // Indicates if block is BAD,坏块标识 ??? WORD? wReserved2;???? 4????????? // Reserved - used by FAL,为FAL保留的字节 ??? }SectorInfo,*PSectorInfo; 对这个结构体的初始化代码如下: ? 图4 我们知道nandflash主要以page(页)为单位进行读写,以block(块)为单位进行擦除。每一页中又分为main区和spare区,main区用于正常数据的存储,spare区用于存储一些附加信息,如块好坏的标记、块的逻辑地址、页内数据的ECC校验和等。K9F1G08U0B中关于一页中main field和spare field的结构如下: ? 图5 下面接下来通过调用函数来把第0到第3个block标识为只读与保留的坏块,如下代码如下: ? ? 图6 这里主要是通过调用函数FMD_WriteSector来实现的,这个函数会调用FMD_LB_WriteSector() 主要部分如下所示: ? 图7 下面就来看看NAND_LB_WriteSectorInfo的函数体吧 ? 图8 下面合适接着看NAND_LB_WriteSectorInfo函数的后部分 ? 图9 下图是大页面的nandflash一页的结构图: ? ? 10 下图是K9F1G08U0B编程和读状态的操作时序图 ? 图11 ? 1.3?? 调用函数FMD_GetBlockStatus来获取存放eboot之后的所有的blcok的状态 ? 该函数获得nandflash中某一个block的状态。参数为nandflash的block地址。由于nandflash中可能有坏块,所以针对nandflash,这个函数首先会检查当前块是否是坏块,这个一般通过读取当前block的第0个page和第1个page的带外数据。对于小page nandflash一般是读取第5个byte,对于大page nandflash一般读取第0个byte,如果不为0xff表示该块是坏块。当然,至于具体该读哪个byte,最好还是看一下所用nandflash的datasheet,确认一下,不同的厂家可能有所不同。如果发现该块是坏块,应该返回BLOCK_STATUS_BAD。如果不是坏块,需要读取这个块的起始扇区的扇区信息。如果读该扇区信息出错,应该返回BLOCK_STATUS_UNKNOWN,否则,判断独到的信息,返回相应结果。 ? 具体是如何实现的呢,我们先来看函数的调用关系: FMD_GetBlockStatus() -> FMD_LB_GetBlockStatus() -> FMD_LB_ReadSector() -> NAND_LB_ReadSectorInfo(),主要是通过NAND_LB_ReadSectorInfo函数来实现的,下面就来看看这个函数的内容: ? 图12 下图是读操作的时序图中的一部分: ? 图13 接着看NAND_LB_ReadSectorInfo函数的后半部分的实现: ? 图14 下面接着看ECC_CorrectData函数的实现 ? 图15 下面我们回到FMD_LB_GetBlockStatus函数中来 ? 图16 ? 1.4?? 擦除eboot之后的非坏块 ? 图17 下图是判读K9F1G08U0B某一块为坏块的根据和流程图 ? 图18 下面来看看是如何擦除块的,函数的调用关系是:FMD_EraseBlock() -> FMD_LB_EraseBlock(),在看FMD_LB_EraseBlock函数之前,先来看看K9F1G08U0B对擦除块的操作时序图 ? 图19 擦除是以块为单位进行的,因此在写地址周期是,只需写两个行周期,在擦除结束前还要判断是否擦除操作成功,FMD_LB_EraseBlock函数体如下: ? 图20 到此在下载NK.bin之前的格式化动作已经完成。 ? 2. 在nandflash上建立BINFS分区,通过USB下载的NK.bin会保存在这个分区中。 代码入下图所示: ? 图21 这部分的内容见我的另一篇博文: http://blog.csdn.net/LoongEmbedded/archive/2010/11/02/5981033.aspx ? 3.下载NK.bin 至于如何下载可以参考我的博文:WINCE6.0+S3C2443的启动过程系列博文 http://blog.csdn.net/LoongEmbedded/archive/2010/11/02/5981033.aspx ? ? 一些概念说明: ? FAL及FMD做基本定义的說明如下: ? FMD(FLASH Media Driver)可针对特定厂商的Flash作Driven、Read、Write、Erase等动作,实际上去对Flash做读写的操作。 ? FAL(FLASH Abstraction Layer):File System对Flash读写,必須透过此层操作。而此层则再更加FMD所提供的Interface再对Flash做读写。 ? NFSECC:Whenever data is read or written,the spare area ECC module generates ECC parity code on register ? NFSECCD is for ECC in the spare area (Usually,the user will write the ECC value generated from main data area to Spare area,which value will be the same as NFMECC0/1) and which is generated from the main data area. ? NFSECCD(nandflash的spare区ECC寄存器),NFMECCD0/1(nandflash的main区ECC寄存器),NFSECC(nandflash用于IO的ECC寄存器)。 ? 参考链接: http://blog.csdn.net/renpine/archive/2009/09/20/4572347.aspx 坏块http://apps.hi.baidu.com/share/detail/15657923 s3c2440对nandflash的操作(转载)http://www.360doc.com/showWeb/0/0/70026701.aspx 转自:LoongEmbedded的博客http://blog.csdn.net/loongembedded/article/details/6015302 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |