zoukankan      html  css  js  c++  java
  • WinCE NAND flash


    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上。

    clip_image001

    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驅動的系統架構

    clip_image002

    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,在實體上會如下圖:

    clip_image003

    Figure 3. Region at Flash

    而Region中會存有多個Block,其示意圖如下:

    clip_image004

    Figure 4. Block at Region

    而Block中也有多個Sector,其示意圖如下:

    clip_image005

    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。

    clip_image006

    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中。

    clip_image007

    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存到這個位置中:

    clip_image008

    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的情況。

    clip_image009

    這裡要改下列的數個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. 以下的選項記得要選起來

    clip_image010

    Step 4. 上面的動作都做了之後,選取你新建的FMD再整個Project Build過。再來,便是Attach Device之後就可以看到Win CE emulator的畫面,點取紅色方框的My Device

    clip_image011

    Step 5.點取紅色方框的Control Panel

    clip_image012

    Step6.點取紅色方框的Storage Manger

    clip_image013

    Step 7. 以下便是新加的FMD。

    按下Partitions旁的New Button

    clip_image014

    會出現下列視窗,取一個名字按右上方的OK

    clip_image015

    會回到上一個畫面,選Properties

    clip_image016

    Step 8. 先選Dismount。

    clip_image017

    其它的Button會Enable

    clip_image018

    選Format Button

    Step 9. Choose Start Button

    clip_image019

    之後會跳一個訊問Message Box,選確定便會開始Format。完成後按下OK

    clip_image020

    Step 10. 回到Partition Properties的畫面,選Mount Button,按下右上方的OK

    clip_image021

    回到Storage Properties畫面後,按下右上方的OK

    clip_image022

    Step 11. 回到My Device畫面就可以看到產生了一個新的Storage。

    clip_image023

    以上便是去Create一個新的Flash Device的簡單流程。

    上面这篇分析很清晰,不过比较零散,大致的类的练习随意画了个图:

    clip_image024

    一个FAL实例针对一个Region区域,有些概念需要清楚,Wince的Sector是底层返回的页的大小,不要混淆。

    针对大的Nand Flash FAL+FMD绝对不是好的实现方式,上电建立映射表的过程太慢,如果将每个页信息放入一个集中的地方,又难免导致该处使用过度。

    使用MDD+PDD可能会更好,还没实验,之后做对比。

  • 相关阅读:
    Torchkeras,一个源码不足300行的深度学习框架
    【知乎】语义分割该如何走下去?
    【SDOI2017】天才黑客(前后缀优化建图 & 最短路)
    【WC2014】紫荆花之恋(替罪羊重构点分树 & 平衡树)
    【SDOI2017】相关分析(线段树)
    【学习笔记】分治法最短路小结
    【CH 弱省互测 Round #1 】OVOO(可持久化可并堆)
    【学习笔记】K 短路问题详解
    【学习笔记】浅析平衡树套线段树 & 带插入区间K小值
    【APIO2020】交换城市(Kruskal重构树)
  • 原文地址:https://www.cnblogs.com/LoongEmbedded/p/5298511.html
Copyright © 2011-2022 走看看