NAND FLASH ECC校验原理与实现

发布者:leader4最新更新时间:2016-08-13 来源: eefocus关键字:NAND  FLASH  ECC校验 手机看文章 扫描二维码
随时随地手机看文章
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,如下图所示:

NAND FLASH ECC校验原理与实现 - 咏春 - lwmswun 的博客

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

NAND FLASH ECC校验原理与实现 - 咏春 - lwmswun 的博客

NAND FLASH ECC校验原理与实现 - 咏春 - lwmswun 的博客


  用数学表达式表示为:
    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的行校验和生成规则如下图所示:

NAND FLASH ECC校验原理与实现 - 咏春 - lwmswun 的博客

  用数学表达式表示为:
    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;
  }


关键字:NAND  FLASH  ECC校验 引用地址:NAND FLASH ECC校验原理与实现

上一篇:一个相当详细的MINI2440按键驱动详解
下一篇:将Android移植到FS2410开发板上

推荐阅读最新更新时间:2024-03-16 15:04

分页烧写Flash的多页程序并行自举方法
摘 要:以TMS320VC5410为例,介绍对Am29LV200B Flash存储器进行程序分页烧写以及上电后多页用户程序并行自举的方法。对多页Flash存储器的烧写,须在烧写过程中对已烧写的数据长度进行动态判断,当达到预定烧写长度后对Flash进行换页,然后继续烧写,重复上述换页过程,直到程序烧写完为止。对多页程序的并行自举,在系统上电后,利用TI提供的自举程序,将一个用户自己编写的前导程序载入DSP,利用该前导程序将多页程序载入DSP来实现程序的自举。此方法适用于多种FIash芯片和C5000系列DSP。 关键词:TMS320VC5410 Am29LV200B DSP 多页并行自举 TI公司的DSP芯片TMS320Vc5
[缓冲存储]
STM32L152XX--读写内部Flash
Flash模块组织 存储器被组织为程序存储器模块,数据EEPROM模块和信息块。 程序存储器块分为4 KB的扇区,每个扇区都是进一步分成16页,每页256字节。 程序存储器页面擦除 该操作用于擦除程序存储器中的页面(64个字)。要做到这一点: ●解锁FLASH_PECR寄存器 1.将PEKEY1 = 0x89ABCDEF写入编程/擦除密钥寄存器(FLASH_PEKEYR) 2.将PEKEY2 = 0x02030405写入编程/擦除密钥寄存器(FLASH_PEKEYR) ●解锁程序存储器 ●解锁FLASH_PECR寄存器 1. 将PRGKEY1 = 0x8C9DAEBF写入程序存储器密钥寄存器 (FLASH_
[单片机]
美光推出全球首款 176 层 NAND 移动解决方案,助力 5G 超体验
美光推出全球首款 176 层 NAND 移动解决方案,助力 5G 超快体验 先进的 3D NAND 技术应用于美光移动存储产品,为用户打造丰富流畅的多媒体体验 2021 年 7 月 30 日,中国上海 —— 内存和存储解决方案领先供应商 Micron Technology Inc. (美光科技股份有限公司,纳斯达克股票代码:MU) 今日宣布,公司已开始批量出货全球首款基于 176 层 NAND 技术的通用闪存 UFS 3.1 移动解决方案。该产品为高端旗舰手机量身打造,与前代产品相比可实现高达 75% 的顺序写入和随机读取性能提升 ,从而解锁 5G 潜力 — 只需 9.6 秒即可下载一部 2 小时的 4K 电影 。
[手机便携]
美光推出全球首款 176 层 <font color='red'>NAND</font> 移动解决方案,助力 5G 超体验
ATtiny13 Flash程序存储器
系统内可编程的Flash 程序存储器 ATtiny13具有1K字节的在线编程Flash,用于存放程序指令代码。因为所有的AVR指令为 16 位或 32 位,故而 Flash 组织成 512 x 16 位的形式。 Flash存储器至少可以擦写10,000次。ATtiny13的程序计数器(PC)为9位,因此可以寻址512字的程序存储器空 P97“存储器编程” 详述了如何用SPI接口实现对Flash的串行下载。 常数可以保存于整个程序存储器地址空间( 参考LPM 加载程序存储器指令的说明)。取指与执行时序图请参见 P9“ 指令执行时序”。
[单片机]
ATtiny13 <font color='red'>Flash</font>程序存储器
基于Flash型FPGA的信号源卡设计
摘要:介绍了一种基于Flash型FPGA的多路模拟重信号源设计方法,该系统以ACTEL公司的A3P125VQ100芯片为核心,实现了系统的软硬件结合。它包括数模转换单元、电源模块、多路模拟开关模块以及运算放大单元等,实现了电源独立的、频率可调的、不同波形的多路模拟量信号源。该系统通过编写程序可以产生正弦波、三角波、方波以及直漉波并实现1~500 Hz频率可调。研究的核心内容主要是通过FPGA控制D/A和多路模拟开关,通过D/A产生波形从多路模拟开关中送出,通过拨码开关在1~500 Hz的频率范围内控制选择,并且能够通过示波器观测到相应的频率的波形。 关键词:Flash;FPGA;信号源卡;多路选通;数模转换 0 引言 信号源
[嵌入式]
基于<font color='red'>Flash</font>型FPGA的信号源卡设计
NAND Flash管理算法的设计及实现
  引言   Flash是一种非易失存储器,它在掉电条件下仍然能够长期保持数据。由于它具有容量大、速度快、功耗低、抗震性能好等优点,近几年在U盘、SD卡、SSD硬盘等各种移动存储设备中得到了广泛的应用。本文给出了一款性能优异、成本低廉可用于SD卡的NAND flash控制芯片的设计方法。(本方法也同样适用于其他存储设备。文中集中探讨了一种高效管理物理块的算法,包括逻辑物理地址映射以及spare区的定义,另外,还有双缓冲器优化读写的方法等。   1 Flash简介   1.1 SLC flash与MLC flash的比较   从架构上,flash可以分为SLC(Single-Level-Cell) flash和MLC(Mu
[单片机]
<font color='red'>NAND</font> <font color='red'>Flash</font>管理算法的设计及实现
铠侠日本四日市晶圆厂发生火警,NAND Flash价格或上涨?
今(8)日消息,原名东芝存储器的铠侠(Kioxia)位于日本四日市的晶圆6厂传出火警。 铠侠对客户发出通知,指2020年1月7日上午6点10分,该公司位于日本三重县四日市的Fab6工厂,内部设备发生火警,火势很快被扑灭,没有造成任何人员伤亡,相关的起火原因及工厂生产设备的损害状况,目前仍进行调查与统计中,等相关损害统计资料完成,若对客户的供货造成影响,将会在第一时间内通知。 对于此次铠侠的晶圆厂发生火警,业界推测,因火灾发生在工厂的无室内,可能造成该无尘室短期内无法正常运作,对今年第一季NAND Flash的供货与价格恐多少会有影响。 近段时间以来,全球存储产业意外不断。2019年12月31日,韩国三星电子于华城厂区也发生
[手机便携]
铠侠日本四日市晶圆厂发生火警,<font color='red'>NAND</font> <font color='red'>Flash</font>价格或上涨?
STM32将常量数组定义到FLASH固定地址
方法:static const uint8_t s_acBmpLogo030 __attribute__((at(0X800F000)))={0x80,0xC0,0xC0,0xC0,0xC0,0x80,xxxxxxx} 编译之后可在.map文件看到其分配到的地址 0x0800f000 0x0000005c Data RO 4013 .ARM.__AT_0x0800F000 main.o 这是从调试窗口查看的flash数据
[单片机]
STM32将常量数组定义到<font color='red'>FLASH</font>固定地址
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved