《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 嵌入式技術(shù) > 設(shè)計(jì)應(yīng)用 > 基于NAND Flash的轉(zhuǎn)譯層的設(shè)計(jì)
基于NAND Flash的轉(zhuǎn)譯層的設(shè)計(jì)
來(lái)源:微型機(jī)與應(yīng)用2010年第24期
侯 超,徐建城
(西北工業(yè)大學(xué),陜西 西安710129)
摘要: 基于NAND Flash的嵌入式存儲(chǔ)系統(tǒng)以其輕巧便攜、讀寫速度快等特點(diǎn)成為當(dāng)前嵌入式存儲(chǔ)系統(tǒng)的主流配置。但由于固有壞塊以及在擦、寫過(guò)程中隨機(jī)產(chǎn)生的壞塊影響了NAND Flash的實(shí)際應(yīng)用,所設(shè)計(jì)的NAND Flash的驅(qū)動(dòng)轉(zhuǎn)譯層具有壞塊管理機(jī)制并實(shí)現(xiàn)上層文件系統(tǒng)的連續(xù)讀寫功能。
關(guān)鍵詞: SOC NFTL 地址映射 壞塊管理
Abstract:
Key words :

摘  要: 基于NAND Flash的嵌入式存儲(chǔ)系統(tǒng)以其輕巧便攜、讀寫速度快等特點(diǎn)成為當(dāng)前嵌入式存儲(chǔ)系統(tǒng)的主流配置。但由于固有壞塊以及在擦、寫過(guò)程中隨機(jī)產(chǎn)生的壞塊影響了NAND Flash的實(shí)際應(yīng)用,所設(shè)計(jì)的NAND Flash的驅(qū)動(dòng)轉(zhuǎn)譯層具有壞塊管理機(jī)制并實(shí)現(xiàn)上層文件系統(tǒng)的連續(xù)讀寫功能。
關(guān)鍵詞: NFTL;地址映射;壞塊管理

    目前市場(chǎng)上閃存芯片主要有兩類,即NAND Flash(Not And Flash ROM)和NOR Flash(Not Or Flash ROM)。前者具有容量大、讀寫速度快、芯片面積小、單元密度高、擦除速度快、成本低等特點(diǎn),更適合于大批量數(shù)據(jù)存儲(chǔ)的嵌入式系統(tǒng)。如今Windows仍是桌面系統(tǒng)的主流,對(duì)FAT文件系統(tǒng)提供了天然的支持。然而就技術(shù)而言,F(xiàn)AT文件系統(tǒng)并不適合Flash,因?yàn)镕lash設(shè)備并不是塊設(shè)備[1],為了不破壞兼容性,并在NAND型閃存中應(yīng)用FAT文件系統(tǒng),國(guó)際上提出了閃存轉(zhuǎn)譯層FTL(Flash Translation Layer)的解決方案。
1 NAND Flash嵌入式存儲(chǔ)系統(tǒng)結(jié)構(gòu)
    基于NAND Flash的存儲(chǔ)系統(tǒng)的設(shè)計(jì)首先要解決壞塊問(wèn)題。由于NAND Flash自身存在固有壞塊并在擦除和編程中又隨機(jī)產(chǎn)生壞塊,因此為了提高設(shè)備的可靠性應(yīng)該將這兩種操作分散在閃存不同的塊中,以避免對(duì)某塊的過(guò)度操作。
    一般的基于NAND Flash嵌入式存儲(chǔ)系統(tǒng)驅(qū)動(dòng)結(jié)構(gòu)分為三個(gè)層次:最底層是硬件操作接口,負(fù)責(zé)將主控芯片與Flash的控制管腳相連,這方面的固件主要實(shí)現(xiàn)對(duì)NAND Flash的物理操作;中間層是閃存轉(zhuǎn)譯層NFTL(NAND FTL),是封裝在Flash驅(qū)動(dòng)中的軟件模塊,其作用是將Flash模擬成與磁盤相類似的塊設(shè)備,使對(duì)上層操作系統(tǒng)而言,NAND Flash就像普通磁盤一樣被訪問(wèn)。這一層主要是封裝一些特殊的復(fù)雜管理控制功能;最上面的層就是文件管理層,功能類似于普通磁盤上的通用文件系統(tǒng),向上層提供標(biāo)準(zhǔn)的文件操作接口?;贜AND Flash的嵌入式系統(tǒng)存儲(chǔ)結(jié)構(gòu)原理圖如圖1所示。

    根據(jù)以上兩個(gè)方面,既要在驅(qū)動(dòng)中實(shí)現(xiàn)壞塊管理,又要進(jìn)行塊模擬,所以可用的方法有兩種[2]:一是在上層文件系統(tǒng)中解決壞塊問(wèn)題,驅(qū)動(dòng)層只實(shí)現(xiàn)本身的功能,文件系統(tǒng)為驅(qū)動(dòng)層提供不變的接口,為上層應(yīng)用程序提供可靠透明的服務(wù)。這種方法較簡(jiǎn)單,開發(fā)周期比較短,但只對(duì)特定應(yīng)用的嵌入式系統(tǒng)有很強(qiáng)的適應(yīng)性;第二種方法是在驅(qū)動(dòng)層的NFTL中解決壞塊問(wèn)題,將不可靠的NAND Flash虛擬成可靠的存儲(chǔ)設(shè)備,為上層文件系統(tǒng)提供可靠透明服務(wù),這種方法較第一種更復(fù)雜,但是此法具有較強(qiáng)的可移植性并能徹底斷絕與文件系統(tǒng)的聯(lián)系,其他文件系統(tǒng)也同樣適用。
    本文是以Samsung的NAND Flash K9F2808U0C作為存儲(chǔ)芯片,設(shè)計(jì)了一種在NFTL上實(shí)現(xiàn)壞塊管理并且實(shí)現(xiàn)連續(xù)數(shù)據(jù)讀取的方法。
2 設(shè)計(jì)思想
2.1 閃存空間劃分

    K9F2808U0C是16 MB×8 bit的NAND Flash,共有1 024個(gè)Block,1 Block=16 KB,32 Page/Block,1 Page=528 B=(512 B+16 B),其中16 B為備用區(qū),主要存放NAND Flash出廠壞塊標(biāo)記、ECC校驗(yàn)碼以及用戶自定義區(qū)。K9F2808U0C地址空間是24 bit,分三個(gè)周期依次送入NAND Flash的地址鎖存器。本文使用的地址均為字節(jié)地址,數(shù)據(jù)類型為DWORD(4 B)。
    將K9F2808U0C的存儲(chǔ)空間劃分為四個(gè)區(qū):壞塊映射表存放區(qū)、交換塊區(qū)、壞塊映射區(qū)和實(shí)際數(shù)據(jù)存放區(qū)。文件系統(tǒng)管理的空間就是實(shí)際的數(shù)據(jù)存放空間,如圖2所示。

2.2 各分區(qū)宏定義
    #define FLASH_BLOCK_SIZE   0x40000    //16 KB/Block
    #define FLASH_PAGE_SIZE   0x200        //512 B/Page
    #define FLASH_SECTOR_SIZE  0x200
//1Page=1Sector(only K9F2808U0C)
    #define FLASH_BLOCKS_TABLE  3//壞塊映射表存放塊數(shù)
    #define FLASH_SWAP_BLOCKS   5    //交換區(qū)的塊數(shù)
    #define FLASH_BAD_BLOCKS_REMAP   50
//壞簇重映區(qū)的塊數(shù)
    #define FLASH_MAX_ADDR  0xFFFFFF
//Flash最大字節(jié)地址
    各分區(qū)首地址計(jì)算公式:
    FLASH_BLOCK_TABLE_ADDR=FLASH_MAX_ADDR+
1-3*FLASH_BLOCK_SIZE);
    FLASH_SWAP_BLOCK_ADDR=(FLASH_BLOCK_
TABLE_ADDR-5*FLASH_BLOCK_SIZE);
    FLASH_BAD_BLOCK_REMAP_ADDR=(FLASH_SWAP_
BLOCK_ADDR-50*FLASH_BLOCK_SIZE);
    FLASH_MAX_SECTOR_ADDR=(FLASH_MAX_ADDR-
3*FLASH_BLOCK_TABLE_ADDR-5*FLASH_SWAP_
BLOCK_ADDR-50*FLASH_BAD_BLOCK_REMAP_ADDR);
文件系統(tǒng)管理的最大字節(jié)地址。
    任意地址Addr:
    所在塊地址:Addr&(~(FLASH_BLOCK_SIZE-1));
    塊內(nèi)偏移地址:Addr&(FLASH_BLOCK_SIZE-1);
    塊中的頁(yè):(Addr&(FLASH_BLOCK_SIZE-1))/FLASH_
PAGE_SIZE;
2.3 分區(qū)功能設(shè)計(jì)
    壞塊映射區(qū)存放復(fù)制3份的壞塊信息BBI(Bad Block Information)表。復(fù)制3份是預(yù)防系統(tǒng)突然斷電,造成BBI表數(shù)據(jù)丟失。選擇最后3個(gè)塊,主要是出于固件設(shè)計(jì)。當(dāng)Flash首次上電,固件程序通過(guò)讀取Flash ID,獲得設(shè)備的容量等信息,然后從Flash的最后一塊中尋找BBI表,如果最后一塊沒有發(fā)現(xiàn)BBI表,則認(rèn)為此塊為壞塊,繼續(xù)前移尋找,依此類推,直到在預(yù)留的3個(gè)塊中找到,并將其數(shù)據(jù)讀入到在主控芯片為其開設(shè)的RAM中。如果還找不到,則固件認(rèn)為該片F(xiàn)lash沒有BBI表。
    交換塊區(qū)是對(duì)NAND Flash進(jìn)行擦除或?qū)懖僮鲿r(shí)用來(lái)臨時(shí)存放數(shù)據(jù),共分配5個(gè)塊。選取5塊是出于可靠性設(shè)計(jì)。用一個(gè)數(shù)組FlashSwapBlockStatus[FLASH_SWAP_BLOCKS]記錄交換塊狀態(tài):有效還是已經(jīng)損壞。初始化時(shí),固件認(rèn)為所有的交換塊都是有效塊,在隨后對(duì)其進(jìn)行擦除或?qū)懖僮鲿r(shí),通過(guò)讀Flash狀態(tài)寄存器判斷該交換塊的真實(shí)狀態(tài),并記錄在數(shù)組中。交換塊的管理圍繞固件請(qǐng)求返回當(dāng)前可用交換塊地址或當(dāng)前正在使用的交換塊地址,并判斷標(biāo)記當(dāng)前使用的交換塊狀態(tài)為壞。
    壞塊映射區(qū)是當(dāng)主機(jī)向數(shù)據(jù)區(qū)寫數(shù)據(jù)時(shí),檢測(cè)到當(dāng)前塊(數(shù)據(jù)區(qū))為壞塊時(shí),將數(shù)據(jù)寫到壞塊映射區(qū)中的相應(yīng)好塊中,并且將這兩個(gè)塊的塊地址記錄到BBI表中,以后主機(jī)若要對(duì)當(dāng)前塊(數(shù)據(jù)區(qū))訪問(wèn)時(shí),只需讀BBI表就可以找到相應(yīng)映射塊,從而代替壞塊的訪問(wèn)。這樣就使文件系統(tǒng)所見邏輯塊地址LBA(Logical Block Address)變成連續(xù)的,但實(shí)際上物理塊地址PBA(Physical Block Address)可能并不連續(xù)。上述方法就是壞塊管理的精髓。出于保守設(shè)計(jì)本文共選50塊作為重映塊。用數(shù)組FlashRemapBlockStatus[FLASH_BAD_BLOCKS_REMAP]標(biāo)識(shí)壞塊映射區(qū)的狀態(tài):未使用、已使用還是已經(jīng)損壞。初始化時(shí)認(rèn)為壞塊映射區(qū)中所有塊都是好塊。
3 NFTL壞塊管理設(shè)計(jì)
3.1 構(gòu)建BBI表

    用一數(shù)組FlashBadBlockTable[2][FLASH_BAD_BLOCKS_REMAP]存放BBI表。第一維為壞塊(數(shù)據(jù)區(qū))的塊地址,第二維為映射塊地址(重映塊)。
    BBI表的構(gòu)建可在Flash首次上電時(shí),通過(guò)讀取廠商設(shè)置在Flash備用區(qū)中的壞塊標(biāo)記識(shí)別壞塊,建立壞塊映射表,此法初始化時(shí)間與Flash的容量成正比;或通過(guò)讀NAND Flash所有塊內(nèi)容并和0xFF作比較[3],如果不相同,則表示壞塊。這種方法只針對(duì)新閃存,并且構(gòu)建BBI表的時(shí)間長(zhǎng),主控芯片的占用率高;另一種方法是在Flash初次上電時(shí)先不建立壞塊表,認(rèn)為當(dāng)前所有的塊都是好塊,在隨后操作中發(fā)現(xiàn)壞塊,并更新BBI表。本文選擇后一種方法。
3.2 壞塊映射表區(qū)的設(shè)計(jì)
    將BBI表通過(guò)特殊的方式保存,以后通過(guò)此種方式的逆向來(lái)識(shí)別BBI表。壞塊映射表區(qū)的3個(gè)塊的設(shè)計(jì)方法如下:
    (1)在每塊最后一頁(yè)的首字節(jié)處做特殊標(biāo)記,用于標(biāo)識(shí)該塊有沒有準(zhǔn)備被擦除:0xFF表示沒有準(zhǔn)備被擦除;0x00表示該塊已經(jīng)準(zhǔn)備被擦除[4]。
    (2)在每塊的倒數(shù)第二頁(yè)的首字節(jié)處寫0x00,表示該塊存放BBI表數(shù)據(jù);并在第2、3、4、5個(gè)字節(jié)處以大端模式存放校驗(yàn)和,用于校驗(yàn)該塊中存放的所有數(shù)據(jù)的正確性。該頁(yè)的剩余字節(jié)寫0xFF。
    (3)在第一頁(yè)起依次寫:表頭特殊標(biāo)記(0x0055AAFF)、壞塊總數(shù)(FlashBadBlockCount)、BBI表(FlashBadBlockTable)、重映塊狀態(tài)(FlashRemapBlockStatus),其結(jié)構(gòu)如圖3所示。

3.3 邏輯地址映射
    在與主機(jī)批量數(shù)據(jù)傳輸時(shí),首先對(duì)主機(jī)發(fā)送的CBW命令解析,從而固件獲得主機(jī)請(qǐng)求數(shù)據(jù)傳輸?shù)腖BA,再對(duì)LBA地址映射以此獲得相應(yīng)的PBA,然后再執(zhí)行主機(jī)命令。具體方法:首先讀取當(dāng)前總的壞塊數(shù)FlashBadBlocksCount,如果為0,表示無(wú)壞塊,LBA就不用映射,直接返回;如果最后一次訪問(wèn)地址與LBA同屬于一個(gè)塊,那么也不用地址映射;如果當(dāng)前壞塊的數(shù)量為1,判斷LBA塊地址與BBI表中壞塊地址是否相同,從而決定是否采取地址映射;如果當(dāng)前壞塊的數(shù)量不為1,就需要查找BBI表判斷是不是含有LBA的塊地址,如果存在,則要地址重新映射,如果不存在,就不用重新映射??梢圆捎枚址ú楸韺?shí)現(xiàn)兩地址快速比較[4]。
3.4 壞塊處理
    對(duì)映射后的地址進(jìn)行寫或擦除過(guò)程中發(fā)現(xiàn)當(dāng)前塊變壞的處理方法:首先查找映射區(qū)中的塊狀態(tài)FlashRemapBlockStatus[FLASH_BAD_BLOCKS_REMAP],尋找可用的映射塊。如果50個(gè)重映塊都被標(biāo)記為壞或已使用,則程序進(jìn)入死循環(huán);如果找到可用的映射塊,則固件對(duì)可能出現(xiàn)壞塊的三種情況進(jìn)行散轉(zhuǎn):(1)擦除當(dāng)前塊時(shí)出錯(cuò):將當(dāng)前塊地址與可用的重映塊地址寫入BBI表中,按地址大小排列有利于二分法查表,并返回重映塊地址。(2)復(fù)制某頁(yè)從交換區(qū)到操作地址時(shí)失敗:首先獲得當(dāng)前使用的交換塊的塊地址,然后判斷操作地址是在數(shù)據(jù)存儲(chǔ)區(qū)還是在重映區(qū)。如果在重映區(qū),說(shuō)明當(dāng)前操作地址所對(duì)應(yīng)的在數(shù)據(jù)存儲(chǔ)區(qū)中的塊已經(jīng)是壞塊,并且在這次操作中重映塊也變壞,此時(shí)就應(yīng)該標(biāo)記當(dāng)前映射塊狀態(tài)為壞,并在重映區(qū)中尋找下一個(gè)可用重映塊,將原來(lái)在數(shù)據(jù)存儲(chǔ)區(qū)中的塊地址與更新后的映射塊地址寫入BBI表中,并返回新的映射后的地址;如果在數(shù)據(jù)存儲(chǔ)區(qū),就進(jìn)行第一次重映射,更新壞塊表,并且將映射地址返回。然后再完成復(fù)制工作。(3)向操作地址寫一頁(yè)數(shù)據(jù)時(shí)出錯(cuò):將當(dāng)前地址所在塊中的前面頁(yè)從交換塊中相應(yīng)地址復(fù)制到重映塊,然后將操作地址所在當(dāng)前頁(yè)中的沒有寫到的數(shù)據(jù)從交換塊中復(fù)制,并將緩沖區(qū)中的數(shù)據(jù)重新寫到重映射的地址中,并返回重映射地址。函數(shù)實(shí)現(xiàn)如下:
    DWORD FlashDealBadBlock(DWORD Addr,DWORD Type)
    {
     DWORD i;
     DWORD RemapBlockAddr;
     DWORD SwapBlockAddr;
    while(1)
    {
        RemapBlockAddr=FlashGetNewRemapBlock();
        if(RemapBlockAddr==-1)
         return Addr;
        switch(Type)
         { case 1:
           goto Exit;
           break;
           case 2:
           SwapBlockAddr=FlashGetCurrentSwapBlock();
        for(i=0;i<(Addr&(FLASH_BLOCK_SIZE-1))/
FLASH_PAGE_SIZE+1;i++)
         {
         if(0x00==(FlashCopyPage(SwapBlockAddr+
i*FLASH_PAGE_SIZE,RemapBlockAddr+
i*FLASH_PAGE_SIZE)))
            goto BadRemapBlock;
           }
         goto Exit;
         break;
         case 3:
         SwapBlockAddr=FlashGetCurrentSwapBlock();
         for(i=0;i<(Addr&(FLASH_BLOCK_SIZE-1))/
FLASH_PAGE_SIZE;i++)
           {
         if(0x00==(FlashCopyPage(SwapBlockAddr+
i*FLASH_PAGE_SIZE,RemapBlockAddr+
i*FLASH_PAGE_SIZE)))
            goto BadRemapBlock;
          }
         if(0x00==(FlashCopyPage(Addr,RemapBlockAddr+
i*FLASH_PAGE_SIZE)))
            goto BadRemapBlock;
         goto Exit;
         break;
         default:
         break;
    }
    BadRemapBlock:    FlashMarkRemapBlockBad
(RemapBlockAddr);
}
    Exit:FlashUpdateBadBlockTable(Addr,RemapBlockAddr);
    return RemapBlockAddr+(Addr&(FLASH_BLOCK_SIZE-1));
}
3.5 連續(xù)讀寫操作
    當(dāng)主機(jī)與設(shè)備建立批量傳輸數(shù)據(jù)連接時(shí),固件通過(guò)解析CBW封包獲得起始LBA。對(duì)該地址進(jìn)行映射和壞塊管理從而獲得PBA。設(shè)置一個(gè)變量,當(dāng)此變量有效時(shí),表示主機(jī)對(duì)Flash仍需要讀或?qū)憯?shù)據(jù),直到此變量失效為止。同時(shí)將主機(jī)上一次讀寫扇區(qū)的地址存入另一個(gè)變量,此變量在連續(xù)讀中作用不大,但在連續(xù)寫時(shí),通過(guò)與上一次寫操作地址所在塊做比較,判斷是否同屬一個(gè)塊,以此決定是不是需要進(jìn)行地址跨塊處理。
    本文設(shè)計(jì)了一種針對(duì)NAND型的閃存轉(zhuǎn)譯層,使NFTL完成地址映射和壞塊管理以及連續(xù)讀寫數(shù)據(jù)的操作。對(duì)NAND Flash的分區(qū)設(shè)計(jì),使塊管理結(jié)構(gòu)清晰,有利于固件的開發(fā)。本文沒有對(duì)Flash的ECC校驗(yàn)進(jìn)行過(guò)多的設(shè)計(jì),這是因?yàn)樵趯?shí)際應(yīng)用中NAND Flash主要用于存儲(chǔ)多媒體數(shù)據(jù)(圖片、語(yǔ)音文件)等,并不會(huì)對(duì)它進(jìn)行頻繁的寫入或擦除操作,而且多媒體文件數(shù)據(jù)對(duì)數(shù)據(jù)的完整性不敏感[5],所以不需要對(duì)存儲(chǔ)在其中的每一位數(shù)據(jù)進(jìn)行嚴(yán)格的ECC校驗(yàn),可以通過(guò)另外設(shè)計(jì)簡(jiǎn)單的校驗(yàn)方法來(lái)代替ECC校驗(yàn)。
參考文獻(xiàn)
[1] 張雪,楊春林,黃娟.NAND Flash文件系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J].福建電腦,2007,24(10):147-148.
[2] 羅曉,劉昊.一種基于FAT文件系統(tǒng)的NAND Flash壞塊處理方法[J].電子器件,2008,31(2):716-718.
[3] 鄭桂芬.基于USB的可移動(dòng)閃盤技術(shù)探討[J].計(jì)算機(jī)工程,2003,29(7):195-197.
[4] 劉榮.圈圈教你玩USB[M].北京:北京航空航天大學(xué)出版社,2009.
[5] 楊玲,袁光濤.大容量NAND Flash在多媒體手機(jī)中的應(yīng)用[J].科技咨詢導(dǎo)報(bào),2007,4(1):22-24.

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。