• 基于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

     

  • 相关阅读:
    每日一练4
    每日一练3
    每日一练2 字符串逆序输出
    每日一练1
    python全局变量
    python __file__ 与argv[0]
    python 静态方法和类方法
    常用的python库(不断更新)
    django 自定义用户user模型的三种方法
    实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(三)
  • 原文地址:https://www.cnblogs.com/LoongEmbedded/p/1888345.html
Copyright © 2020-2023  润新知