<h1 class="title_txt"> NAND FLASH ECC校验原理与实现
<cite class="fav_csdnstylebykimi"><a class="fav_csdnstylebykimi" title="收藏到我的网摘中,并分享给我的朋友">收藏</a>
</cite>
</h1>
<div class="blogstory">
<p><strong>参考文档: <a href="http://blogimg.chinaunix.net/blog/upfile2/080702112233.pdf">http://blogimg.chinaunix.net/blog/upfile2/080702112233.pdf</a>
</strong>
</p>
<p><strong></strong>
</p>
<p><strong>NANDFLASHECC校验原理与实现<br><br></strong>
</p>
<div>
<p><strong>ECC简介</strong>
<br>
由于NANDFlash的工艺不能保证NAND的MemoryArray在其生命周
期中保持性能的可靠,因此,在NAND的生产中及使用过程中会产生坏块。为了检测数据的可靠性,在应用NANDFlash的系统中一般都会采用一定的坏
区管理策略,而管理坏区的前提是能比较可靠的进行坏区检测。<br>
如果操作时序和电路稳定性不存在问题的话,NANDFlash出错的时候一般不会造成整个Block或是Page不能读取或是全部出错,而是整个Page(例如512Bytes)中只有一个或几个bit出错。<br>
对数据的校验常用的有奇偶校验、CRC校验等,而在NANDFlash处理中,一般使用一种比较专用的校验——ECC。ECC能纠正单比特错误和检测双比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的错误不保证能检测。</p>
<p><strong>ECC原理</strong>
<br>
ECC一般每256字节原始数据生成3字节ECC校验数据,这三字节共24比特分成两部分:6比特的列校验和16比特的行校验,多余的两个比特置1,如下图所示:</p>
<p align="center"><img src="http://hi.csdn.net/attachment/201012/15/7929_12924282529qYY.png" alt="" width="774" height="206"></p>
<p align="left"> <br>
ECC的列校验和生成规则如下图所示:</p>
<p align="center"><img src="http://hi.csdn.net/attachment/201012/15/7929_12924282535Srs.png" alt="" width="442" height="113"></p>
<p align="center"><img src="http://hi.csdn.net/attachment/201012/15/7929_1292428254jjKq.png" alt="" width="702" height="334"></p>
<p align="left"><br>
用数学表达式表示为:<br>
P4=D7(+)D6(+)D5(+)D4 P4`=D3(+)D2(+)D1(+)D0<br>
P2=D7(+)D6(+)D3(+)D2 P2`=D5(+)D4(+)D1(+)D0<br>
P1=D7(+)D5(+)D3(+)D1 P1`=D6(+)D4(+)D2(+)D0<br>
这里(+)表示“位异或”操作<br>
<br>
ECC的行校验和生成规则如下图所示:</p>
<p align="center"><img src="http://hi.csdn.net/attachment/201012/15/7929_1292428254k9R8.png" alt="" width="710" height="337"></p>
<p align="left"> 用数学表达式表示为:<br>
P8=bit7(+)bit6(+)bit5(+)bit4(+)bit3(+)bit2(+)bit1(+)bit0(+)P8<br>
……………………………………………………………………………………<br>
这里(+)同样表示“位异或”操作<br>
<br>
当往NANDFlash的page中写入数据的时候,每256字节我们生成一个ECC校验和,称之为原ECC校验和,保存到PAGE的OOB(out-of-band)数据区中。<br>
当从NANDFlash中读取数据的时候,每256字节我们生成一个ECC校验和,称之为新ECC校验和。<br>
校验的时候,根据上述ECC生成原理不难推断:将从OOB区中读出的原ECC校验和新ECC校验和按位异或,若结果为0,则表示不存在错(或是出现了
ECC无法检测的错误);若3个字节异或结果中存在11个比特位为1,表示存在一个比特错误,且可纠正;若3个字节异或结果中只存在1个比特位为1,表示
OOB区出错;其他情况均表示出现了无法纠正的错误。</p>
<p align="left"><strong>ECC算法的实现</strong>
<br>
staticconstu_charnand_ecc_precalc_table[]=<br>
{<br>
0x00,0x55,0x56,0x03,0x59,0x0c,0x0f,0x5a,0x5a,0x0f,0x0c,0x59,0x03,0x56,0x55,0x00,<br>
0x65,0x30,0x33,0x66,0x3c,0x69,0x6a,0x3f,0x3f,0x6a,0x69,0x3c,0x66,0x33,0x30,0x65,<br>
0x66,0x33,0x30,0x65,0x3f,0x6a,0x69,0x3c,0x3c,0x69,0x6a,0x3f,0x65,0x30,0x33,0x66,<br>
0x03,0x56,0x55,0x00,0x5a,0x0f,0x0c,0x59,0x59,0x0c,0x0f,0x5a,0x00,0x55,0x56,0x03,<br>
0x69,0x3c,0x3f,0x6a,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6a,0x3f,0x3c,0x69,<br>
0x0c,0x59,0x5a,0x0f,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0f,0x5a,0x59,0x0c,<br>
0x0f,0x5a,0x59,0x0c,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0c,0x59,0x5a,0x0f,<br>
0x6a,0x3f,0x3c,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3c,0x3f,0x6a,<br>
0x6a,0x3f,0x3c,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3c,0x3f,0x6a,<br>
0x0f,0x5a,0x59,0x0c,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0c,0x59,0x5a,0x0f,<br>
0x0c,0x59,0x5a,0x0f,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0f,0x5a,0x59,0x0c,<br>
0x69,0x3c,0x3f,0x6a,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6a,0x3f,0x3c,0x69,<br>
0x03,0x56,0x55,0x00,0x5a,0x0f,0x0c,0x59,0x59,0x0c,0x0f,0x5a,0x00,0x55,0x56,0x03,<br>
0x66,0x33,0x30,0x65,0x3f,0x6a,0x69,0x3c,0x3c,0x69,0x6a,0x3f,0x65,0x30,0x33,0x66,<br>
0x65,0x30,0x33,0x66,0x3c,0x69,0x6a,0x3f,0x3f,0x6a,0x69,0x3c,0x66,0x33,0x30,0x65,<br>
0x00,0x55,0x56,0x03,0x59,0x0c,0x0f,0x5a,0x5a,0x0f,0x0c,0x59,0x03,0x56,0x55,0x00<br>
};</p>
<p> // Createsnon-invertedECCcodefromlineparity<br>
staticvoidnand_trans_result(u_charreg2,u_charreg3,u_char*ecc_code)<br>
{<br>
u_chara,b,i,tmp1,tmp2;</p>
<p> /*Initializevariables*/<br>
a=b=0x80;<br>
tmp1=tmp2=0;</p>
<p> /*CalculatefirstECCbyte*/<br>
for(i=0;i<4;i++)<br>
{<br>
if(reg3&a) /*LP15,13,11,9-->ecc_code[0]*/<br>
tmp1|=b;<br>
b>>=1;<br>
if(reg2&a) /*LP14,12,10,8-->ecc_code[0]*/<br>
tmp1|=b;<br>
b>>=1;<br>
a>>=1;<br>
}</p>
<p> /*CalculatesecondECCbyte*/<br>
b=0x80;<br>
for(i=0;i<4;i++)<br>
{<br>
if(reg3&a) /*LP7,5,3,1-->ecc_code[1]*/<br>
tmp2|=b;<br>
b>>=1;<br>
if(reg2&a) /*LP6,4,2,0-->ecc_code[1]*/<br>
tmp2|=b;<br>
b>>=1;<br>
a>>=1;<br>
}</p>
<p> /*StoretwooftheECCbytes*/<br>
ecc_code[0]=tmp1;<br>
ecc_code[1]=tmp2;<br>
}</p>
<p> // Calculate3byteECCcodefor256byteblock<br>
voidnand_calculate_ecc(constu_char*dat,u_char*ecc_code)<br>
{<br>
u_charidx,reg1,reg2,reg3;<br>
intj;</p>
<p> /*Initializevariables*/<br>
reg1=reg2=reg3=0;<br>
ecc_code[0]=ecc_code[1]=ecc_code[2]=0;</p>
<p> /*Buildupcolumnparity*/<br>
for(j=0;j<256;j++)<br>
{</p>
<p> /*GetCP0-CP5fromtable*/<br>
idx=nand_ecc_precalc_table[dat[j]];<br>
reg1^=(idx&0x3f);</p>
<p> /*AllbitXOR=1?*/<br>
if(idx&0x40){<br>
reg3^=(u_char)j;<br>
reg2^=~((u_char)j);<br>
}<br>
}</p>
<p> /*Createnon-invertedECCcodefromlineparity*/<br>
nand_trans_result(reg2,reg3,ecc_code);</p>
<p> /*CalculatefinalECCcode*/<br>
ecc_code[0]=~ecc_code[0];<br>
ecc_code[1]=~ecc_code[1];<br>
ecc_code[2]=((~reg1)<<2)|0x03;<br>
}</p>
<p> // Detectandcorrecta1biterrorfor256byteblock<br>
intnand_correct_data(u_char*dat,u_char*read_ecc,u_char*calc_ecc)<br>
{<br>
u_chara,b,c,d1,d2,d3,add,bit,i;</p>
<p> /*Doerrordetection*/<br>
d1=calc_ecc[0]^read_ecc[0];<br>
d2=calc_ecc[1]^read_ecc[1];<br>
d3=calc_ecc[2]^read_ecc[2];</p>
<p> if((d1|d2|d3)==0)<br>
{<br>
/*Noerrors*/<br>
return0;<br>
}<br>
else<br>
{<br>
a=(d1^(d1>>1))&0x55;<br>
b=(d2^(d2>>1))&0x55;<br>
c=(d3^(d3>>1))&0x54;</p>
<p> /*Foundandwillcorrectsinglebiterrorinthedata*/<br>
if((a==0x55)&&(b==0x55)&&(c==0x54))<br>
{<br>
c=0x80;<br>
add=0;<br>
a=0x80;<br>
for(i=0;i<4;i++)<br>
{<br>
if(d1&c)<br>
add|=a;<br>
c>>=2;<br>
a>>=1;<br>
}<br>
c=0x80;<br>
for(i=0;i<4;i++)<br>
{<br>
if(d2&c)<br>
add|=a;<br>
c>>=2;<br>
a>>=1;<br>
}<br>
bit=0;<br>
b=0x04;<br>
c=0x80;<br>
for(i=0;i<3;i++)<br>
{<br>
if(d3&c)<br>
bit|=b;<br>
c>>=2;<br>
b>>=1;<br>
}<br>
b=0x01;<br>
a=dat[add];<br>
a^=(b<<bit);<br>
dat[add]=a;<br>
return1;<br>
}<br>
else<br>
{<br>
i=0;<br>
while(d1)<br>
{<br>
if(d1&0x01)<br>
++i;<br>
d1>>=1;<br>
}<br>
while(d2)<br>
{<br>
if(d2&0x01)<br>
++i;<br>
d2>>=1;<br>
}<br>
while(d3)<br>
{<br>
if(d3&0x01)<br>
++i;<br>
d3>>=1;<br>
}<br>
if(i==1)<br>
{<br>
/*ECCCodeErrorCorrection*/<br>
read_ecc[0]=calc_ecc[0];<br>
read_ecc[1]=calc_ecc[1];<br>
read_ecc[2]=calc_ecc[2];<br>
return2;<br>
}<br>
else<br>
{<br>
/*UncorrectableError*/<br>
return-1;<br>
}<br>
}<br>
}</p>
<p> /*Shouldneverhappen*/<br>
return-1;<br>
}</p>
</div>
</div>