WinCE NAND flash - FAL
http://blog.csdn.net/renpine/article/details/4572347
http://msdn.microsoft.com/en-US/library/ee482032(v=winembedded.60).aspx
WinCE NAND flash - FAL
From ESSLabWiki
1. Introduction
Flash與一般常見的Disk不同,其特性是無法重複對同一塊記憶體位置去做Write的動作,必須要Erase那塊記憶體位置才可以做Write的動作。因此一般的File System,如FAT16、FAT32、NFTS…,無法直接在Flash Memory上使用;若是想要沿用這些File System,則必須透過一層Translation Layer來將Logical Block Address對應到實體的Flash Memory的位置,並透過一些機制能讓系統能把Flash Memory當作一般的硬碟一樣處理,在Win
CE的平台上,我們稱這層為FTL(Flash Translation Layer)。
FTL最原始的應用,為使用於NOR Flash,然而目前的市場價格,大容量的NOR Flash的成本,遠高於同樣容量的NAND flash ,因此有NFTL(NAND Flash Translation Layer)的產生,NFTL主要想法與FTL相似,主要差別在於是用在NAND Flash上。
![]()
Figure 1. Architecture
本文件將介紹WinCE6.0在與Flash相關的Data structure、RAM上的Data structure,以及Win CE如何在Flash作Garbage Collection、Wear-Leveling,最後說明如何在Win CE的基本系統上,註冊一個Flash Device。
2. System Architecture
下圖為Windows CE 平台中,Flash Memory驅動的系統架構
![]()
Figure 2. Flash Architecture
先對本篇的重點:FAL及FMD做基本定義的說明如下:
FMD(FLASH Media Driver)可針對特定廠商的Flash作Driven、Read、Write、Erase等動作,實際去對Flash做讀寫的操作。
FAL(FLASH Abstraction Layer):File System對Flash讀寫,必須透過此層操作。而此層則再根據FMD所提供的Interface再對Flash做讀寫。
參考Figure 1再來看此圖的行為;File System為了對Flash操作,必須透過FAL對FMD(Driver)做操作。因此面對各家Flash來說,只需修改FMD即可,而不用再行修改 FAL的Interface即可對Flash做Read、Write、Erase等基本的操作。因此可得到一個結論,若是有一個產品裡的Flash換成了另一廠商的,因Flash對FAL的interface是一致的,那麼只要抽換FMD則其它的程式都不用再修改即可使用。
那麼FMD對FAL所提供的interface及其作用後面會再詳細說明,此處便不再贅述。
FAL存在兩個Table(DLUT、Secondary Table)以提供Translation的動作,其中也存在兩條List一個存Free Sector,一個存Dirty Block來分別提供Free Sector以及可幫助Garbage Collection的作用,詳細的流程及使用後續會再行說明。
3. Terminology
以下說明一些在本篇會出現的基本名詞及其定義
在Flash中可能會有多個Region,在實體上會如下圖:
![]()
Figure 3. Region at Flash
而Region中會存有多個Block,其示意圖如下:
![]()
Figure 4. Block at Region
而Block中也有多個Sector,其示意圖如下:
![]()
Figure 5. Sector at Block
但這裡要注意的是,Win CE是採用Sector Mapping的方式,因此取Block動作時,必須依所給的Sector Address算出它是屬於那一個Block。
這裡再說明它在各Term的情況:
對Region而言,它只紀錄了它有多少個Block,且一個Block有多少個Sector。
對Block而言,它的起始位置就是第一個Sector(以Figure 5來看,就是Sector 1)。但是這裡要說明一下Block裡面是如何去算它第一個Sector的位置。假設一個Block中有10個Sector,那麼下一個Block的第一個Sector就是Sector 11。
對File System而言,所看到的Sector Address都是Logical Address;當File System想取一個在Flash上的資料,必須要給FAL那個資料的Logical Address,而FAL要去取所需的資料,需根據Logical Address解析是位於Mapping Table的位置,再依據Table中的位置取出Physical Address,再交由FMD去取出在Flash上的Data;FAL再將取得的Data交給送出Request的System。這中間更詳細的細節,後面章節會再解釋。
4. Address Translation
一個Logical Address要如何快速找到Physical Address,靠的就是Mapping Table。有了這個就可以很方便且快速的找到所需的Address(Sector)。本段要介紹如何Create Mapping Table以及如何Mapping。
4.1 In-RAM Data Structures
PUCHAR m_pDynamicLUT[MASTER_TABLE_SIZE]; DWORD m_cbPhysicalAddr;
BOOL m_bIsNumSectorsPerSecTableLog2;
DWORD m_dwNumSectorsPerSecTable;
DWORD m_dwSecondaryTableSize;
DWORD m_dwStartLogSector;
DWORD m_dwNumLogSectors;
DWORD m_dwStartPhysSector;
DWORD m_dwNumPhysSectors;
這裡主要的動作是在處理及維護 DLUT Table和Secondary Table;其用途是為了快速的從Logical Address來找到Physical Address;是做Translation一個重要的Table。
m_pDynamicLUT[MASTER_TABLE_SIZE]:
這裡MASTER_TABLE_SIZE是256。因此可知一開始便給定Table的大小。這個Variable是Dynamic Look-Up Table (DLUT),也就是Mapping Table。
m_bIsNumSectorsPerSecTableLog2:
判斷Sector的個數在Secondary Table中是否是power of 2,會影響計算Table Size以及Secondary ID。若它是2的倍數,可直接Shift取值,節省做除法取值的時間
m_dwNumSectorsPerSecTable:
在Secondary table中可紀錄多少個Sector
m_dwSecondaryTableSize:
Secondary Table的Size。根據有多少個Logical Sector及Physical Address的長度來決定Size的大小
m_dwStartLogSector:
這個Logical Block的起始Sector的位置
m_dwNumLogSectors:
Logical Sector的個數
m_dwStartPhysSector:
這個Physical Block的起始Sector的位置
m_dwNumPhysSectors:
Physical Block的Sector的個數
4.2 On-Flash Data Structures
typedef struct _FlashInfoEx
{
DWORD cbSize;
FLASH_TYPE flashType;
DWORD dwNumBlocks;
DWORD dwDataBytesPerSector;
DWORD dwNumRegions;
FlashRegion region[1];
}FlashInfoEx, *PFlashInfoEx;
typedef struct _FlashInfo
{
FLASH_TYPE flashType;
DWORD dwNumBlocks;
DWORD dwBytesPerBlock;
WORD wSectorsPerBlock;
WORD wDataBytesPerSector;
}FlashInfo, *PFlashInfo;
flashType:在init之後這裡要取得Flash Type看是NOR亦或NAND。
dwNumBlocks:看這Flash中有多少個Block
dwBytesPerBlock:一個Block有多少Bytes
wSectorsPerBlock:一個Block有多少個Sector
wDataBytesPerSector:一個Sector有多少個Bytes
這裡是取得Flash的基本Info,之後再去算這個Flash內有多少Block。而FlashInfoEx與FlashInfo的差別是Region的部分,由於看的NAND flash的部分只用一個Region,所以,下面都以一個Region做介紹。
Block有以下幾種Status, 根據不同的status來決定Sector會被放在那一個List裡。
BLOCK_STATUS_UNKNOWN:其它無法判斷的情況
BLOCK_STATUS_BAD:這個Block是Bad Block。
BLOCK_STATUS_READONLY:這個Block是Read Only。
BLOCK_STATUS_RESERVED:這個Block被Reserved。
另外,在取Block Status時,FAL是用Block ID跟FMD取Block Status,而FMD是在得到這個Block ID之後,去算出此Block在Flash中的第一個Sector是第幾個Sector,再去取出它的Status給FAL。
以下圖為例,若是一個Block有10個Sector,那麼Block 2的第一個Sector就是Sector 11。因此,FMD便是取Sector 11的Status交還給FAL。
![]()
Figure 6. Get Block Status
4.3 How to Create Mapping Table
這裡介紹在Win CE所使用的Mapping Table。它是去Scan Flash上Info,先取出Region、Flash Type。一個Region內有多個Block,每一個Region都有各自一個獨立的Table ,Region裡有多個Block。
Region的data Structure如下
typedef struct _FlashRegion
{
REGION_TYPE regionType;
DWORD dwStartPhysBlock;
DWORD dwNumPhysBlocks;
DWORD dwNumLogicalBlocks;
DWORD dwSectorsPerBlock;
DWORD dwBytesPerBlock;
DWORD dwCompactBlocks;
}FlashRegion, *PFlashRegion;
dwStartPhysBlock:在這個Region中Physical Block的index值,這裡的初始值是0。也就是說若是這個Flash中有兩個Region,而每個Region中有10個Block,則第一個 Region的Start Physical Block為0,第二個Region的Start Physical Block為10。
dwNumPhysBlocks:有多少個Block在這個Region裡
dwSectorsPerBlock:Block中有多少個Sector
dwCompactBlocks:在Compactor裡定義其值為2,之後在Compaction會看到
這裡是做Sector Mapping。因此Table是依一個個Sector去建成的。先取Block,再取Block中的所有Sector的Info(這裡取出的只有 Spare area的資料);依據這個Sector status再決定它是放入一般的List (在這裡亦有分Free, Read only) 或是Dirty list。其它有info的sector則是去做Mapping Table的動作。其中要注意的是,由於Write是以Sector為單位在寫,所以存Free List是以Sector為單位在存,而Erase是以Block為單位,所以Dirty
List是以Block為單位在存。
建Table的psuedo-code如下,
for (each Block)
{
for (each Sector)
{
Read Sector Info (spare area)
if (Sector is free)
{
add into m_list(Free)
}
if (Sector is dirty)
{
add into dirty_list
}
if (Sector is mapped)
{
if (Block is Read_Only && Sector is first sector on Block)
{
add into m_list(Read_only);
for (each Sector)
mapping the Table : L2P
break;
}
mapping the Table : L2P
}
} //for (each Sector)
}// for (each Block)
接下來說明Mapping Table的流程:
DLUT(Dynamic Look Up Table)指的是Master Table,有256個entry,一個entry對映一個Secondary Table。沒有用到的Sector(Free Sector)不會在Table中去建立,採取On Demand的方式。
一個有資料的Sector會存有之前在系統中所代表其位置的Sector Logical Address,若是要找Secondary Tables並未建立,系統才會去建其Table,並根據Logical Address算出它在Secondary Table中的位置,再將其Physical Address存入至Table中。
![]()
Figure 7. DLUT and Secondary Table
下圖是詳細的建立Table的過程:
1. 根據給的Logical Sector先去算出Secondary Table ID(此圖假設算出來的ID = 1),再查詢是否已有Secondary Table,若該table不存在,系統會在此時Allocate一個新的Secondary Table。
2. 就先前讀出的Sector’s Spare Area的資料來建Secondary Table。再來便是計算在Secondary Table中的位置
3. 取出後再把Physical Sector Address存到這個位置中:
![]()
Figure 8. Create Logical to Physical Sector Address
4.4 Read
它做的流程可參考Figure 4來解釋,。根據Sector’s Logical Address算出在DLUT是第幾個entry,再依據Entry就可以取得相對應的Secondary Table,再利用Logical Address做計算取出在這個Secondary Table中的位置,之後便可取得Physical Address。而FMD就可根據這個Address來取出位於Flash的資料。
4.5 Write
在Write之前必須在Free list中取一個可用的Sector,若是Sector不足,便會啟動Compaction機制,以取到足夠的Sector,以便完成 Write。
在Write之前先將Sector Info Mark成處理中,再去寫Sector info;寫完info確定該Sector可以寫入,再將Sector Info 標示為處理完,與Data一起寫入。最後更新Mapping Table以及Logical Address對映的Physical Address。
而之前舊的資料,將其update Sector info設定為Dirty;此外會算出此Sector位於哪一個Block,並將該Block Dirty的Sector個數加1。這邊要請讀者注意的是,它是SLC的動作,它可以允許一次這個動作,而MLC是不允許此值直接變更寫回。
5. Garbage Collection (Compaction)
Garbage Collection,在WinCE中的命名是Compaction。簡單的說,其目的是回收被無效資料所佔據的空間,且一次可回收愈多愈好。
5.1 What’s Garbage Collection?
由於Flash無法在更新資料時寫回相同的位置(除非先將該位置Erase),所以採Outplace的方式寫回資料。Outplace是將更新的資料寫入在不同的頁面中,來避免每次更新資料就必須進行抹除的動作的Overhead。
那麼原來不能直接寫回而變成無用舊資料的Sector,便需要有policy去將它釋放成為可用的Sector,這個policy便是Garbage Collection
5.2 Garbage Collection Policy
在這個FAL中會存在兩條List,分別去紀錄Free Sector及Dirty Block。這兩條List所紀錄的大小不一樣是由於寫是Sector為單位去寫,而Erase是以Block為單位在做。
上面所提到的直接選Dirty Block,便是直接去取Dirty List裡Dirty Sector最多的一個Block來當做Victim Block。而Random選Block的方式,是取第一個Physical Block做Base,用1~32做Random去除Physical Block的數量取餘數;Base加上餘數之後的值為Block ID,這個Block即為Victim Block。
Compaction的時機是當Free Sector不足時做,且會做到這個Compaction完成才離開,這裡稱它是Synchronous Compaction。例如:一個Block有20個Sector,那麼Free Sector最少要有40個才夠。另一個情況是,當你要寫的Data的Sector個數若是比目前Free Sector個數多時,它也會強制執行Compaction直到有足夠的Free Sector,得以完成Write Data的任務才會結束。
另一個時機是當Flash目前的Dirty Sector數目Free Sector多(但此情況還是Free Sector的個數比限制的下限個數多),但是它的Priority低,是Background Compaction這裡稱它是Asynchronous Compaction,不會強制必須要Compaction結束才會離開。
6. Wear-Leveling
6.1 What is Wear-Leveling?
因為Flash的每個Block有Erase次數的限制,當某個Block Erase次數過多,可能會造成該Block存取速度變慢,嚴重時甚至會造成該Block毀損。因此為了避免同一區塊過度存取而造成毀損,且能夠平均每個 Block Erase的的次數,此機制稱為Wear-Leveling。
6.2 How WL is done in FAL
這裡Critical是指當Free Sector不足時的情況,所以會直接取Dirty List裡的Block去做Compact。其它情況下就使用Random的方式,下面就直接介紹這兩種policy。
1. Critical = True
從Dirty List裡取一個Dirty Sector最多的Block來Earse
Bool value 不更改。
2. Critical = False
是用Random的方式,用Static Bool value做交替的條件,Bool value的初始值為False。
若第一次是Random方式選(Bool Value = True),且更改Bool value
則第二次從Dirty List裡選(Bool Value = False),亦更改Bool value
此外,若是Random選出來的Block是Free或是Invalid就從Dirty List裡選。
Random使用範例如下:
Sequence(S)
1
2
3
4
5
Execute
Dirtiest
Random
Dirtiest
Random
Dirtiest
Free Block
N
N
N
Y
N
Re-Execute
Dirtiest
S 1:第一次是Bool value = False,所以從Dirty List裡取,且更改Bool value為True
S 2:第二次是Bool value = True,所以取Random,且更改Bool value為False
S 3:第三次是Bool value = False,從Dirty List裡取,且更改Bool value為True
S 4:第四次是Bool value = True,所以取Random,且更改Bool value為False。但取出的Block為Free Block所以改取Dirty List。
S 5:第五次是Bool value = False,從Dirty List裡取,且更改Bool value為True
綜合使用範例如下:
C = Critical, D = Dirty Block, R = Random Block,
B = bRandom-表示T下一次要選Random或是從Dirty List裡取Victim
(請看Critical = False的範例及說明)
若C的順序如下:
TFFTFFF B = F (init)
則選的Block的流程如下:
Critical
Choose Block
B (Change)
C = T
D
B = F(no change)
C = F
D
B = T
C = F
R→若選出Block is Free
則再從D選
B = F
C = T
D
B = F (no change)
C = F
D
B = T
C = F
R
B = F
C = F
D
B = T
7. FMD/FAL interface
7.1 FMD給FAL的函式介面
typedef struct _FMDInterface
{
DWORD cbSize;
PFN_INIT pInit;
PFN_DEINIT pDeInit;
PFN_GETINFO pGetInfo;
PFN_GETBLOCKSTATUS pGetBlockStatus;
PFN_SETBLOCKSTATUS pSetBlockStatus;
PFN_READSECTOR pReadSector;
PFN_WRITESECTOR pWriteSector;
PFN_ERASEBLOCK pEraseBlock;
PFN_POWERUP pPowerUp;
PFN_POWERDOWN pPowerDown;
PFN_GETPHYSSECTORADDR pGetPhysSectorAddr;
PFN_OEMIOCONTROL pOEMIoControl;
} FMDInterface, *PFMDInterface;
以上FMD Function其本來是以FMD_做Prefix,以pGetBlockStatus為例,其在FMD.cpp的naming是 FMD_GetBlockStauts;但為了某些使用技巧,因此將其包裝成Structure使其得以用Function Point的方式使用,以下說Function的用途:
pInit:
當Flash Device要initial時對Device做初始化的動作。找到其支援的chip加以進行初始化,以及返回一個FMD handle。
pDeInit:
取得FMD handle以釋放一些用到的資源,關掉chip controller。
pGetInfo:
該函數用於取得Flash的資訊。其中pFlashInfo是一個包含Flash資訊的結構。
pFlashInfo->flashType:Flash的類型。
pFlashInfo->wDataBytesPerSector:一個Sector多少個Bytes。
pFlashInfo->dwNumBlocks:Flash中總共有多少個Block。
pFlashInfo->wSectorsPerBlock:每個Block中包含多少個Sector。
pFlashInfo->dwBytesPerBlock:每個Block中包含多少個Bytes。
pGetBlockStatus:
為取得某一個block的狀態。參數為Block Address。由於Flash中可能有Bad Block,所以首先會檢查目前是否為Bad Block,是取得第一個Sector的Status即可知道。如果發現該塊是Bad Block,應該返回BLOCK_STATUS_BAD。如果不是Bad Block,需要讀取這個塊的起始Sector的Sector Info。如果讀該Sector Info出錯,應該返回BLOCK_STATUS_UNKNOWN。
pSetBlockStatus:
設定某個block的狀態,第一個參數是Block位址,第二個是要設定的狀態。在這個函數中,首先檢查dwStatus是不是 BLOCK_STATUS_BAD,如果是就對作Bad Block標記,然後返回FALSE。如果不是,就將dwStatus寫到該block的第一個Sector的info中。
pReadSector:
用於讀Flash上的一個Sector。其中傳入的參數值代表如下:
startSectorAddr:
Sector的起始位址,就是從哪個Sector開始。
pSectorBuff:
讀出的每一個Sector的資料都存放在這個buffer中。
pSectorInfoBuff:
一般每個Sector的資訊會被保存在Flash的資料中。從Flash的資料將該Sector的相關資訊讀出來,存放在這個buffer中。這些資料也就是Spare area。
dwNumSectors:
讀取多少個Sector。
pWriteSector:
意義與上面相同,此處是對Write。
pEraseBlock:
為Erase block,參數為第幾個block。
pPowerUp:
恢復Flash設備電源
pPowerDown:
關閉Flash設備電源
pGetPhysSectorAddr:
取得在Flash上它physical Address。
pOEMIoControl:
就像很多的IOControl函數一樣,根據不同的case,實現相應的功能。針對NAND Flash來說,這裡面不一定都需要implement。事實上,如果什麼都沒有implement,也不影響使用。
7.2 FAL給File System的函式介面
DSK_Init:
這裡會先去initial FMD,以便取得Flash基本資料。之後再去initial FAL,以取得對Flash操作的interface,還有建立Translation Table。
DSK_Deinit:Free FAL object再Free FMD
DSK_Open:這裡並未implement只有debug message。
DSK_Close:這裡並未implement只有debug message,return TRUE。
DSK_Read:Not Used。
DSK_Write:Not Used。
DSK_Seek:Not support。
DSK_PowerDown:直接Call FMD的PowerDown function。
DSK_PowerUp:直接Call FMD的PowerUp function。
DSK_IOControl:
對Flash的操作皆是透過這支Function。先根據進來的Control Code再去做相應的檢查;例如對Flash取得其Information(GetInfo),要確認傳進來的Buffer以及Size是否正確,無誤之後再去做相應的動作。
因此上述的Open、Close、Read、Write皆是由此Function做處理。
8. 與系統註冊一個Device
8.1 FAL、FMD
在 WinCE 裡的Flash driven實作是由FAL及FMD所組成(Figure 1),FAL以Library的型式,它對外的interface其Prefix為DSK_開頭(7.2章有介紹),而FMD是Dynamic Link的型式,其Prefix則是FMD_開頭(7.1章有介紹)。要在WinCE上需要MSflash.lib來趨動,這會需要有fal.lib及 fmd.dll,才可以在WinCE裡使用這個Flash。FAL也要有一個FMD才可以在WinCE上Run一個Device,否則在WinCE而言,也只是提供了一個Interface而沒有可使用的Device。
FAL是由下列File組成的(在此僅列.Cpp)
1. Compactor – 提供Compactor function
2. Fal – Build Mapping Table以及對FMD Layer下Read、Write、Compactor、Format的動作,實際對Flash做Read、Write、Erase還是FMD Layer(架構請見Figure 1)
3. falmain – 提供給File System的Interface
4. log2physmap – Mapping Table之Update及取得Physical Sector Address。
5. sectormgr – 對Sector之管理,諸如對Free-List及Dirty-List之處理(管理),以及提供對Sector操作的Function
以下做的動作是將系統中FAL(Library)從系統中抽出來,再加上修改過的Flash FMD(Driver),將其在Simulator上得以被註冊顯示在WinCE的環境裡。
8.2如何與系統註冊一個Storage
Step 1.
在建好一個OSDesign時,請先Build整個環境(約二十至四十分鐘不等),若是先做下面的動作再一起Build,會出現Error。
Step 2.
加入Project在your clone emulator (這裡是Clone自Device Emulator : ARMV4I。Clone name : ARVV4IBase)
下的SRC->Drivers (path : C:/WINCE600/PLATFORM/ARMV4IBase/SRC/DRIVERS)
以下是顯示在Visual Studio的情況。
![]()
這裡要改下列的數個File
Dirs:C:/WINCE600/PLATFORM/your clone emulator/SRC/DRIVES裡,加入新加的Project name(Driver name)。
Example:(# -- 注解)
# @CESYSGEN ENDIF CE_MODULES_SHOWFAL
FALSHOW /
FMDSHOW /
Platfrom.bib:其目的是要定義那些是要包在OS的Image內,因此要加入新的FMD。
Example:
IF BSP_FMDSHOW1
FMDSHOW1.dll $(_FLATRELEASEDIR)/FMDSHOW1.dll NK SHK
ENDIF
Platfrom.reg:定義冷開機時系統啟始的Registry Key及相關數值,值得一提的是,Storage的IClass是可以重複的。
Example:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/FMDSHOW1]
"Prefix"="DSK"
"Dll"="FMDSHOW1.dll"
"IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
之後若是修改Platfrom.reg裡的值只需要Build->Advanced BuildCommands->Build Current BSP and Subprojects即可
Source:是存要Link的library或是會使用到的library,這個是每個Project都會有的。
Catalog Item:如此建的FMD才可以在Catalog Items View下的Device Drivers裡看到。
Step 3. 以下的選項記得要選起來
![]()
Step 4. 上面的動作都做了之後,選取你新建的FMD再整個Project Build過。再來,便是Attach Device之後就可以看到Win CE emulator的畫面,點取紅色方框的My Device
![]()
Step 5.點取紅色方框的Control Panel
![]()
Step6.點取紅色方框的Storage Manger
![]()
Step 7. 以下便是新加的FMD。
按下Partitions旁的New Button
![]()
會出現下列視窗,取一個名字按右上方的OK
![]()
會回到上一個畫面,選Properties
![]()
Step 8. 先選Dismount。
![]()
其它的Button會Enable
![]()
選Format Button
Step 9. Choose Start Button
![]()
之後會跳一個訊問Message Box,選確定便會開始Format。完成後按下OK
![]()
Step 10. 回到Partition Properties的畫面,選Mount Button,按下右上方的OK
![]()
回到Storage Properties畫面後,按下右上方的OK
![]()
Step 11. 回到My Device畫面就可以看到產生了一個新的Storage。
![]()
以上便是去Create一個新的Flash Device的簡單流程。
上面这篇分析很清晰,不过比较零散,大致的类的练习随意画了个图:
![]()
一个FAL实例针对一个Region区域,有些概念需要清楚,Wince的Sector是底层返回的页的大小,不要混淆。
针对大的Nand Flash FAL+FMD绝对不是好的实现方式,上电建立映射表的过程太慢,如果将每个页信息放入一个集中的地方,又难免导致该处使用过度。
使用MDD+PDD可能会更好,还没实验,之后做对比。
WinCE NAND flash - FAL的更多相关文章
- SRAM SROM DRAM DROM DDR NAND FLASH EMMC的区别
RAM(Random Access Memory)的全名为随机存取记忆体,它相当于PC机上的移动存储,用来存储和保存数据的.它在任何 时候都可以读写,RAM通常是作为操作系统或其他正在运行程序的临时存 ...
- 嵌入式Linux驱动学习之路(二十三)NAND FLASH驱动程序
NAND FLASH是一个存储芯片. 在芯片上的DATA0-DATA7上既能传输数据也能传输地址. 当ALE为高电平时传输的是地址. 当CLE为高电平时传输的是命令. 当ALE和CLE都为低电平时传输 ...
- (一)Nand FLASH 原理讲解
NAND FLASH 优势 : 可以用当硬盘 这里好像型号是 K9F2G08 基本结构: 不是很难自己看看,暂时不要看
- NAND flash sub-pages
http://www.linux-mtd.infradead.org/doc/ubi.html#L_subpage NAND flash sub-pages As it is said here, a ...
- Nand Flash,Nor Flash,CFI Flash,SPI Flash 之间的关系
前言: 在嵌入式开发中,如uboot的移植,kernel的移植都需要对Flash 有基本的了解.下面细说一下标题中的中Flash中的关系 一,Flash的内存存储结构 flash按照内部存 ...
- 硬件初始化,nand flash固化操作,系统启动简单流程
2015.3.27星期五 晴 链接脚本定义代码的排放顺序 硬件系统初始化:一:arm核初始化:(里面有指令)初始化ARM核的时候需要看arm核的手册指令:1.异常向量(最起码有个复位异常,初始化模式- ...
- 第8章 NAND FLASH控制器
8.1 NAND Flash介绍和NAND Flash控制器使用 NAND Flash在嵌入式系统中的地位与PC上的硬盘类似 NAND Flash在掉电后仍可保存 8.1.1 Flash介绍 有NOR ...
- s3c2440 移值u-boot-2016.03 第4篇 支持NAND flash 识别
1, /include/configs/smdk2440.h 中添加 #define CONFIG_CMD_NAND 编译 drivers/mtd/nand/built-in.o: In functi ...
- s3c2440 移值u-boot-2016.03 第2篇 支持Nand flash启动
1, 要求:在4K 的代码以内,完成 NOR NAND 类型判断,初始化 NAND 复制自身到 SDRAM ,重定向. 2, 在 /arch/arm/cpu/arm920t/ 文件夹里 添加一个 in ...
随机推荐
- 3.12php
这是我的第一个博客 纪念一下 反正都是自己看 第一个问题 出现错误 当图片超过1M时就可能出现以下错误 当然这个也跟你php.ini设置有关 如果你php设置里 memory_limit 16M ...
- XE5 ANDROID平台 调用 webservice
服务端需要midas.dll XE5对android的平台支持很有吸引力,虽然目前用来直接开发应用到安卓市场卖赚钱可能性估计不大(安卓市场目前国内好像都是免费的天下),但是对于企业应用很是很有帮助 ...
- Spark Streaming揭秘 Day10 从BlockGenerator看接收数据的生命周期
Spark Streaming揭秘 Day10 从BlockGenerator看接收数据的生命周期 昨天主要介绍了SparkStreaming中对于Receiver的生命周期管理,下面让我们进入到Re ...
- python 模拟ajax查询社工库...
在windows中使用,输入有关信息查询社工库,本来是网页版的,我把ajax请求提取出来.粗略的封装下,挺好玩. #coding:utf8 import urllib2,urllib from Bea ...
- Django文档——Model中的ForeignKey,ManyToManyField与OneToOneField
关联关系字段 (Relationship fields) ForeignKey,ManyToManyField与OneToOneField分别在Model中定义多对一,多对多,一对一关系. 例如,一本 ...
- python 判断 windows 隐藏文件/系统文件
linux 下隐藏文件是以句号 “.” 开头的文件,根据文件名即可判断是否为隐藏文件. win 下是以文件隐藏属性确定的,所以,只能通过微软的 API 获取隐藏属性来判断是否为隐藏文件. 1. win ...
- Device eth0 does not seem to be present
解决办法: 首先,打开/etc/udev/rules.d/70-persistent-net.rules内容如下面例子所示: # vi /etc/udev/rules.d/70-persistent- ...
- 判断js中的数据类型
如何判断js中的数据类型:typeof.instanceof. constructor. prototype方法比较 如何判断js中的类型呢,先举几个例子: var a = "iamstri ...
- hdu 4717 The Moving Points(第一个三分题)
http://acm.hdu.edu.cn/showproblem.php?pid=4717 [题意]: 给N个点,给出N个点的方向和移动速度,求每个时刻N个点中任意两点的最大值中的最小值,以及取最小 ...
- 如何通过logcat查看系统程序的意图
如果在logcat中不能看到系统程序启动时的意图的类名, 以打开图库(gallery)为例,可以通过在ddms中如图设置,就可以在tomcat中查看到gallery启动时的意图.