wince系統中對nand壞塊的修正

  wince系統中對nand壞塊的修正

產生壞塊的原因是因爲NANDFlash的工藝不能保證NAND的Memory Array在其生命週期中保持性能的可靠,所以,在NAND
的生產中及使用過程中會產生壞塊。

一、壞塊的具體表現:

 當編程/擦除這個塊時,不能將某些位拉高,這會造成Page Program和Block Erase操作時的錯誤,相應地反映到
Status Register的相應位。

二、壞塊的種類:

 1.先天性壞塊 

這種壞塊是在生產過程中產生的,一般芯片原廠都會在出廠時都會將壞塊第一個page的spare area的第6個byte標記爲不等於
0xff的值。
 

2. 後天性壞塊

 
這種壞塊是在NAND Flash使用過程中產生的,如果Block Erase
或者Page Program錯誤,就可以簡單地將這個塊作爲壞塊來處理,這個時候需要把壞塊標記起來。爲了和先天性壞塊信息保持一致,
將新發現的壞塊的第一個page的spare area的第6個Byte標記爲非0xff的值,這個壞塊標記字節的位置不具有通用性,具體以nand的datasheet爲準。
 

三、壞塊的處理

理解了先天性壞塊和後天性壞塊後,我們已明白NAND Flash出廠時在spare area中已經反映出了壞塊信息,因此,如果在擦除一個塊之前,一定要先check一下spare area的第6個byte是否是
0xff,如果是就證明這是一個好塊,可以擦除;如果是非0xff,那麼就不能擦除。
不過,這樣處理可能會錯殺僞壞塊,因爲在芯片操作過程中可能由於電壓不穩定等偶然因素會造成NAND操作的錯誤。但是,爲了數據的可靠性及軟件設計的簡單化,壞塊一個也不能放過。
但是wince爲了防止這種僞壞塊的浪費,採用了一定的補救措施來進一步驗證該壞塊爲物理壞塊還是僞壞塊。該部分實現在BOOL WriteFlashReserved(PBYTE  pBuffer, UINT32 dwLength)函數裏,具體代碼如下:
for (i=0; i < dwSectorSize; i++)
{
// 寫入新的Block時, 作一些判斷
if (i%g_FlashInfo.wSectorsPerBlock == 0)
{

if (!FMD_ReadSector(dwCurrentWriteBlock*g_FlashInfo.wSectorsPerBlock, NULL, g_pSectorInfoBuf, 1)) 
       {
OALLog(L"Fail read info %d\n", dwCurrentWriteBlock);
       }
RETAILMSG(1, (TEXT("g_pSectorInfoBuf->bBadBlock1 = %d \r\n", g_pSectorInfoBuf->bBadBlock)));//add by zhang , 20150303


//add end


// 算出這個物理block的值
BadBlockCheck:
dwCurrentWriteBlock = dwStartBlock + dwSkipBlock + i/g_FlashInfo.wSectorsPerBlock;
       
// 擦除這個block
    if (!FMD_EraseBlock(dwCurrentWriteBlock)) 
       {
           OALLog(L"Fail erase %d\n", dwCurrentWriteBlock);
           goto BadBlock;         
       }


// 再次讀出info
if (!FMD_ReadSector(dwCurrentWriteBlock*g_FlashInfo.wSectorsPerBlock, NULL, g_pSectorInfoBuf, 1)) 
       {
OALLog(L"Fail read info %d\n", dwCurrentWriteBlock);
       goto BadBlock;
       }
            RETAILMSG(1, (TEXT("g_pSectorInfoBuf->bBadBlock2 = %d \r\n", g_pSectorInfoBuf->bBadBlock)));//add by zhang , 20150303
// 擦除後, 再次讀出, 卻發現bBadBlock不爲0xFF, 是物理壞塊!
       if ((g_pSectorInfoBuf->bBadBlock != 0xff) || (g_pSectorInfoBuf->bOEMReserved != 0xff))
       {
OALLog(L"Fail oxff %d\n", dwCurrentWriteBlock);
           goto BadBlock;
       }
       
       goto GoodBlock;
       
       BadBlock:
       if (dwCurrentWriteBlock >= LOGO_BLOCK)
       {
           // 在寫Logo區時允許壞塊
           FMD_SetBlockStatus(dwCurrentWriteBlock, BLOCK_STATUS_BAD);
           
           dwSkipBlock++; //移到下一個Block
           goto BadBlockCheck;
       }
       else
       {
           RETAILMSG(1, (TEXT("WriteFlaseReserved Fail. #%x\n"), dwCurrentWriteBlock));
           return FALSE;
       }
       GoodBlock:
;
}
以上爲部分實現代碼,紅色的部分爲我加的串口打印消息,主要是將處理之前和處理之後該塊的壞塊標記位的值打印出來,以方便觀察是否能夠將壞塊通過處理之後變爲好塊。
串口打印的消息如下:
CheckSum: eecf
CheckSum Success, USBDownLoadRaw Done
WriteFlashReserved 
g_pSectorInfoBuf->bBadBlock1 = 0 
g_pSectorInfoBuf->bBadBlock2 = 255 
g_pSectorInfoBuf->bBadBlock1 = 0 
g_pSectorInfoBuf->bBadBlock2 = 255 

以上部分是下載EBOOT時候打印的消息,EBOOT佔兩個block;


Send image (DNW->UsbPort->Transmite)
Supported: stepldr.nb0 eboot.nb0 *.bmp  nk.bin(<32MB)
ReadCheckSum: 395f
CheckSum: 395f
CheckSum Success, USBDownLoadRaw Done
WriteFlashReserved 
g_pSectorInfoBuf->bBadBlock1 = 0 
g_pSectorInfoBuf->bBadBlock2 = 255
以上部分是下載STEPLDR時候打印的消息,STEPLDR佔一個block;


處理方法從代碼部分也能看得出來,首先對將要寫的塊進行擦除,擦除的時候忽略壞塊的標誌,也就是說不管好塊還是壞塊都進行擦除,擦除其實就相當於對當前塊的所有地址全部寫FF,寫完之後會從新生產壞塊標記,保存在spare area區域;然後再次讀出該spare area區域的數據進行判斷,如果爲FF則表示修正成功,該塊爲好塊,可以進行讀寫操作,如果爲非FF,則證明該塊爲不可修正的壞塊,禁止對其讀和寫操作,這樣既避免了錯殺一千的浪費,同時又保證了數據傳輸的穩定性。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章