当前位置: 代码迷 >> WinCE >> wince系统中对nand坏块的更正
  详细解决方案

wince系统中对nand坏块的更正

热度:378   发布时间:2016-04-28 11:51:08.0
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,则证明该块为不可修正的坏块,禁止对其读和写操作,这样既避免了错杀一千的浪费,同时又保证了数据传输的稳定性。

版权声明:本文为博主原创文章,未经博主允许不得转载。

  相关解决方案