您的位置:首页 > 其它

WinCE中nandflash驱动开发介绍 +WinCE中地Flash分区和CheckSum+ NAND和NOR的比较

2010-09-28 19:00 375 查看

摘录下来,用来学习,呵呵


[b]文章一:

一. NAND和NOR的比较

NOR和NAND是现在市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM
和EEPROM一统天下的局面。紧接着,1989年,东芝公司发表了NAND flash结构,强调降低每比特的成本,更高的性能,并且象磁盘一样可以通
过接口轻松升级。但是经过了十多年之后,仍然有相当多的硬件工程师分不清NOR和NAND闪存。相"flash存储器"经常可以与相"NOR存储器"互换
使用。许多业内人士也搞不清楚NAND闪存技术相对于NOR技术的优越之处,因为大多数情况下闪存只是用来存储少量的代码,这时NOR闪存更适合一些。而
NAND则是高数据存储密度的理想解决方案。NOR的特点是芯片内执行(XIP, eXecute In Place),这样应用程序可以直接在
flash闪存内运行,不必再把代码读到系统RAM中。NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大
影响了它的性能。NAND结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快。应用NAND的困难在于flash的管理和需要特
殊的系统接口。

二.性能比较

flash闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。任何flash器件的写入操作只能在空或已擦除的单元内进行,所以
大多数情况下,在进行写入操作之前必须先执行擦除。NAND器件执行擦除操作是十分简单的,而NOR则要求在进行擦除前先要将目标块内所有的位都写为0。
由于擦除NOR器件时是以64~128KB的块进行的,执行一个写入/擦除操作的时间为5s,与此相反,擦除NAND器件是以8~32KB的块进行的,执
行相同的操作最多只需要4ms。执行擦除时块尺寸的不同进一步拉大了NOR和NADN之间的性能差距,统计表明,对于给定的一套写入操作(尤其是更新小文
件时),更多的擦除操作必须在基于NOR的单元中进行。这样,当选择存储解决方案时,设计师必须权衡以下的各项因素。

☆ NOR的读速度比NAND稍快一些;

☆ NAND的写入速度比NOR快很多;

☆ 大多数写入操作需要先进行擦除操作;

☆ NAND的擦除单元更小,相应的擦除电路更少。

三.接口差别

NOR flash带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每一个字节。NAND器件使用复杂的I/O口来串行地存
取数据,各个产品或厂商的方法可能各不相同。8个引脚用来传送控制、地址和数据信息。NAND读和写操作采用512字节的块,这一点有点像硬盘管理此类操
作,很自然地,基于NAND的存储器就可以取代硬盘或其他块设备。
[/b]



章二:WinCE中nandflash驱动开发介绍

先来谈一下flash,flash是一种非易失存储器,一般flash存储设备分为Nandflash和Norflash
。这两种
flash各有优缺点。在读写速度上,norflash的读速度快一些,nandflash的写速度会快一些。Nandflash的容量一般都比
Norflash大很多,而且相比价格比较便宜。但是Norflash支持XIP,而nandflash不支持,而且Nandflash可能有坏块。相关
的比较,网上很多文章都有介绍,这里就说这么多了。

  这里介绍nandflash驱动,在WinCE中,有专门针对flash存储设备驱动的支持,一般传统采用FAL+FMD的架构
。在WinCE
最新的版本中,也就是Windows CE6.0
R2中,还支持MDD+PDD的架构
。在FAL+FMD架构中,FAL层由微软来实现,我们需要实现FMD层的相关接口函数。在MDD+PDD的架构
中,MDD替换了原来架构中的FAL,而PDD相当于原来的FMD,只要实现PDD层就可以了。如果你的系统已经升级到WinCE6.0
R2,那么你应该可以在WINCE600PublicCOMMONOAKDRIVERS目录下面找到这两种架构驱动的源代码。
由于MDD+PDD的架构在WinCE6.0
R2中才有支持,本人也没有实现过。所以这里只介绍基于FAL+FMD架构下,nandflash驱动的开发,这也是目前大家都采用的开发flash驱动
的架构。

  如上面所说,我们需要实现FMD层的相关接口,下面来介绍一下各个接口函数:

  1. PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn,
PPCI_REG_INFO pRegOut):
这个是Flash设备的初始化函数。在WinCE启动的时候,要加载Flash驱动时,首先调用这个函数对flash设备进行初始化。如果你的系统中有
nandflash的controller,那么你需要在这里对你的nandflash
controller进行初始化
。如果没有的话,你需要针对你的硬件设计进行相关的片选,时序等进行配置。返回一个handle表示成功,这个
handle将被FMD_Deinit(..)函数用到,如果返回NULL表示失败。

2. BOOL FMD_Deinit(PVOID hFMD):
这个函数在nandflash驱动卸载的时候被调用,参数就是FMD_Init函数返回的Handle.一般在这个函数里面,你可以释放一些用到的资源,
然后关闭nandflash controller。

  3. BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE
pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors):
这个函数用于读nandflash的一个扇区。对于nandflash来说,分大page和小page,大page是2048个bytes一页,小
page是512个bytes一页。所以大page每个扇区有2048 bytes,小page每个扇区有512 bytes。

  startSectorAddr: nandflash物理扇区的起始地址,对于nandflash来说,就是nandflash中从哪个page开始。

  pSectorBuff:扇区数据buffer,从nandflash中读出的每一个扇区的数据都存放在这个buffer中。

  pSectorInfoBuff:扇区信息buffer,一般每个扇区的信息会被保存在nandflash的带外数据中,针对小page,带外
数据有16 bytes,大page有64 bytes。从nandflash的带外数据将该扇区的相关信息读出来,存放在这个buffer中。

  dwNumSectors:读取多少个扇区,对于nandflash来说相当于读取多少个page。

  4. BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE
pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors):
该函数用于写nandflash的一个扇区。参数和上面的FMD_ReadSector的参数意思一样,就不多说了。

  5. BOOL FMD_EraseBlock(BLOCK_ID blockID): 该函数用于擦出nandflash的一个block,参数为要擦除nandflash的block地址,也就是第几个block。

  6. DWORD FMD_GetBlockStatus(BLOCK_ID blockID):
该函数获得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,否则,判断独到的信息,返回相应结果。

 7. BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus):
该函数设置nandflash某个block的状态,第一个参数是nandflash的block地址,第二个是要设置的状态。在这个函数中,首先检查
dwStatus是不是BLOCK_STATUS_BAD,如果是就对nandflash作坏块标记,然后返回FALSE。如果不是,就将
dwStatus写到该block的第0个page的扇区info中。这个函数和上面的函数正好是相反的。

  8. BOOL FMD_GetInfo(PFlashInfo pFlashInfo): 该函数用于返回flash的信息。其中pFlashInfo是一个包含flash信息的结构。

  pFlashInfo->flashType:flash的类型,对于nandflash来说,应该是NAND。

  pFlashInfo->wDataBytesPerSector:一个扇区多少个bytes,对于大page是2048,对于小page是512。

  pFlashInfo->dwNumBlocks:flash中总共有多少个block,查一下所用的nandflash的datasheet就知道了。

  pFlashInfo->wSectorsPerBlock:每个block中包含多少个扇区。

  pFlashInfo->dwBytesPerBlock:每个block中包含多少个bytes。

  9. VOID FMD_PowerDown()和VOID FMD_PowerUp():
这两个函数用于电源管理。FMD_PowerDown()用于关闭flash设备电源,FMD_PowerUp()用于恢复flash设备电源。根据你所
用处理器和相关硬件环境,去实现这两个函数。不实现也不会影响nandflash的使用。

  10. BOOL FMD_OEMIoControl(..):
就像很多的IOControl函数一样,根据不同的case,实现相应的功能。针对nandflash来说,这里面的case不一定都需要实现。事实上,
如果什么都没有实现,也不影响nandflash的使用。在WinCE的文档中,定义了一些需要实现的case,你可以实现,也可以不去实现。

  对于nandflash来说,实现上述函数就可以了。在nandflash出厂的时候,厂家已经对nandflash中的坏块进行了标记。所以
第一次对nandflash操作的时候,不要随便擦除nandflash,因为这样可能会把坏块标记擦掉,这样你就判断不出哪个块是坏块了。

  关于ECC校验,目前很多处理带有nandflash controller,而且nandflash
controller带有硬件ECC功能。如果没有硬件ECC,也可以使用软件ECC,软ECC的代码可以在
WINCE600PUBLICCOMMONOAKDRIVERSBLOCKMSFLASHFMDECC下找到。一般来说,ECC校验会对512个BYTE
产生3个字节的校验码,也就是说对小PAGE来说,每个PAGE有3个字节的ecc校验码;对于大PAGE来说,有12个字节。这些校验码应该在写扇区数
据的时候,被写在扇区的带外数据里面。当读扇区数据时,会先把数据读出来,然后根据这些数据计算ecc,再和读出来的ecc进行比较,如果一致,则表示正
确。

文章之三:WinCE中地Flash分区和CheckSum(转载C151151
)

最近在分析如何在WinCE运行时得到保存在FLASH的binfs分区中的image数据的完整性,积累了一些CheckSum和image数据结构,FLASH分区原理的经验点滴,分享一下,有些地方可能存在猜测的成分,仅供参考。

CheckSum是一种用于检查数据文件有没有发生变化的方法,对于一些重要的数据文件为了检查传输过程过程中有没有数据的损坏或丢失,常常会用到CheckSum算法。

WinCE中经常用到CheckSum的地方就是对即将烧写进Flash中的image文件进行校验,和烧写完对写入的数据进行完整性检查,一般这里的image有OSimage和UT的bin文件两种。

CheckSum的原理是把一个文件以二进制的方式打开,将里面所有的字节的值一个一个的累加起来,一直到最后一个字节,最后得到一个累加值,
它就是我们要的CheckSum的结果。从CheckSum的这个特性可知数据值为0的字节是不会影响到最终的结果,这种特性我认为也是CheckSum
的一个弱点,不能像MD5,SHA1等摘要算法一样基本上能反映出哪怕一个bit的改动,但是这个特性也给WinCE运行期间计算保存在FLASH上的
image数据文件的完整性带来了方便。

为了从Flash中得到正确的CheckSum值必须先了解image在Flash中的烧写方式,这包括了解image文件内部是怎么组织的,Flash的分区和块的分配是如何进行的。

先以Sumsung的FLASH为例来分析一下Flash的分区大体原则:

WinCE的Flash分区大体分为Nand
BootLoader(NBL)区,Binfs区和文件区,NBL区存放BootLoader和烧写Image的工具程序,Binfs分区存放MBR、
image的XIPKERNEL.bin、Chain.bin和NK.bin等OS的数据。文件区一般格式化为FAT分区让WinCE上层的磁盘和分区管
理程序管理。Flash的分区是由UT在烧入image的时候决定的,包括每个分区的起止块地址,分区的大小和类型等,Detail如下:

1)NBL区一般占10个块(128K/块)的大小,分区虽小但是却是最重要的部分,
保存着UT的三大模块:NBL1(bootloader),NBL2(IPL,Init Program Loader)和NBL3(Upgrade
Tools),其中NBL1和NBL2共同保存在FlASH的第一个block中,FLASH芯片在生产的时候厂商都会特别保障这些block的可靠性,
特别是保存了最开始bootloader代码和IPL的第一块。按经验来讲,NBL的三个模块加起来一共大约400多K,其占用的10块的
block=128K×10 byte的空间大部分是空余的,为了下面叙述方便,这里假设NBL3_END_BLCOK为NBL的最后的block编号。

2)Binfs分区紧接着BL分区,即
CE_START_BLOCK=NBL3_END_BLCOK+1,然后一般会将Binfs分区的第一个块存放MBR,MBR在这里仅仅是个标志,不像
PC的硬盘中的MBR主要用来保存分区表的信息和引导代码。所以Binfs分区中保存OS数据的起止block范围为CE_START_BLOCK+1到
CE_START_BLOCK+CE_MAX_BLOCK为止,我接触的项目中其大小一般为250个块左右,大约等于30Mbytes,WinCE的
image一般不会超过这个大小,如果需要可以在分区时加大它的大小。

3)Flash的文件分区就是将剩下的block模拟成为和硬盘,CF卡类似的块设备让WinCE加载成盘符使用。

现在回到正题:如何计算CheckSum。

1)UT的CheckSum计算

UT的bin文件是由
bootloader.bin(NBL1),IPL.bin(NBL2)和UpgradeTools.bin(NBL3)这三文件打成的一个封包,然后用
PC上的checksum工具计算出checksum值,我们的目的就是在WinCE起来后用AP能通过读Flash的NBL的三个分区并实时计算到这个
值。

UT的bin文件最后会被完整的烧写到NAND
Flash的编号为0到NBL3_END_BLCOK的block中(虽然会被分为三块烧,但是数据是完整的),具体占用多少block由bin文件的大
小决定,剩余的空间会以0填满。虽然不知道bin文件具体的结尾的位置,但是知道剩余空间填0的这个特性后,我们就可以直接调用NAND
Flash的驱动程序,而且可以使用轻量级的不带坏块管理的驱动代码直接去读0到NBL3_END_BLCOK的所有数据,然后把每个byte累加起来就
能得到CheckSum的值了。

2)IMG的CheckSum计算

大家都知道,如果定义了MultiXIP
region的话,WinCE的image用romimage编译出来会生成多个bin文件,这里假设我们在配置image的bib文件中定义了两个
region:XIPKernel和NK,那么在执行romimage ce.bib
之后我们会得到XIPKernel.bin,NK.bin,Chain.bin三个文件,最后调用makebinfs生成一个ceimgb.nb0的
image镜像文件,我们也会先用CheckSum工具对ceimgb.nb0进行运算得到其完整的CheckSum值。

烧写的过程和UT有两点不同:1)烧写内容选择上,UT的bin文件的所有数据会被烧入Flash,而IMG的镜像文件包含了一些不需要烧入的头信息,所
以可能导致烧入Flash的数据不完整;2)烧写使用的NAND
Flash的函数不一样,因为IMG烧写在FLASH中的位置位于普通的不受特殊保护的块区,所以要考虑到坏块的管理,所以在调用具体的读写接口的时候要
使用较高一层的代码,拿samsung的flash驱动PoketStoreII为例,烧写UT时用的读写函数为NF_ReadPage
,而烧写IMG镜像使用的时STL_Read/Write。

第一个不同点决定了我们如果要能计算得到正确的IMG的CheckSum值则必须将没有烧入到Flash中的ceimgb.nb0的头部数据烧写到为保存
IMG预留的并且没有被占用的Flash中,比如IMG预留空间的最后一块,块号为CE_START_BLOCK+CE_MAX_BLOCK。我们通过修
改烧写IMG的代码,在烧写完IMG的三个bin的数据后把从0x0到0x248(记不太清楚,大概)的数据写到块
CE_START_BLOCK+CE_MAX_BLOCK中。这样的话因为其他的空余空间被0填充,我们就可以调用STL_READ把从
CE_START_BLOCK+1(+1是为了略过MBR块)到CE_START_BLOCK+CE_MAX_BLOCK数据全读取出来并且累加得到最后
的CheckSum值。

三星的ONENAND的flash,其实就是拥有4K NOR的NAND
flash,我们的bootloader也分成三部份,第一部分bootloader主要是映射到0x00000000地址的一些跳转指令,这个部分会被
烧写到flash的前4K里面,然后三星的ONENAND会自动复制前4K的数据到一个类似NOR的物理模块中,这个NOR模块支持CPU的直接寻址;第
二部份叫IPL,它的功能是加载在NAND
flash中的image或UT,然后在加载后跳转到其RAM中的入口去执行,因为CPU的数据线和地址线在这个时候还只能直接访问NOR
flash,要访问NAND
flash的话必须要有NAND的接口驱动,所以在IPL的部分会有NAND的接口驱动的代码,这就导致IPL的代码一般有几十到上百K,我们的
flash一个块是128K,前两部分一共占了两个块;第三个部分是UT,就是一些通用的工具,比如烧image,烧bootloader,格式化
flash等常用的维护和image升级工具,这个部分的数据最多包括了很多的驱动程序,体积也很大,有300K的样子。
最后我们的三个部分的bootloader一共占据了flash的头10个块(block),128K*10,但这三个部分在三星的flash的分区中是
两个BML分区(三星的flash驱动PocetStoreII里面的概念,你就把它看成普通的磁盘分区好了),等下后面给的图示可以看到。
接下来的块会放置一个MBR,然后从11个块开始我们放置wince的image了,这个区是第三个BML分区,大小一般在40-200个块左右,因为
wince的image也就在4M-20M左右,这些划分分区的工作都是由上面提到的UT去做的,我也没有仔细看源代码,只是看到有BMLFormat之
类的函数,其参数就是后面看到的图示。如果是binfs那么这个区会放置两个模块:XIPKERNEL和NK,NK的区域会被binfs的驱动识别并且加
载成FAT分区的样子,可以在wince的资源管理器中看到的,具体是怎么被识别的还没有认真的搞懂。
大概算下来,前面所有的空间也就被占用20多M的样子,剩下的空间了你可以随意利用了,分区的方法还是调用三星的flash驱动中的BMLFormat和
STLformat,分区的参数定好了它们就会自动把分区建好,这部分的工作我们在BT中完成的。然后WinCE中仅仅需要将这些分区读出来并显示成磁盘
就行了,这个就和SD、HDD的驱动相似了,参考楼顶的介于“IF PokertStore”部分的注册表写法就行了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: