久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3827|回復: 1
打印 上一主題 下一主題
收起左側

NAND FLASH ECC校驗原理與實現

[復制鏈接]
跳轉到指定樓層
樓主
ID:80436 發表于 2015-5-21 00:14 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式

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;


  }



分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:161913 發表于 2017-1-15 19:15 | 只看該作者
很有用,謝謝。正在做這個,不是很會
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 超碰免费在线观看 | 国产精品99999 | 久久综合一区二区三区 | 第一区在线观看免费国语入口 | 黄色大片观看 | 91热在线 | 久久com| 91精品国产色综合久久 | a级大片 | 亚洲天堂一区二区 | 久久婷婷国产麻豆91 | 我爱操| 国产线视频精品免费观看视频 | 国产精品明星裸体写真集 | 日韩高清av | 青青草一区 | 久久精品国产久精国产 | 999国产视频 | 国产91中文 | 婷婷久久综合 | 国产羞羞视频在线观看 | 国产成人麻豆免费观看 | 精品99久久久久久 | 久久久www成人免费精品 | 一久久久 | 国产精品不卡 | 午夜免费在线电影 | 日韩α片 | 欧美一级免费看 | 国产成人av在线播放 | 免费一二区 | 少妇淫片aaaaa毛片叫床爽 | 国产精品精品视频一区二区三区 | 亚洲国产欧美91 | av一二三区 | 成人在线免费观看视频 | 久久亚洲国产精品 | 精品视频 免费 | 欧美片网站免费 | 91视频进入| 久久综合成人精品亚洲另类欧美 |