zoukankan      html  css  js  c++  java
  • 基于WINCE6.0的nandflash驱动(基于K9F1G08U0B)

    *******************************LoongEmbedded********************************

    作者:LoongEmbedded

    时间:2010.11.26

    类别:WINCE驱动开发

    ********************************LoongEmbedded********************************

     

     

    1. 1.       nandflash驱动架构概述

     

    1

     

    Windows CE下的FLASH驱动分为两层,分别为FMD层和FAL(flash abstraction layer)FMDFlash Media Driver)属于底层,直接操作Flash硬件,比如读、写和擦除等,不同的Flash硬件则FMD_XXX接口实现函数各不相同,上层则是FAL (Flash Abstraction Layer)层,该层是由微软实现并提供的,是一个与硬件无关的层,可用于FAL层实现扇区的动态分配和坏块管理等。FAL层向应用层(如API)提供DSK接口。例如CreateFile中调用的设备即是调用该FAL层提供的接口。FMD层暴露FMD_XXXFAL层调用。 PB中的阐述如下:

    The flash media driver (FMD) is a device driver that performs the actual input and output of data to a flash memory device. An FMD contains all of the device-specific code necessary for read, write, and erase commands to the flash memory device. You can link the FMD with the flash abstraction layer (FAL) to create a block driver that a file system such as FAT can use. You can also link the FMD with a boot loader so that the boot loader can flash a run-time image.

     

    2.FALFMD对应的实现代码部分

    首先我们知道是由FAL+FMDàsmflash.dll的,下面看看FALFMD分别对应哪些代码:

     

    2.1 FAL

    FAL: \WINCE600\PRIVATE\WINCEOS\DRIVERS\MSFLASH,这个文件夹下的代码编译出fal.lib

    也就是说FAL层是以fal.lib供链接的,fal.lib的导出文件内容如下:

    LIBRARY     MSFLASH

     

    EXPORTS

            DSK_Init

            DSK_Deinit

            DSK_Open

            DSK_Close

            DSK_Read

            DSK_Write

            DSK_Seek

            DSK_IOControl

                       DSK_PowerDown

                       DSK_PowerUp

     

    从上面的导出函数可知FAL层向应用层(如API)提供DSK接口

     

     

    2.2 FMD

    smflash_lib.lib\WINCE600\PLATFORM\DMA2443\Src\Common\Smartmedia\fmd,这个文件下的代码生成smflash_lib.lib,而\WINCE600\PLATFORM\DMA2443\Src\Common\Smartmedia\Dll

    文件夹将生成smflash.dll,下面是其sources的内容:

    TARGETNAME=smflash

    TARGETTYPE=DYNLINK

    RELEASETYPE=PLATFORM

     

    WINCEOEM=1

    DEFFILE=smflash.def

     

    TARGETLIBS=$(_COMMONSDKROOT)\lib\$(_CPUINDPATH)\coredll.lib \

     

    SOURCELIBS=$(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\fal.lib \

               $(_TARGETPLATROOT)\lib\$(_CPUINDPATH)\smflash_lib.lib

    可以知道smflash.dll需要链接fal.libsmflash_lib.lib这个两个库,而fal.lib就是FAL层提供的链接库,smflash_lib.libFMD层提供的链接库。

     

     

    3. FAL层和FMD层的交互

     

    3.1 FAL层获取FMD层的函数接口

    在系统启动过程中,oal.exe 载了kernel.dll, kernel.dll加载device.dll, device.dll加载devmgr.dll, 这个就是负责加载, 卸载, 管理流驱动的. 备管理器找到HKLM\Drivers\BuiltInBusEnum.dll加载, 这是一个总线枚举驱动, 依照ORDER值指示的加载顺序,它来完成后续的加载工作, 也是使用ActiveDevice来加载.设备管理器加载smflash驱动的时候,调用DSK_Init函数,这个函数在falmain.cpp下面定义,下面是其中一部分

     

    2

    下面来看GetFMDInterface函数是如何或去FMD提供的接口函数的

     

     

    3

    到此FAL层已经获得FMD层提供的函数接口,结构体FMDInterfacepublic\common\oak\inc\fmd.h中定义,如下:

     

     

    4

     

    3.2 FMD层提供的函数接口

     

    3.2.1 PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)

     

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

     

    5

    nand flash控制器参数TACLSTWRPH0TWRPH1的确定,可以参考我另一篇博文:

    http://blog.csdn.net/LoongEmbedded/archive/2010/10/14/5939912.aspx,下面先来了解读取K9F1G08U0BID,读取K9F1G08U0B芯片ID操作首先需要写入读ID命令(0x90),然后再写入0x00地址,就可以读取到一共五个周期的芯片ID,第一个周期为厂商ID,第二个周期为设备ID,第三个周期至第五个周期包括了一些具体的该芯片信息,K9F1G08U0B关于读取ID的操作如下图:

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    6

    那么函数ReadFlashID是如何实现的呢,见下图:

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    7

    接下来继续看FMD_Init函数的后半部分:

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    8

     

    3.2.2 BOOL FMD_Deinit(PVOID hFMD)

    这个函数在nandflash驱动卸载的时候被调用,参数就是FMD_Init函数返回的Handle.一般在这个函数里面,你可以释放一些用到的资源,然后关闭nandflash controller,但是这里的FMD_Denit函数只是简单返回TRUE,所以就不做介绍了。

     

    3.2.3 BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)

     

    这个函数用于读nandflash的一个扇区。对于nandflash来说,分大page和小page,大page2048bytes一页,小page512bytes一页。所以大page每个扇区有2048 bytes,小page每个扇区有512 bytes

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

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

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

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

     

    因为本驱动的nandflash是大页面的,FMD_ReadSector函数 调用FMD_LB_ReadSector函数来实现,在看read操作的代码之前先看K9F1G08U0B读操作的时序要求:

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    9

    下面来看FMD_LB_ReadSector函数的实现:

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    10

    接着看此函数的实现部分:

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    11

    接下来就开始读取页数据了,先来看看K9F1G08U0B对随即读取页数据的时序图

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    12

    下面看看其实现的代码

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    13

    下图是S3C2443 nandflash控制器中关于NFMECCD0NFMECCD1寄存器的描述

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    14

     

    3.2.4 BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff,DWORD dwNumSectors)

     

    该函数用于写nandflash的一页。参数和上面的FMD_ReadSector的参数意思一样,就不多说了。FMD_WriteSector 函数会调用FMD_LB_WriteSector函数来写数据,下面先来看K9F1G08U0B页编程的时序图:

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

     

    15

    接下来来看这个函数的实现部分:

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    16

    接着看此函数体

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    17

    继续,结合我的博文http://blog.csdn.net/LoongEmbedded/archive/2010/11/17/6015302.aspx可以更好去理解

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    18

    继续

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    19

    下图是K9F1G08U0B中关于编程和读状态操作的时序图

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    20

     

     

    3.2.5 BOOL FMD_EraseBlock(BLOCK_ID blockID)

    该函数用于擦除nandflash中一个block,参数为要擦除nandflashblock地址,也就是第几个block。这个函数的详细描述见我的另一篇博文:

    http://blog.csdn.net/LoongEmbedded/archive/2010/11/17/6015302.aspx

     

    3.2.6 DWORD FMD_GetBlockStatus(BLOCK_ID blockID)

    该函数获得nandflash中某一个block的状态。参数为nandflashblock地址。由于nandflash中可能有坏块,所以针对nandflash,这个函数首先会检查当前块是否是坏块,这个一般通过读取当前block的第0page和第1page的带外数据。对于小page nandflash一般是读取第5byte,对于大page nandflash一般读取第0byte,如果不为0xff表示该块是坏块。当然,至于具体该读哪个byte,最好还是看一下所用nandflashdatasheet,确认一下,不同的厂家可能有所不同。如果发现该块是坏块,应该返回BLOCK_STATUS_BAD。如果不是坏块,需要读取这个块的起始扇区的扇区信息。如果读该扇区信息出错,应该返回BLOCK_STATUS_UNKNOWN,否则,判断独到的信息,返回相应结果。

     

    这个函数的详细描述见我的另一篇博文:

    http://blog.csdn.net/LoongEmbedded/archive/2010/11/17/6015302.aspx

     

    3.2.7 BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)

    该函数设置nandflash某个block的状态,第一个参数是nandflashblock地址,第二个是要设置的状态。在这个函数中,首先检查dwStatus是不是BLOCK_STATUS_BAD,如果是就对nandflash作坏块标记,如果不是,就将dwStatus写到该block的第0page的扇区info中。这个函数和上面的函数正好是相反的。对于大页面的nandflashFMD_SetBlockStatus函数调用FMD_LB_SetBlockStatus函数来实现,下面来看函数体

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    21

    下面就来看看LB_MarkBlockBad函数是如何把一块标识为坏块的。

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    22

     

     

     

     

    3.2.8 BOOL FMD_GetInfo(PFlashInfo pFlashInfo)

    该函数用于返回flash的信息。其中pFlashInfo是一个包含flash信息的结构。在public\common\oak\inc\fmd.h下有定义:

    typedef enum  _FLASH_TYPE { NAND, NOR } FLASH_TYPE;

     

    typedef struct _FlashInfo

    {

        FLASH_TYPE  flashType;

        DWORD       dwNumBlocks;

        DWORD       dwBytesPerBlock;

        WORD        wSectorsPerBlock;

        WORD        wDataBytesPerSector;

     

    }FlashInfo, *PFlashInfo;

    其中

    flashTypeflash的类型,对于nandflash来说,应该是NAND

    dwNumBlocksflash中总共有多少个block,查一下所用的nandflashdatasheet就知道了,在此为1024.

    dwBytesPerBlock:每个block中包含多少个bytes,在此为2112 bytes

    wSectorsPerBlock:每个block中包含多少个扇区,也就是多少页,在此为64页。

    wDataBytesPerSector:一个扇区多少个bytes,对于大page2048,对于小page512

     

    下面是此函数体

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    23

    因为此函数和FMD_Init函数体内容差不多,可参考上面对FMD_Init函数的描述。

     

     

    3.2.9 VOID FMD_PowerDown(VOID)VOID FMD_PowerUp(VOID)

    这两个函数用于电源管理。FMD_PowerDown()用于关闭flash设备电源,FMD_PowerUp()用于恢复flash设备电源。根据你所用处理器和相关硬件环境,去实现这两个函数。不实现也不会影响nandflash的使用。FMD_PowerDown函数的函数体为空,所以就没有什么介绍的了,下面看FMD_PowerUp的函数体

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    24

    此函数和FMD_Init函数中初始化nandflash控制器的代码是一样的,可以共用,具体需要根据CPUnandflash控制器和具体的nandflash来设置。

     

    3.2.10 BOOL  FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize,

                           PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)

     

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

     

     基于WINCE6.0的nandflash驱动(基于K9F1G08U0B) - 男儿当自强 - 男儿当自强的博客

    25

    FAL层的DSK_Init 函数会通过调用FMD_OEMIoControl函数来获得FALFMD层的接口函数,这些接口函数是FMD层提供的,为什么说FMD_OEMIoControl函数可以不是对IOCTL_FMD_GET_INTERFACE这个case的支持呢?因为DSK_Init函数在发现在调用FMD_OEMIoControl函数的时候如发现不支持IOCTL_FMD_GET_INTERFACE这个case,那么DSK_Init函数会自己用FMD层的接口函数来为其全局结构体变量FMD赋值,见图3

     

    参考的链接:

     

    Windows CE下的FMD接口实现文件与FAL.LIB的链接

    http://www.cnblogs.com/xilentz/archive/2010/05/31/1747839.html

     

    WinCE NAND flash – FAL

    http://blog.csdn.net/renpine/archive/2009/09/20/4572347.aspx

     

    WinCEnandflash驱动开发介绍

    http://blog.csdn.net/zhongnanjun_3/archive/2009/03/09/3973312.aspx

     

    s3c2440nandflash的操作

    http://www.360doc.com/content/10/1117/08/4128402_70026701.shtml

     

  • 相关阅读:
    Two strings CodeForces
    Dasha and Photos CodeForces
    Largest Beautiful Number CodeForces
    Timetable CodeForces
    Financiers Game CodeForces
    AC日记——整理药名 openjudge 1.7 15
    AC日记——大小写字母互换 openjudge 1.7 14
    AC日记——将字符串中的小写字母换成大写字母 openjudge 1.7 13
    AC日记——加密的病历单 openjudge 1.7 12
    AC日记——潜伏着 openjudge 1.7 11
  • 原文地址:https://www.cnblogs.com/LoongEmbedded/p/1888345.html
Copyright © 2011-2022 走看看