http://blog.chinaunix.net/uid-26009923-id-3787768.html
一. ECC校验
ECC: error Checking and correct,既能检查错误也能纠正错误.优点是: 速度奇快
缺点是: 只能检查2bit的错误,只能纠正1bit的错误
如果想验证这儿需要打开param.no_tags_ecc=0,默认param.no_tags_ecc=1不进行tags校验.
同时,mkyaffs2image中也要把ECC校验信息加进去,这样才能从nand_flash中读出ECC进行比较.
nandmtd2_read_chunk_tags
--> yaffs_unpack_tags2
-
void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct
yaffs_packed_tags2 *pt, int tags_ecc)
-
{
- enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
-
if (pt->t.seq_number != 0xffffffff && tags_ecc) {
-
struct yaffs_ecc_other ecc;
-
int result;
-
yaffs_ecc_calc_other((unsigned char *)&pt->t, sizeof(struct
yaffs_packed_tags2_tags_only), &ecc);
-
result = yaffs_ecc_correct_other((unsigned char *)&pt->t,
-
sizeof(struct yaffs_packed_tags2_tags_only), &pt->ecc, &ecc);
-
switch (result) {
-
case 0:
-
ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
-
break;
-
case 1:
-
ecc_result = YAFFS_ECC_RESULT_FIXED;
-
break;
-
case -1:
-
ecc_result = YAFFS_ECC_RESULT_UNFIXED;
-
break;
-
default:
-
ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
-
}
-
}
-
yaffs_unpack_tags2_tags_only(t, &pt->t);
-
-
t->ecc_result = ecc_result; //保存校验后的结果,
调用它的函数是要检查的
-
-
yaffs_dump_packed_tags2(pt); //打印而己,不关心
-
yaffs_dump_tags2(t); //打印而己,不关心
- }
-
struct yaffs_packed_tags2_tags_only {
-
unsigned seq_number;
-
unsigned obj_id;
-
unsigned chunk_id;
-
unsigned n_bytes;
-
};
-
struct yaffs_ecc_other {
-
unsigned char col_parity;
-
unsigned line_parity;
-
unsigned line_parity_prime;
-
};
-
struct yaffs_packed_tags2 {
-
struct yaffs_packed_tags2_tags_only t;
-
struct yaffs_ecc_other ecc;
- };
yaffs把OOB区前28个字节也拿来当数据使用了,所以这部分也需要校验.但是nand_flash只会对data区的数据进行校验,所以需要自己写代码来校验这OOB的28个字节
二.校验算法
2. 生成column_parity_table表
-
#include <stdio.h>
-
#include <stdlib.h>
-
unsigned char entry(unsigned char x)
-
{
-
unsigned char b0, b1, b2, b3, b4, b5, b6, b7;
-
unsigned char p4, p2, p1, p4p, p2p, p1p;
-
unsigned char linep;
-
unsigned char result;
-
-
b0 = (x & 0x01) ? 1 : 0;
-
b1 = (x & 0x02) ? 1 : 0;
-
b2 = (x & 0x04) ? 1 : 0;
-
b3 = (x & 0x08) ? 1 : 0;
-
b4 = (x & 0x10) ? 1 : 0;
-
b5 = (x & 0x20) ? 1 : 0;
-
b6 = (x & 0x40) ? 1 : 0;
-
b7 = (x & 0x80) ? 1 : 0;
-
-
p4 = b7 ^ b6 ^ b5 ^ b4; p4p = b3 ^ b2 ^ b1 ^ b0;
-
p2 = b7 ^ b6 ^ b3 ^ b2; p2p = b5 ^ b4 ^ b1 ^ b0;
-
p1 = b7 ^ b5 ^ b3 ^ b1; p1p = b6 ^ b4 ^ b2 ^ b0;
-
-
linep = p1 ^ p1p;
-
-
result = 0;
-
if(p4) result |= 0x80;
-
if(p4p) result |= 0x40;
-
if(p2) result |= 0x20;
-
if(p2p) result |= 0x10;
-
if(p1) result |= 0x08;
-
if(p1p) result |= 0x04;
-
if(linep) result |= 0x01;
-
-
//result >>= 2;
-
//if(linep) result |= 0x40;
-
return result;
-
}
-
-
int main(int argc, char *argv[])
-
{
-
unsigned i;
-
-
printf("const unsigned char column_parity_table[] = {");
-
for(i = 0; i < 256; i++)
-
{
-
if((i & 0xf) == 0) printf("\n");
-
printf("0x%02x, ",entry((unsigned
char) i));
-
}
-
printf("\n};\n");
- }

所以每一个result都是:

2.1校验步骤
a. 通过yaffs_ecc_calc_other生成ECC, 称为new_ecc
b. new_ecc与old_ecc进行异或,如果不一样,则说明出错
c. 类似于二叉树,找到出错位,并进行校正
-
void yaffs_ecc_calc_other(const unsigned char *data, unsigned
n_bytes, struct yaffs_ecc_other *ecc_other) //生成新的ECC
-
{
-
unsigned int i;
-
unsigned char col_parity = 0;
-
unsigned line_parity = 0;
-
unsigned line_parity_prime = 0;
-
unsigned char b;
-
-
for (i = 0; i < n_bytes; i++) {
-
b = column_parity_table[*data++];
- col_parity ^= b;
-
if (b & 0x01) {
-
/* odd number of bits in the byte */
-
line_parity ^= i;
-
line_parity_prime ^= ~i;
-
}
-
-
}
-
-
ecc_other->col_parity = (col_parity >> 2) & 0x3f;
-
ecc_other->line_parity = line_parity;
-
ecc_other->line_parity_prime = line_parity_prime;
- }
-
int yaffs_ecc_correct_other(unsigned char *data, unsigned
n_bytes,
-
struct yaffs_ecc_other *read_ecc, const struct yaffs_ecc_other *test_ecc)
-
{ //与test_ecc比较如果不同则进行校正
-
unsigned char delta_col; /* column parity delta */
-
unsigned delta_line; /* line parity delta */
-
unsigned delta_line_prime; /* line parity delta */
-
unsigned bit;
-
delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
-
delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
-
delta_line_prime = read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
-
if ((delta_col | delta_line | delta_line_prime) == 0)
-
return 0; /* no error */
-
if (delta_line == ~delta_line_prime && (((delta_col
^ (delta_col >> 1)) & 0x15) == 0x15)) {
-
bit = 0; //bit
<0-7>,代表哪一位出错
-
if (delta_col & 0x20)
-
bit |= 0x04;
-
if (delta_col & 0x08)
-
bit |= 0x02;
-
if (delta_col & 0x02)
-
bit |= 0x01;
-
if (delta_line >= n_bytes)
-
return -1;
-
data[delta_line] ^= (1 << bit); //找到出错的位了,把它反转
-
return 1; /* corrected */
-
}
-
if ((hweight32(delta_line) + hweight32(delta_line_prime) + hweight8(delta_col)) == 1) {
-
/* Reccoverable error in ecc */
-
*read_ecc = *test_ecc;
-
return 1; /* corrected */
-
}
-
/* Unrecoverable error */
-
return -1;
- }