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 = ;

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

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

    /* Store two of the ECC bytes */
    ecc_code[] = tmp1;
    ecc_code[] = 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 = ;
    ecc_code[] = ecc_code[] = ecc_code[] = ;

    /* Build up column parity */
    ; j < ; 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[] = ~ecc_code[];
    ecc_code[] = ~ecc_code[];
    ecc_code[] = ((~reg1) << ) | 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[] ^ read_ecc[];
    d2 = calc_ecc[] ^ read_ecc[];
    d3 = calc_ecc[] ^ read_ecc[];

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

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

    /* Should never happen */
    ;
  } 

NAND FLASH ECC校验原理与实现的更多相关文章

  1. ECC校验原理以及在Nand Flash中的应用

         本篇文章主要介绍ECC基本原理以及在Nand Flash中的应用,本文记录自己对ECC校验原理的理解和学习. ECC介绍      ECC,全称为Error Correcting Code, ...

  2. Nand Flash 控制器工作原理

    对 Nand Flash 存储芯片进行操作, 必须通过 Nand Flash 控制器的专用寄存器才能完成.所以,不能对 Nand Flash 进行总线操作.而 Nand Flash 的写操作也必须块方 ...

  3. Nand flash 芯片工作原理

    Nand flash 芯片型号为 Samsung K9F1208U0B,数据存储容量为 64MB,采用块页式存储管理.8 个 I/O 引脚充当数据.地址.命令的复用端口. 芯片内部存储布局及存储操作特 ...

  4. NAND FLASH 原理

    NAND FLASH 原理 http://www.360doc.com/content/12/0522/21/21412_212888167.shtml 闪存保存数据的原理: 与DRAM以电容作为存储 ...

  5. nand flash详解及驱动编写

    https://www.crifan.com/files/doc/docbook/linux_nand_driver/release/html/linux_nand_driver.html#nand_ ...

  6. 如何编写linux下nand flash驱动-4

    2.       软件方面 如果想要在Linux下编写Nand Flash驱动,那么就先要搞清楚Linux下,关于此部分的整个框架.弄明白,系统是如何管理你的nand flash的,以及,系统都帮你做 ...

  7. DM365视频处理流程/DM368 NAND Flash启动揭秘

    出自http://blog.csdn.net/maopig/article/details/7029930 DM365的视频处理涉及到三个相关处理器,分别是视频采集芯片.ARM处理器和视频图像协处理器 ...

  8. Nand flash 三种类型SLC,MLC,TLC【转】

    转自:https://blog.csdn.net/fc34235/article/details/79584758 转载自:http://diy.pconline.com.cn/750/7501340 ...

  9. DM368 NAND Flash启动

    概要: 本文介绍了DM368 NAND Flash启动的原理,并且以DM368  IPNC参考设计软件为例,介绍软件是如何配合硬件实现启动的. 芯片上电后是如何启动实现应用功能的?这是许多工程师在看到 ...

随机推荐

  1. ecshop二次开发之购物车常见问题

    1.ecshop二次开发中保存注册用户购物车数据解决方法:ecshop购物车是数据库中cart表来支持的,在ecshop表中rec_id是编号,user_id是注册用户的id,session_id表示 ...

  2. js点击更多显示更多内容效果

    我写了一个简单的分段显示插件,用法很简单:1,把你要分面显示的内容的容器元素增加一个class=showMoreNChildren,并增加一个自定义属性pagesize="8" 这 ...

  3. C#文本文件或其他文件新内容追加

    以txt文本为例,以下代码实现a.txt文件中追加内容 FileStream mystream = new FileStream("C:\\a.txt", FileMode.Ope ...

  4. 考察printf函数返回值

    最近偶然间见了这样一道题:  #include<stdio.h> int main() { ; printf("%d\n",printf("%d", ...

  5. PHP学习之数据库操作

    PHP数据库操作: 一.连接数据库 mysql_connect() 例:$link=mysql_connent("localhost","root"," ...

  6. gcc编译器对宽字符的识别

    最早是使用VC++工具来学习C++,学的越多就越对VC挡住的我看不见的东西好奇,总想多接触一些开发环境,今日抽空摸索了一下CodeBlocks这个开源的IDE使用方法,配置的编译器是MinGW的gcc ...

  7. Crossing River poj1700贪心

    题目描述:N个人过河,只有一只船,最多只能有两人划船,每个人划船速度不同,船速为最慢的人的速度.输入T为case个数,每个case输入N为人数,接下来一行输入的是每个人过河的时间,都不相同.要求输出N ...

  8. DOM4J读取XML文件

    最近在做DRP的项目,其中涉及到了读取配置文件,用到了DOM4J,由于是刚开始接触这种读取xml文件的技术,好奇心是难免的,于是在网上又找了一些资料,这里就结合找到的资料来谈一下读取xml文件的4中方 ...

  9. eclipse 修改编码

    在Eclipse的开发使用中,我们经常使用的是UTF-8,但是刚刚安装的或者是导入的项目是其他编码的默认是GBK的,这就造成我们的项目乱码,一些中文解析无法查看,对我们的开发造成不便. 工具/原料 E ...

  10. 权威指南学习心得-浏览器中的js

    window对象:表示web了浏览器的一个窗口或窗体(winow属性引用自身) 含有以下属性:location包含Location对象,指定当前显示在窗口中URL,允许脚本往窗口里载入新的URL 含有 ...