基于WINCE6.0的nandflash驱动(基于K9F1G08U0B)
*******************************LoongEmbedded********************************
作者:LoongEmbedded
時間:2010.11.26
類別:WINCE驅動開發
********************************LoongEmbedded********************************
?
?
1.?????? nandflash驅動架構概述
圖1
?
Windows CE下的FLASH驅動分為兩層,分別為FMD層和FAL層(flash abstraction layer),FMD(Flash Media Driver)屬于底層,直接操作Flash硬件,比如讀、寫和擦除等,不同的Flash硬件則FMD_XXX接口實現函數各不相同,上層則是FAL (Flash Abstraction Layer)層,該層是由微軟實現并提供的,是一個與硬件無關的層,可用于FAL層實現扇區的動態分配和壞塊管理等。FAL層向應用層(如API)提供DSK接口。例如CreateFile中調用的設備即是調用該FAL層提供的接口。FMD層暴露FMD_XXX讓FAL層調用。 在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.FAL和FMD對應的實現代碼部分
首先我們知道是由FAL+FMDàsmflash.dll的,下面看看FAL和FMD分別對應哪些代碼:
?
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.lib和smflash_lib.lib這個兩個庫,而fal.lib就是FAL層提供的鏈接庫,smflash_lib.lib是FMD層提供的鏈接庫。
?
?
3. FAL層和FMD層的交互
?
3.1 FAL層獲取FMD層的函數接口
在系統啟動過程中,oal.exe加 載了kernel.dll, kernel.dll加載device.dll, device.dll加載devmgr.dll, 這個就是負責加載, 卸載, 管理流驅動的. 設 備管理器找到HKLM/Drivers/BuiltIn下BusEnum.dll加載, 這是一個總線枚舉驅動, 依照ORDER值指示的加載順序,它來完成后續的加載工作, 也是使用ActiveDevice來加載.設備管理器加載smflash驅動的時候,調用DSK_Init函數,這個函數在falmain.cpp下面定義,下面是其中一部分
圖2
下面來看GetFMDInterface函數是如何或去FMD提供的接口函數的
圖3
到此FAL層已經獲得FMD層提供的函數接口,結構體FMDInterface在public/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_Init是Flash設備的初始化函數。在WinCE啟動的時候,要加載Flash驅動時,首先調用這個函數對flash設備進行初始化。如果你的系統中有nandflash的controller,那么你需要在這里對你的nandflash controller進行初始化。如果沒有的話,你需要針對你的硬件設計進行相關的片選,時序等進行配置。返回一個handle表示成功,這個handle將被FMD_Deinit(..)函數用到,如果返回NULL表示失敗。下面來看看FMD_Init的函數體:
圖5
nand flash控制器參數TACLS、TWRPH0和TWRPH1的確定,可以參考我另一篇博文:
http://blog.csdn.net/LoongEmbedded/archive/2010/10/14/5939912.aspx,下面先來了解讀取K9F1G08U0B的ID,讀取K9F1G08U0B芯片ID操作首先需要寫入讀ID命令(0x90),然后再寫入0x00地址,就可以讀取到一共五個周期的芯片ID,第一個周期為廠商ID,第二個周期為設備ID,第三個周期至第五個周期包括了一些具體的該芯片信息,K9F1G08U0B關于讀取ID的操作如下圖:
?
圖6
那么函數ReadFlashID是如何實現的呢,見下圖:
圖7
接下來繼續看FMD_Init函數的后半部分:
圖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,大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。
?
因為本驅動的nandflash是大頁面的,FMD_ReadSector函數 調用FMD_LB_ReadSector函數來實現,在看read操作的代碼之前先看K9F1G08U0B讀操作的時序要求:
圖9
下面來看FMD_LB_ReadSector函數的實現:
?
圖10
接著看此函數的實現部分:
圖11
接下來就開始讀取頁數據了,先來看看K9F1G08U0B對隨即讀取頁數據的時序圖
圖12
下面看看其實現的代碼
圖13
下圖是S3C2443 nandflash控制器中關于NFMECCD0和NFMECCD1寄存器的描述
圖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頁編程的時序圖:
圖15
接下來來看這個函數的實現部分:
圖16
接著看此函數體
圖17
繼續,結合我的博文http://blog.csdn.net/LoongEmbedded/archive/2010/11/17/6015302.aspx可以更好去理解
圖18
繼續
圖19
下圖是K9F1G08U0B中關于編程和讀狀態操作的時序圖
圖20
?
?
3.2.5 BOOL FMD_EraseBlock(BLOCK_ID blockID)
該函數用于擦除nandflash中一個block,參數為要擦除nandflash的block地址,也就是第幾個block。這個函數的詳細描述見我的另一篇博文:
http://blog.csdn.net/LoongEmbedded/archive/2010/11/17/6015302.aspx
?
3.2.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,否則,判斷獨到的信息,返回相應結果。
?
這個函數的詳細描述見我的另一篇博文:
http://blog.csdn.net/LoongEmbedded/archive/2010/11/17/6015302.aspx
?
3.2.7 BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)
該函數設置nandflash某個block的狀態,第一個參數是nandflash的block地址,第二個是要設置的狀態。在這個函數中,首先檢查dwStatus是不是BLOCK_STATUS_BAD,如果是就對nandflash作壞塊標記,如果不是,就將dwStatus寫到該block的第0個page的扇區info中。這個函數和上面的函數正好是相反的。對于大頁面的nandflash,FMD_SetBlockStatus函數調用FMD_LB_SetBlockStatus函數來實現,下面來看函數體
圖21
下面就來看看LB_MarkBlockBad函數是如何把一塊標識為壞塊的。
圖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;
其中
flashType:flash的類型,對于nandflash來說,應該是NAND。
dwNumBlocks:flash中總共有多少個block,查一下所用的nandflash的datasheet就知道了,在此為1024.
dwBytesPerBlock:每個block中包含多少個bytes,在此為2112 bytes。
wSectorsPerBlock:每個block中包含多少個扇區,也就是多少頁,在此為64頁。
wDataBytesPerSector:一個扇區多少個bytes,對于大page是2048,對于小page是512。
?
下面是此函數體
圖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的函數體
圖24
此函數和FMD_Init函數中初始化nandflash控制器的代碼是一樣的,可以共用,具體需要根據CPU的nandflash控制器和具體的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,你可以實現,也可以不去實現,下面是其函數體
圖25
FAL層的DSK_Init 函數會通過調用FMD_OEMIoControl函數來獲得FAL和FMD層的接口函數,這些接口函數是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
?
WinCE中nandflash驅動開發介紹
http://blog.csdn.net/zhongnanjun_3/archive/2009/03/09/3973312.aspx
?
s3c2440對nandflash的操作
http://www.360doc.com/content/10/1117/08/4128402_70026701.shtml
?
總結
以上是生活随笔為你收集整理的基于WINCE6.0的nandflash驱动(基于K9F1G08U0B)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WINCE支持的波斯语的codepage
- 下一篇: Wince程序内存和存储内存