最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【转】关于“NAND FLASH ECC校验原理与实现”中部分代码的理解

Flash crifan 2022浏览 0评论

【转】关于“NAND FLASH ECC校验原理与实现”中部分代码的理解

nand_ecc.c详解(待续)

文件:NAND_ECC_Algoritalm.PDF
大小:166KB
下载:下载

首先感谢www.mcuos.comwonder sky对我的指导.本帖主要是对话记录.

代码中的ECC_CODE顺序和文中的ECC图示并不相同,
代码中的ECC_CODE[0]对应的是P1024~P128′,
ECC_CODE[1]
对应的是P64~P8′

检验代码如下:
#include <iostream.h>
#include <stdlib.h>

typedef   unsigned char u_char;

u_char ecc_code[3];

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
};

void nand_trans_result(u_char reg2,u_char reg3,u_char *ecc_code)
{
u_char a,b,i,tmp1,tmp2;
a=b=0x80;
tmp1=tmp2=0;
for(i = 0;i < 4;i++)
{
       if(reg3&a)
         tmp1|=b;
       b>>=1;
       if(reg2&a)
         tmp1|=b;
       b>>=1;
       a>>=1;
}

b=0x80;
for(i = 0;i < 4;i++)
{
       if(reg3&a)
         tmp2|=b;
       b>>=1;
       if(reg2&a)
         tmp2|=b;
       b>>=1;
       a>>=1;
}

ecc_code[0]=tmp1;
ecc_code[1]=tmp2;

}

void nand_calculate_ecc(u_char *dat,u_char*ecc_code)
{
u_char idx,reg1,reg2,reg3;
int j;
reg1=reg2=reg3=0;
ecc_code[0]=ecc_code[1]=ecc_code[2]=0;
for(j=0;j<256;j++)
{
       idx=nand_ecc_precalc_table[dat[j]];
       reg1^=(idx&0x3f);
       if(idx&0x40)
       {
         reg3^=(u_char)j;
         reg2 ^=~((u_char)j);
       }
}
ecc_code[2]=reg1;
nand_trans_result(reg2,reg3,ecc_code);
cout<<"Org_Cal -> Ecc_code are :n"
       <<(int)ecc_code[0]<<endl
       <<(int)ecc_code[1]<<endl
       <<(int)ecc_code[2]<<endl;

}

void hard_cal(u_char *dat,u_char*ecc_code)
{
u_char idx,reg1,reg2,reg3;
int j;
reg1=reg2=reg3=0;
ecc_code[0]=ecc_code[1]=ecc_code[2]=0;
for(j=0;j<256;j++)
{
       idx=nand_ecc_precalc_table[dat[j]];
       reg1^=(idx&0x3f);
}
ecc_code[2]=reg1;
u_char cal1=0,cal2=0;
int Move=0,count=1;

while(count<=128)
{
       int i=0;
       cal1=0;
       cal2=0;
       while(i<256)
       {
         for(int j=0;j<count;j++)
         {
            if(nand_ecc_precalc_table[dat[i+j]]&0x40)
                   cal1^=1;//P’
            if(nand_ecc_precalc_table[dat[i+count+j]]&0x40)
                   cal2^=1;//P
         }
         i+=2*count;
       }
       if(Move<8)
       {
         ecc_code[0]|=cal1<<(Move);
         ecc_code[0]|=cal2<<(Move+1);
       }
       else
       {
         ecc_code[1]|=cal1<<(Move-8);
         ecc_code[1]|=cal2<<((Move-8)+1);
       }
       count*=2;
       Move+=2;
}

cout<<"hard cal -> Ecc_code are :n"
       <<(int)ecc_code[0]<<endl
       <<(int)ecc_code[1]<<endl
       <<(int)ecc_code[2]<<endl;
}

/*
ECC_CODE[0]
实际保存的是高位的P1024,P1024′,P512,P512′,P256,P256′,P128,P128′
ECC_CODE[1]
保存的是
P64,P64′,P32,P32′,P16,P16′,P8,P8′
*/
int main()
{
u_char dat[256];
for(int i=0;i<256;i++)
       dat
= rand()%256;
hard_cal(dat,ecc_code);
nand_calculate_ecc(dat,ecc_code);
return 1;
}

VC6下编译通过,其中的hard_cal是按照图示的顺序摆放ECC,按照定义来进行计算的,结果两者的ECC_CODE颠倒,可以证明之前的结论正确。

这样的Reg3中从高位到地位摆放的是P1024~P8的值。
为什么这些位的值可以表示P1024~P8的值呢,看看之前的
if(idx&0x40)
{
reg3^=(u_char)j;
reg2 ^=~((u_char)j);
}

idx&0x40,因为行校验初始为0,所以只有在idx&0x40=1的情况,即某行的行校验为1的时候,进行异或才能使行校验的值发生改变。
reg3^=(u_char)j
,这句代码可以记住这些行校验的值,
首先,81632……1024对应的字节数为1,2,4……128
对于P8,进行计算的行号为135……,即所有的奇数号,这些数字的二进制表示的特征是第一位一定为1
对于P16,计算的行号为2367……,这些数字的二机制表示的特征是第二位一定为1
以此类推,每个行校验的P都有一个对应的二进制位,暂时叫做特征位吧,
结合前面所说的某行的行校验为1的时候,进行异或才能使行校验的值发生改变
可以得到reg3各位就是对应的行校验。

reg3保存的是p1024   ~ p8 的值
reg2
保存的是p1024′ ~ p8′的值

j是原始data的下标,也就是原始数据的行号,reg3 ^= (uchar) j;取的就是第几行的如果2,3行对应的是P16那么 2,3取反 就是0,1 也就是P16′ 呵呵,非常感谢了,经过你耐心指导~算法这块儿是明白一些了. 然后对照1BIT校验的其他的yaffs_eccwince ecc都是一样的.

然后在其余的一些时间里,看了S3C2410A的手册(中文第6)关于nandflash控制器后,它的硬件ECC512b校验1,3个字节, wince ecc是硬件ECC 算法是判断那几种情况就可以,linux ecc要简单些.揭过不提.
nand_ecc
yaffs_ecc 从根本上就是一样的(个人认为)

转载请注明:在路上 » 【转】关于“NAND FLASH ECC校验原理与实现”中部分代码的理解

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
83 queries in 0.168 seconds, using 22.16MB memory