×
单片机 > 单片机程序设计 > 详情

S3C6410使用---21yaffs2的ECC

发布时间:2021-04-22 发布时间:
|

一. 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); //打印而己,不关心

}

这部分主要是校验yaffs_packed_tags2* pt中的结果, sizeof(yaffs_packed_tags2)=4*7=28

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;

};


注意: 这个校验只被 nandmtd2_read_chunk_tags所调用,因为 pt中的数据是存在nand flash的OOB区的,data区的数据在读取时己经被检验过了.

yaffs把OOB区前28个字节也拿来当数据使用了,所以这部分也需要校验.但是nand_flash只会对data区的数据进行校验,所以需要自己写代码来校验这OOB的28个字节


二.校验算法

2. 生成column_parity_table表

#include

#include

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;

}


3.

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;

}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多