logo资料库

NAND FLASH ECC校验原理与实现.pdf

第1页 / 共9页
第2页 / 共9页
第3页 / 共9页
第4页 / 共9页
第5页 / 共9页
第6页 / 共9页
第7页 / 共9页
第8页 / 共9页
资料共9页,剩余部分请下载后查看
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 算法的实现 显示代码 打印 001 static const u_char nand_ecc_precalc_table[] = 002 { 003 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, 004 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 005 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 006 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 007 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 008 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 009 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 010 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 011 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 012 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
013 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 014 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 015 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 016 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 017 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 018 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 019 }; 020 021 // Creates non-inverted ECC code from line parity 022 static void nand_trans_result(u_char reg2, u_char reg3,u_char *ecc_code) 023 { 024 u_char a, b, i, tmp1, tmp2; 025 026 /* Initialize variables */ 027 a = b = 0x80; 028 tmp1 = tmp2 = 0; 029 030 /* Calculate first ECC byte */ 031 for (i = 0; i < 4; i++) 032 { 033 if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ 034 tmp1 |= b; 035 b >>= 1; 036 if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ 037 tmp1 |= b; 038 b >>= 1; 039 a >>= 1; 040 } 041 042 /* Calculate second ECC byte */
043 b = 0x80; 044 for (i = 0; i < 4; i++) 045 { 046 if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ 047 tmp2 |= b; 048 b >>= 1; 049 if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ 050 tmp2 |= b; 051 b >>= 1; 052 a >>= 1; 053 } 054 055 /* Store two of the ECC bytes */ 056 ecc_code[0] = tmp1; 057 ecc_code[1] = tmp2; 058 } 059 060 // Calculate 3 byte ECC code for 256 byte block 061 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code) 062 { 063 u_char idx, reg1, reg2, reg3; 064 int j; 065 066 /* Initialize variables */ 067 reg1 = reg2 = reg3 = 0; 068 ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; 069 070 /* Build up column parity */ 071 for(j = 0; j < 256; j++) 072 { 073 074 /* Get CP0 - CP5 from table */ 075 idx = nand_ecc_precalc_table[dat[j]]; 076 reg1 ^= (idx & 0x3f); 077 078 /* All bit XOR = 1 ? */
079 if (idx & 0x40) { 080 reg3 ^= (u_char) j; 081 reg2 ^= ~((u_char) j); 082 } 083 } 084 085 /* Create non-inverted ECC code from line parity */ 086 nand_trans_result(reg2, reg3, ecc_code); 087 088 /* Calculate final ECC code */ 089 ecc_code[0] = ~ecc_code[0]; 090 ecc_code[1] = ~ecc_code[1]; 091 ecc_code[2] = ((~reg1) << 2) | 0x03; 092 } 093 094 // Detect and correct a 1 bit error for 256 byte block 095 int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc) 096 { 097 u_char a, b, c, d1, d2, d3, add, bit, i; 098 099 /* Do error detection */ 100 d1 = calc_ecc[0] ^ read_ecc[0]; 101 d2 = calc_ecc[1] ^ read_ecc[1]; 102 d3 = calc_ecc[2] ^ read_ecc[2]; 103 104 if ((d1 | d2 | d3) == 0) 105 { 106 /* No errors */ 107 return 0; 108 } 109 else 110 { 111 a = (d1 ^ (d1 >> 1)) & 0x55; 112 b = (d2 ^ (d2 >> 1)) & 0x55; 113 c = (d3 ^ (d3 >> 1)) & 0x54;
114 115 /* Found and will correct single bit error in the data */ 116 if ((a == 0x55) && (b == 0x55) && (c == 0x54)) 117 { 118 c = 0x80; 119 add = 0; 120 a = 0x80; 121 for (i=0; i<4; i++) 122 { 123 if (d1 & c) 124 add |= a; 125 c >>= 2; 126 a >>= 1; 127 } 128 c = 0x80; 129 for (i=0; i<4; i++) 130 { 131 if (d2 & c) 132 add |= a; 133 c >>= 2; 134 a >>= 1; 135 } 136 bit = 0; 137 b = 0x04; 138 c = 0x80; 139 for (i=0; i<3; i++) 140 { 141 if (d3 & c) 142 bit |= b; 143 c >>= 2; 144 b >>= 1; 145 } 146 b = 0x01; 147 a = dat[add]; 148 a ^= (b << bit);
149 dat[add] = a; 150 return 1; 151 } 152 else 153 { 154 i = 0; 155 while (d1) 156 { 157 if (d1 & 0x01) 158 ++i; 159 d1 >>= 1; 160 } 161 while (d2) 162 { 163 if (d2 & 0x01) 164 ++i; 165 d2 >>= 1; 166 } 167 while (d3) 168 { 169 if (d3 & 0x01) 170 ++i; 171 d3 >>= 1; 172 } 173 if (i == 1) 174 { 175 /* ECC Code Error Correction */ 176 read_ecc[0] = calc_ecc[0]; 177 read_ecc[1] = calc_ecc[1]; 178 read_ecc[2] = calc_ecc[2]; 179 return 2; 180 } 181 else 182 { 183 /* Uncorrectable Error */ 184 return -1;
分享到:
收藏