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,如下图所示:
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 = ; /* Calculate first ECC byte */ ; i < ; i++) { if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ tmp1 |= b; b >>= ; if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ tmp1 |= b; b >>= ; a >>= ; } /* Calculate second ECC byte */ b = 0x80; ; i < ; i++) { if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ tmp2 |= b; b >>= ; if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ tmp2 |= b; b >>= ; a >>= ; } /* Store two of the ECC bytes */ ecc_code[] = tmp1; ecc_code[] = 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 = ; ecc_code[] = ecc_code[] = ecc_code[] = ; /* Build up column parity */ ; j < ; 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[] = ~ecc_code[]; ecc_code[] = ~ecc_code[]; ecc_code[] = ((~reg1) << ) | 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[] ^ read_ecc[]; d2 = calc_ecc[] ^ read_ecc[]; d3 = calc_ecc[] ^ read_ecc[]; ) { /* No errors */ ; } else { a = (d1 ^ (d1 >> )) & 0x55; b = (d2 ^ (d2 >> )) & 0x55; c = (d3 ^ (d3 >> )) & 0x54; /* Found and will correct single bit error in the data */ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { c = 0x80; add = ; a = 0x80; ; i<; i++) { if (d1 & c) add |= a; c >>= ; a >>= ; } c = 0x80; ; i<; i++) { if (d2 & c) add |= a; c >>= ; a >>= ; } bit = ; b = 0x04; c = 0x80; ; i<; i++) { if (d3 & c) bit |= b; c >>= ; b >>= ; } b = 0x01; a = dat[add]; a ^= (b << bit); dat[add] = a; ; } else { i = ; while (d1) { if (d1 & 0x01) ++i; d1 >>= ; } while (d2) { if (d2 & 0x01) ++i; d2 >>= ; } while (d3) { if (d3 & 0x01) ++i; d3 >>= ; } ) { /* ECC Code Error Correction */ read_ecc[] = calc_ecc[]; read_ecc[] = calc_ecc[]; read_ecc[] = calc_ecc[]; ; } else { /* Uncorrectable Error */ ; } } } /* Should never happen */ ; }
NAND FLASH ECC校验原理与实现的更多相关文章
- ECC校验原理以及在Nand Flash中的应用
本篇文章主要介绍ECC基本原理以及在Nand Flash中的应用,本文记录自己对ECC校验原理的理解和学习. ECC介绍 ECC,全称为Error Correcting Code, ...
- Nand Flash 控制器工作原理
对 Nand Flash 存储芯片进行操作, 必须通过 Nand Flash 控制器的专用寄存器才能完成.所以,不能对 Nand Flash 进行总线操作.而 Nand Flash 的写操作也必须块方 ...
- Nand flash 芯片工作原理
Nand flash 芯片型号为 Samsung K9F1208U0B,数据存储容量为 64MB,采用块页式存储管理.8 个 I/O 引脚充当数据.地址.命令的复用端口. 芯片内部存储布局及存储操作特 ...
- NAND FLASH 原理
NAND FLASH 原理 http://www.360doc.com/content/12/0522/21/21412_212888167.shtml 闪存保存数据的原理: 与DRAM以电容作为存储 ...
- nand flash详解及驱动编写
https://www.crifan.com/files/doc/docbook/linux_nand_driver/release/html/linux_nand_driver.html#nand_ ...
- 如何编写linux下nand flash驱动-4
2. 软件方面 如果想要在Linux下编写Nand Flash驱动,那么就先要搞清楚Linux下,关于此部分的整个框架.弄明白,系统是如何管理你的nand flash的,以及,系统都帮你做 ...
- DM365视频处理流程/DM368 NAND Flash启动揭秘
出自http://blog.csdn.net/maopig/article/details/7029930 DM365的视频处理涉及到三个相关处理器,分别是视频采集芯片.ARM处理器和视频图像协处理器 ...
- Nand flash 三种类型SLC,MLC,TLC【转】
转自:https://blog.csdn.net/fc34235/article/details/79584758 转载自:http://diy.pconline.com.cn/750/7501340 ...
- DM368 NAND Flash启动
概要: 本文介绍了DM368 NAND Flash启动的原理,并且以DM368 IPNC参考设计软件为例,介绍软件是如何配合硬件实现启动的. 芯片上电后是如何启动实现应用功能的?这是许多工程师在看到 ...
随机推荐
- fs读取某个json文件的数据
/** * Created by Administrator on 2016/7/12. * 流数据 */ var fs = require('fs'); var stream = fs.create ...
- caret彻底的理解css的三角形【通过border】
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- EC读书笔记系列之8:条款13、14、15
条款13 以对象管理资源 记住: ★为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放 ★两个常被使用的RAII classes分别是tr1::shared_ptr和aut ...
- js数组与对象的一些区别。
之前以为js对象即数组,今天用length取对象的长度老是undefined,用concat合并两个对象也不行,于是网上找了一下, 获取对象的长度 function length(o) { var c ...
- HTTP POST和GET的区别[转]
http://www.cppblog.com/woaidongmao/archive/2008/05/29/51476.aspx 1.HTTP 只有POST和GET 两种命令模式: 2.POST是被设 ...
- onload ready
确保在 <body> 元素的onload事件中没有注册函数,否则不会触发$(document).ready()事件. 可以在同一个页面中无限次地使用$(document).ready()事 ...
- ALOS卫星介绍
ALOS卫星介绍 作者:ALOS 文章来源:ALOS 点击数: 更新时间:2013-6-21 摘要:日本地球观测卫星计划主要包括2个系列:大气和海洋观测系列以及陆地观测系列.先进对地 ...
- 浅谈POSIX线程的私有数据
当线程中的一个函数需要创建私有数据时,该私有数据在对函数的调用之间保持一致,数据能静态地分配在存储器中,当我们采用命名范围也许可以实现它使用在函数或是文件(静态),或是全局(EXTERN).但是当涉及 ...
- spring bean之间的关系:继承;依赖
概要: ' 继承Bean配置 Spring同意继承bean的配置,被继承的bean称为父bean,继承这个父Bean的Bean称为子Bean 子Bean从父Bean中继承配置,包含Bean的属性配置 ...
- USB OTG简单介绍
1 引言 随着USB2.0版本号的公布,USB越来越流行,已经成为一种标准接口.如今,USB支持三种传输速率:低速(1.5Mb/s).全速(12Mb/s)和快速(480Mb/s),四种传输类型:块传输 ...