NAND FLASH ECC校验原理与实现

来源 http://blog.chinaunix.net/u/24474/showart_257625.html

如果有版权问题, 速告诉我,我立即删除

 

 
 

NAND FLASH ECC校验原理与实现

from: http://www.ednchina.com/blog/lieal/17736/message.aspx

ECC简介   由于NAND Flash的工艺不能保证NAND的Memory Array在其生命周期中保持性能的可靠,因此,在NAND的生产中及使用过程中会产生坏块。为了检测数据的可靠性,在应用NAND Flash的系统中一般都会采用一定的坏区管理策略,而管理坏区的前提是能比较可靠的进行坏区检测。   如果操作时序和电路稳定性不存在问题的话,NAND Flash出错的时候一般不会造成整个Block或是Page不能读取或是全部出错,而是整个Page(例如512Bytes)中只有一个或几个bit出错。   对数据的校验常用的有奇偶校验、CRC校验等,而在NAND Flash处理中,一般使用一种比较专用的校验——ECC。ECC能纠正单比特错误和检测双比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的错误不保证能检测。

ECC原理   ECC一般每256字节原始数据生成3字节ECC校验数据,这三字节共24比特分成两部分:6比特的列校验和16比特的行校验,多余的两个比特置1,如下图所示:

点击看大图

     ECC的列校验和生成规则如下图所示:

点击看大图

点击看大图

  用数学表达式表示为:     P4=D7(+)D6(+)D5(+)D4  P4`=D3(+)D2(+)D1(+)D0     P2=D7(+)D6(+)D3(+)D2  P2`=D5(+)D4(+)D1(+)D0     P1=D7(+)D5(+)D3(+)D1  P1`=D6(+)D4(+)D2(+)D0   这里(+)表示“位异或”操作      ECC的行校验和生成规则如下图所示:

点击看大图

  用数学表达式表示为:     P8 = bit7(+)bit6(+)bit5(+)bit4(+)bit3(+)bit2(+)bit1(+)bit0(+)P8     ……………………………………………………………………………………   这里(+)同样表示“位异或”操作     当往NAND Flash的page中写入数据的时候,每256字节我们生成一个ECC校验和,称之为原ECC校验和,保存到PAGE的OOB(out-of-band)数据区中。   当从NAND Flash中读取数据的时候,每256字节我们生成一个ECC校验和,称之为新ECC校验和。   校验的时候,根据上述ECC生成原理不难推断:将从OOB区中读出的原ECC校验和新ECC校验和按位异或,若结果为0,则表示不存在错(或是出现了 ECC无法检测的错误);若3个字节异或结果中存在11个比特位为1,表示存在一个比特错误,且可纠正;若3个字节异或结果中只存在1个比特位为1,表示 OOB区出错;其他情况均表示出现了无法纠正的错误。

ECC算法的实现   static const u_char nand_ecc_precalc_table[] =   {     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00   };

  // Creates non-inverted ECC code from line parity   static void nand_trans_result(u_char reg2, u_char reg3,u_char *ecc_code)   {     u_char a, b, i, tmp1, tmp2;

    /* Initialize variables */     a = b = 0x80;     tmp1 = tmp2 = 0;

    /* Calculate first ECC byte */     for (i = 0; i < 4; i++)     {       if (reg3 & a)    /* LP15,13,11,9 --> ecc_code[0] */         tmp1 |= b;       b >>= 1;       if (reg2 & a)    /* LP14,12,10,8 --> ecc_code[0] */         tmp1 |= b;       b >>= 1;       a >>= 1;     }

    /* Calculate second ECC byte */     b = 0x80;     for (i = 0; i < 4; i++)     {       if (reg3 & a)    /* LP7,5,3,1 --> ecc_code[1] */         tmp2 |= b;       b >>= 1;       if (reg2 & a)    /* LP6,4,2,0 --> ecc_code[1] */         tmp2 |= b;       b >>= 1;       a >>= 1;     }

    /* Store two of the ECC bytes */     ecc_code[0] = tmp1;     ecc_code[1] = tmp2;   }

  // Calculate 3 byte ECC code for 256 byte block   void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)   {     u_char idx, reg1, reg2, reg3;     int j;

    /* Initialize variables */     reg1 = reg2 = reg3 = 0;     ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;

    /* Build up column parity */     for(j = 0; j < 256; j++)     {

      /* Get CP0 - CP5 from table */       idx = nand_ecc_precalc_table[dat[j]];       reg1 ^= (idx & 0x3f);

      /* All bit XOR = 1 ? */       if (idx & 0x40) {         reg3 ^= (u_char) j;         reg2 ^= ~((u_char) j);       }     }

    /* Create non-inverted ECC code from line parity */     nand_trans_result(reg2, reg3, ecc_code);

    /* Calculate final ECC code */     ecc_code[0] = ~ecc_code[0];     ecc_code[1] = ~ecc_code[1];     ecc_code[2] = ((~reg1) << 2) | 0x03;   }

  // Detect and correct a 1 bit error for 256 byte block   int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)   {     u_char a, b, c, d1, d2, d3, add, bit, i;

    /* Do error detection */     d1 = calc_ecc[0] ^ read_ecc[0];     d2 = calc_ecc[1] ^ read_ecc[1];     d3 = calc_ecc[2] ^ read_ecc[2];

    if ((d1 | d2 | d3) == 0)     {       /* No errors */       return 0;     }     else     {       a = (d1 ^ (d1 >> 1)) & 0x55;       b = (d2 ^ (d2 >> 1)) & 0x55;       c = (d3 ^ (d3 >> 1)) & 0x54;

      /* Found and will correct single bit error in the data */       if ((a == 0x55) && (b == 0x55) && (c == 0x54))       {         c = 0x80;         add = 0;         a = 0x80;         for (i=0; i<4; i++)         {           if (d1 & c)             add |= a;           c >>= 2;           a >>= 1;         }         c = 0x80;         for (i=0; i<4; i++)         {           if (d2 & c)             add |= a;           c >>= 2;           a >>= 1;         }         bit = 0;         b = 0x04;         c = 0x80;         for (i=0; i<3; i++)         {           if (d3 & c)             bit |= b;           c >>= 2;           b >>= 1;         }         b = 0x01;         a = dat[add];         a ^= (b << bit);         dat[add] = a;         return 1;       }       else       {         i = 0;         while (d1)         {           if (d1 & 0x01)             ++i;           d1 >>= 1;         }         while (d2)         {           if (d2 & 0x01)             ++i;           d2 >>= 1;         }         while (d3)         {           if (d3 & 0x01)             ++i;           d3 >>= 1;         }         if (i == 1)         {           /* ECC Code Error Correction */           read_ecc[0] = calc_ecc[0];           read_ecc[1] = calc_ecc[1];           read_ecc[2] = calc_ecc[2];           return 2;         }         else         {           /* Uncorrectable Error */           return -1;         }       }     }

    /* Should never happen */     return -1;   }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值