免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 7627 | 回复: 22
打印 上一主题 下一主题

关于nand_ecc.c的菜鸟级问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-06-24 14:19 |只看该作者 |倒序浏览
这个文件代码不多

我刚了解到256+3(24bit)再往代码里去就不懂了

1:第1个结构体(里面定义了256个)用来干吗的啊,看不懂...
(再有问题再编辑近来吧~)

请各位大牛谁了解的给点指示吧~给个网址也行~我搜了不少次了,对于nand_ecc就那一篇分析的,还看不懂...

论坛徽章:
0
2 [报告]
发表于 2008-06-24 14:36 |只看该作者

NAND FLASH ECC校验原理与实现

作者:龙林 EMAIL:dragon_hn@sohu.com WEB:www.dragon-2008.com

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算法的实现
  1.   static const u_char nand_ecc_precalc_table[] =
  2.   {
  3.     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
  4.     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
  5.     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
  6.     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
  7.     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
  8.     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
  9.     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
  10.     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
  11.     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
  12.     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
  13.     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
  14.     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
  15.     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
  16.     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
  17.     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
  18.     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
  19.   };

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

  24.     /* Initialize variables */
  25.     a = b = 0x80;
  26.     tmp1 = tmp2 = 0;

  27.     /* Calculate first ECC byte */
  28.     for (i = 0; i < 4; i++)
  29.     {
  30.       if (reg3 & a)    /* LP15,13,11,9 --> ecc_code[0] */
  31.         tmp1 |= b;
  32.       b >>= 1;
  33.       if (reg2 & a)    /* LP14,12,10,8 --> ecc_code[0] */
  34.         tmp1 |= b;
  35.       b >>= 1;
  36.       a >>= 1;
  37.     }

  38.     /* Calculate second ECC byte */
  39.     b = 0x80;
  40.     for (i = 0; i < 4; i++)
  41.     {
  42.       if (reg3 & a)    /* LP7,5,3,1 --> ecc_code[1] */
  43.         tmp2 |= b;
  44.       b >>= 1;
  45.       if (reg2 & a)    /* LP6,4,2,0 --> ecc_code[1] */
  46.         tmp2 |= b;
  47.       b >>= 1;
  48.       a >>= 1;
  49.     }

  50.     /* Store two of the ECC bytes */
  51.     ecc_code[0] = tmp1;
  52.     ecc_code[1] = tmp2;
  53.   }

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

  59.     /* Initialize variables */
  60.     reg1 = reg2 = reg3 = 0;
  61.     ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;

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

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

  68.       /* All bit XOR = 1 ? */
  69.       if (idx & 0x40) {
  70.         reg3 ^= (u_char) j;
  71.         reg2 ^= ~((u_char) j);
  72.       }
  73.     }

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

  76.     /* Calculate final ECC code */
  77.     ecc_code[0] = ~ecc_code[0];
  78.     ecc_code[1] = ~ecc_code[1];
  79.     ecc_code[2] = ((~reg1) << 2) | 0x03;
  80.   }

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

  85.     /* Do error detection */
  86.     d1 = calc_ecc[0] ^ read_ecc[0];
  87.     d2 = calc_ecc[1] ^ read_ecc[1];
  88.     d3 = calc_ecc[2] ^ read_ecc[2];

  89.     if ((d1 | d2 | d3) == 0)
  90.     {
  91.       /* No errors */
  92.       return 0;
  93.     }
  94.     else
  95.     {
  96.       a = (d1 ^ (d1 >> 1)) & 0x55;
  97.       b = (d2 ^ (d2 >> 1)) & 0x55;
  98.       c = (d3 ^ (d3 >> 1)) & 0x54;

  99.       /* Found and will correct single bit error in the data */
  100.       if ((a == 0x55) && (b == 0x55) && (c == 0x54))
  101.       {
  102.         c = 0x80;
  103.         add = 0;
  104.         a = 0x80;
  105.         for (i=0; i<4; i++)
  106.         {
  107.           if (d1 & c)
  108.             add |= a;
  109.           c >>= 2;
  110.           a >>= 1;
  111.         }
  112.         c = 0x80;
  113.         for (i=0; i<4; i++)
  114.         {
  115.           if (d2 & c)
  116.             add |= a;
  117.           c >>= 2;
  118.           a >>= 1;
  119.         }
  120.         bit = 0;
  121.         b = 0x04;
  122.         c = 0x80;
  123.         for (i=0; i<3; i++)
  124.         {
  125.           if (d3 & c)
  126.             bit |= b;
  127.           c >>= 2;
  128.           b >>= 1;
  129.         }
  130.         b = 0x01;
  131.         a = dat[add];
  132.         a ^= (b << bit);
  133.         dat[add] = a;
  134.         return 1;
  135.       }
  136.       else
  137.       {
  138.         i = 0;
  139.         while (d1)
  140.         {
  141.           if (d1 & 0x01)
  142.             ++i;
  143.           d1 >>= 1;
  144.         }
  145.         while (d2)
  146.         {
  147.           if (d2 & 0x01)
  148.             ++i;
  149.           d2 >>= 1;
  150.         }
  151.         while (d3)
  152.         {
  153.           if (d3 & 0x01)
  154.             ++i;
  155.           d3 >>= 1;
  156.         }
  157.         if (i == 1)
  158.         {
  159.           /* ECC Code Error Correction */
  160.           read_ecc[0] = calc_ecc[0];
  161.           read_ecc[1] = calc_ecc[1];
  162.           read_ecc[2] = calc_ecc[2];
  163.           return 2;
  164.         }
  165.         else
  166.         {
  167.           /* Uncorrectable Error */
  168.           return -1;
  169.         }
  170.       }
  171.     }

  172.     /* Should never happen */
  173.     return -1;
  174.   }
复制代码

[ 本帖最后由 bitmilong 于 2008-6-24 14:56 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2008-06-24 14:40 |只看该作者
5555555看到好感动ING~ 这个图我盯了一上午了 看不懂~~(网上好象我就搜出这唯一一篇介绍的详细的文章~为啥代码不注释,,,,,,)


头儿终于不让我干自己的事情了...我的驱动要暂时放放了,得先把这块儿看明白...


这个图我看不明白  MR BIT  这图需要怎么样才能看懂?那下面代码里的第1个256元素的树组干吗的啊~?

[ 本帖最后由 jn200002 于 2008-6-24 14:46 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2008-06-24 14:55 |只看该作者

回复 #3 jn200002 的帖子

第一個圖就是那三個字節,P* 及 P*' 表示每一個位起個名字
第二三圖就是列校驗時 P* 及 P*' 是如何計算得來
第四個圖就是行校驗時 P* 及 P*' 是如何計算得來

D*就是第幾位(bit0~7)

论坛徽章:
0
5 [报告]
发表于 2008-06-24 15:02 |只看该作者
3Q啦~我再继续看~

图3是列校验,那它把行校验标出来干吗~?没用的吗?

如果说校验的话,如果算出P4 P2 P1及 P4' P2' P1'这6位(NAND控制器在写入时生成)与从flash中读入时比较 那实际P4 P2 P1.. 它们当中是只存了1或者0么?

[ 本帖最后由 jn200002 于 2008-6-24 15:17 编辑 ]

评分

参与人数 1可用积分 +9 收起 理由
bitmilong + 9 鼓勵新人多多學習交流

查看全部评分

论坛徽章:
0
6 [报告]
发表于 2008-06-24 15:10 |只看该作者
大家都研究得这么深入啊,令我感到很惭愧

论坛徽章:
0
7 [报告]
发表于 2008-06-24 15:13 |只看该作者
原帖由 sep 于 2008-6-24 15:10 发表
大家都研究得这么深入啊,令我感到很惭愧


sep兄,太扯了

這裏都是菜鳥,現在

论坛徽章:
0
8 [报告]
发表于 2008-06-24 15:19 |只看该作者
原帖由 sep 于 2008-6-24 15:10 发表
大家都研究得这么深入啊,令我感到很惭愧


还记得当时我在这提第1个问题的时候 你要准备去搞 MIPS了... 我记得我最后一个问题是: MIPS是什么DONGDONG?然后就没信儿了

论坛徽章:
0
9 [报告]
发表于 2008-06-24 15:23 |只看该作者

回复 #7 bitmilong 的帖子

我看明白这图了~ 第4张图画的多余... 第3张不已经都画全了吗...又或者~我还是没能看懂吧...

哈哈 多谢 MR.BIT  那个256的数组用来干吗呢~?

论坛徽章:
0
10 [报告]
发表于 2008-06-24 15:37 |只看该作者
原帖由 jn200002 于 2008-6-24 15:19 发表


还记得当时我在这提第1个问题的时候 你要准备去搞 MIPS了... 我记得我最后一个问题是: MIPS是什么DONGDONG?然后就没信儿了

哎。其实根本不想搞什么劳什子MIPS,但是项目是要用MIPS体系的cpu
因为对于MIPS体系不熟悉,看提供过来的SDK包里的源码,很多地方很难想得通,具体可以看我的悬赏帖
这扯的太远了,当友情一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP