NAND Flash ECC 校验原理与实现

<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&lt;4;i++)<br>
    {<br>
      if(reg3&amp;a)   /*LP15,13,11,9--&gt;ecc_code[0]*/<br>
        tmp1|=b;<br>
      b&gt;&gt;=1;<br>
      if(reg2&amp;a)   /*LP14,12,10,8--&gt;ecc_code[0]*/<br>
        tmp1|=b;<br>
      b&gt;&gt;=1;<br>
      a&gt;&gt;=1;<br>
    }</p>
<p>    /*CalculatesecondECCbyte*/<br>
    b=0x80;<br>
    for(i=0;i&lt;4;i++)<br>
    {<br>
      if(reg3&amp;a)   /*LP7,5,3,1--&gt;ecc_code[1]*/<br>
        tmp2|=b;<br>
      b&gt;&gt;=1;<br>
      if(reg2&amp;a)   /*LP6,4,2,0--&gt;ecc_code[1]*/<br>
        tmp2|=b;<br>
      b&gt;&gt;=1;<br>
      a&gt;&gt;=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&lt;256;j++)<br>
    {</p>
<p>      /*GetCP0-CP5fromtable*/<br>
      idx=nand_ecc_precalc_table[dat[j]];<br>
      reg1^=(idx&amp;0x3f);</p>
<p>      /*AllbitXOR=1?*/<br>
      if(idx&amp;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)&lt;&lt;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&gt;&gt;1))&amp;0x55;<br>
      b=(d2^(d2&gt;&gt;1))&amp;0x55;<br>
      c=(d3^(d3&gt;&gt;1))&amp;0x54;</p>
<p>      /*Foundandwillcorrectsinglebiterrorinthedata*/<br>
      if((a==0x55)&amp;&amp;(b==0x55)&amp;&amp;(c==0x54))<br>
      {<br>
        c=0x80;<br>
        add=0;<br>
        a=0x80;<br>
        for(i=0;i&lt;4;i++)<br>
        {<br>
          if(d1&amp;c)<br>
            add|=a;<br>
          c&gt;&gt;=2;<br>
          a&gt;&gt;=1;<br>
        }<br>
        c=0x80;<br>
        for(i=0;i&lt;4;i++)<br>
        {<br>
          if(d2&amp;c)<br>
            add|=a;<br>
          c&gt;&gt;=2;<br>
          a&gt;&gt;=1;<br>
        }<br>
        bit=0;<br>
        b=0x04;<br>
        c=0x80;<br>
        for(i=0;i&lt;3;i++)<br>
        {<br>
          if(d3&amp;c)<br>
            bit|=b;<br>
          c&gt;&gt;=2;<br>
          b&gt;&gt;=1;<br>
        }<br>
        b=0x01;<br>
        a=dat[add];<br>
        a^=(b&lt;&lt;bit);<br>
        dat[add]=a;<br>
        return1;<br>
      }<br>
      else<br>
      {<br>
        i=0;<br>
        while(d1)<br>
        {<br>
          if(d1&amp;0x01)<br>
            ++i;<br>
          d1&gt;&gt;=1;<br>
        }<br>
        while(d2)<br>
        {<br>
          if(d2&amp;0x01)<br>
            ++i;<br>
          d2&gt;&gt;=1;<br>
        }<br>
        while(d3)<br>
        {<br>
          if(d3&amp;0x01)<br>
            ++i;<br>
          d3&gt;&gt;=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>

你可能感兴趣的:(Flash)