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 co
static void nand_trans_result(u_char reg2, u_char reg3,u_char *ecc_co
{
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_co
tmp1 |= b;
b >>= 1;
if (reg2 & a) /* LP14,12,10,8 –> ecc_co
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_co
tmp2 |= b;
b >>= 1;
if (reg2 & a) /* LP6,4,2,0 –> ecc_co
tmp2 |= b;
b >>= 1;
a >>= 1;
}
/* Store two of the ECC bytes */
ecc_co
ecc_co
}
// Calculate 3 byte ECC co
void nand_calculate_ecc (const u_char *dat, u_char *ecc_co
{
u_char idx, reg1, reg2, reg3;
int j;
/* Initialize variables */
reg1 = reg2 = reg3 = 0;
ecc_co
/* 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 co
nand_trans_result(reg2, reg3, ecc_co
/* Calculate final ECC co
ecc_co
ecc_co
ecc_co
}
// Detect and correct a 1 bit error for 256 byte block
int nand_correct_da
{
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 da
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 Co
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;
}