一文诠释NandFlash ECC校验原理与实现

大家应该都在用u盘,而u盘中的存储芯片就是nandflash,你买的64g的u盘,实际并没有64g,其中一个原因就是存在坏块。
因为工艺和其他方面的原因,不能保证nandflash不存在坏块,因此就需要“挑选出坏块”。
本文就为大家讲述一下用于nandflash的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,如下图所示:
ecc的列校验和生成规则如下图所示:
用数学表达式表示为:
p4=d7(+)d6(+)d5(+)d4p4`=d3(+)d2(+)d1(+)d0p2=d7(+)d6(+)d3(+)d2p2`=d5(+)d4(+)d1(+)d0p1=d7(+)d5(+)d3(+)d1p1`=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 paritystatic 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 blockvoid 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 blockint 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;}
参考文档:
http://blogimg.chinaunix.net/blog/upfile2/080702112233.pdf
免责声明:本文素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。


线性直流稳压电源和开关稳压电源讲解
平安夜将上市全新星空灰版vivo X9,颜值爆表
基于智慧城市中的LED的妙用解析
人工智能时代的生活服务是怎样的
5G无线通信中的索引调制技术研究
一文诠释NandFlash ECC校验原理与实现
今后的Python将如何管理?
什么样的户外电源比较好?
3GPP工作组,一起确认了用于5G商用化的最终技术
创新经济增长点,人工智能接棒开跑
-70℃超低温冰箱解决新冠疫苗运输存储问题
结构仿真:Ansys Mechanical 2023 R1版本的五大新功能
高性能芯片赋能行业发展——先楫半导体惊艳亮相2023杭州电机智造与创新应用峰会
智能硬件投资遇到寒冬,消费者究竟想要怎样
cpu寄存器和存储器的区别
医疗行业正在寻找新技术来筛选和控制大流行的传播
加州理工学院和 NASA 喷气推进实验室开发出弹道发射无人机
职场萌新不恐慌 小A家族商务本助你火力全开
锐尔威视科技新发布高速摄像头其像素高达30万60帧
3898入手iQOO 7全新配置版本,储存翻倍,优势更明显