吕氏春秋8266 发表于 2011-1-13 21:02:05

裸奔程序7(中)-NAND芯片的读写及ECC检验软硬件实现

当我们要对NAND进行读写或复位擦除等操作时,其基本流程如下:
1.      允许片选信号NFCONT寄存器位置0(低电平有效)
2.      传输命令
3.      传输地址
4.      等待操作结束,可以判断NFSTAT位或位为高电平表示操作结束,需注意的时,如果采用位进行判断,我们在允许片选信号后,需向该位写1清0,位由硬件自动清除。
5.      发送命令70,读取操作状态是否成功。
6.      禁止片选信号
具体操作说明,每次操作都需要使能和禁止信号操作。
1.      复位,当我们初始化NAND寄存器后,一般需要复位一次
发送命令0xff
等待操作结束
2.      读取页数据
发送命令0x00
输入列地址(为0)及行地址(从位)
发送命令0x30
等待操作结束
从寄存器NFDATA读取数据
3.      随机读取一页数据
发送命令0x00
输入列地址(为0)及行地址(从位)
发送命令0x30
等待操作结束
发送命令0x05
传送列地址
发送命令0xe0
从寄存器NFDATA读取数据
   个人认为,读取页数据时,是将一页数据都读取到其内部寄存器中,其内部指针为0,当发送随机读取命令和地址只是将其内部指针指向指定位置。读取NFDATA寄存时,其内部指针自动加1.经过程序调试发现,感觉其内部缓冲区大小为4K,也就是说,当我们从NFDATA寄存器读取数据时,读取4K数据后,其内部指针指向0,也就是可以从头再读取,同理,在随机读取数据时,0x05及0xe0命令只是将指针指向指定位置。因此我们可以修改页读取函数,将列地址指向我们需要指向的位置,就可以省两个命令。不过一直没搞明白,其缓冲区大小包括2K页数据和64个字节的SPACE区域,其它数据不知从哪来的。
4.      写页命令
发送命令0x80
传输列地址(为0)及行地址(位)
传输数据
发送命令0x10
等待操作结束
5.      随机写命令
发送命令0x80
传输列地址(为0)及行地址(位)
发送命令0x85
发送列地址
传输数据
发送命令0x10
等待操作结束
6.      块擦除命令
发送命令0x60
发送行地址(位),不需传送列地址,同时,擦除是对整块(共64个页)进
行擦除,故位表示块内某页,需清0
   发送命令0xd0
由于NAND的物理特性,在写操作时,只能将位1反转为0,位0无法反转为位1,故在写操作前,必须保证该页已被擦除,即该页所有位均为1,如不为1,则写操作将不会得到正确的结果,如某页开始位存储如下
NAND 存储:30 04二进制0011 0000 0000 0100[位0无法反转写1]
该位 写值:df 4b二进制1101 1111 0100 1011
其值 结果:10 00二进制0001 0000 0000 0000[位0无法反转写1]
显然得到的10 00不是我们想要存储的字DF 4B。
体会:如果我们程序较大并用DWN下载到NAND中执行时,最好用命令9/2对NAND进行擦除操作,尽量不要有选用有坏块管理命令1,除非你读取程序中也有坏块管理,否则有可能得不到正确的结果,这是我反复测试后得到的体会。

第四节ECC检验
由于NAND的物理特性,不能完全保证数据的正确性,因此必须使用一定的算法对NAND读取的数据进行检验,ECC能纠正1个比特错误和检测2个比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的错误不保证能检测。s3c2440内置了ECC错误检验算法,可硬件实现对数据的检验。
          一、 Ecc算法概论
Flash在读写数据的时候是以页为单位进行的,一页有512/1024/2048个数据,所以可以以512/1024/2048 bit为单位生成校验码。每个数据有8位信息组成,可以把这512/1024/2 048个数据看成n×8的矩阵,这样就可以分别生成行校验码和列校验码来分别校验。
其生成校验码为:6位的列校验信息,2*n位行校验码,其中2^n=字节数,由于K9F2G08,一页数据为2048,故有22位行校验码,需校验数据增加一倍,行校验码只需增加2位
S3c2440ECC校验码组成

其中P4,P41,P2,P21,P1,P11是列校验码,其余为行校验码。
当被校验的数据为512B时,只用到P1~P2048;
当被校验的数据为1024B时,用到了P1~P4096;
当被校验的数据为2048B时,则用到了P1~P8192;
在纠正时,根据P4_1,P2_1,P1_1组成一个字节,即为出错的位。将P8192_1,P4096_1,P2048_1,P1024_1,P512_1,P256_1...P8_1组成一个字,即为出错的字节.
知道哪个字节及哪一位出错后,就可以纠正了。
      一、基本概念
在对2048个字节进行检验时,我们可以将其看成2048X8位的数组,如图:
ECC检验码生成表
                                                                        
列校验码生成规则:
对2048个字节的每一位都分别进行异或,得到D0~D7
举例如下:
对2048字节的第7位进行异或
D7=bit1(7)+bit2(7)+ bit3(7)+bit4(7)……bit2047(7)+bit2048(7)
对2048字节的第0位进行异或
D0=bit1(0)+bit2(0)+ bit3(0)+bit4(0)……bit2047(0)+bit2048(0)

得到D0~D7共8个校验码后,将这8个检验码进行分组
每一步,将其2平分进行异或
P4_1=d4+d5+d6+d7    p4_0=d0+d1+d2+d3
第二步,将其4平分后交差取值进行异或
P2_1=d2+d3+d6+d7   p2_0=d0+d1+d4+d5
第三步,将其8平分后交差取值进行异或
P1_1=d1+d3+d5+d7   p1_0=d0+d2+d4+d6


同理,对2048个字节的每一个字节的8位分别进行异或,得到E1~E2048
举例如下:
第一个字节的8位进行异或)
E1=bit1(7)+bit1(6)+bit1(5) +bit1(4)+bit1(3) +bit1(2)+bit1(1)+bit1(0)
第2048个字节的8位进行异或
E2048=bit2048(7)+bit2048(6)+bit2048(5)+bit2048(4)+
Bit2048(3)+bit2048(2)+bit2048(1)+bit2048(0)

同理,对E1~E2048个校验码进行分组
将其进行2平分后交
P8912_1=E1024+E1025+……+E2047
P8912_0=E0+E1……   +E1023
将其进行2048平分后交差取值进行异或
P8_1=E1+E3+E5+E7+E9   +E2047
P8_0=E0+E2+E6+E8+E10    +E2046
其它同理可得

二、算法实现
说明:
根据异或规则,对n个校验码进行异或时,改变其异或顺序,不影响其结果。
根据异或规则,当对0异或时,其值保持不变,对1异或时,其值改变,也就是说,当En=0时,不改变校验码Px_1或Px_0的值,在求行检验码时,我们就可以不用处理它。
   由于校验码p8~p8192是对2048个校验码En进行分组交差异或所得,也就是说,当En=1是,将改变校验码Px_1或Px_0的值,2048字节将生成22个校验码,将改变11个行检验码的值,同理,将改变3个列校验码的值,也就是说,当2048个字节中有一位改变后,将导致14个校验码的值改变。
2.1.校验表的生成
      由于我们对2048个字节进行校验,每个字节为8位,其值范围为0~255,由于异或顺序不影响异或结果,因此我们可以先生成这0~255每个值的列校验码,其格式如下:

Bit6
Bit5
Bit4
Bit3
Bit2
Bit1
Bit0
En

P4_0
d0+d1+
d2+d3
P4_1
d4+d5+
d6+d7
P2_0
d0+d1+
d4+d5
P2_1
d2+d3+
d6+d7
P1_0
D0+d2+
d4+d6
P1_1
D1+d3+
d5+d7

//生成0~255每个值的列Ecc码,保存在Ecc_Table

Static Unsigned char Ecc_Table
void CreatEccTabe(unsigned char *Ecc_Table)
{
      unsigned int i;
      unsigned char xData;
      for (i=0;i<256;i++)
      {
                xData=0;
                  if(BIT1(i)^BIT3(i)^BIT5(i)^BIT7(i)){xData|=0x1;}//p1_1
                  if(BIT0(i)^BIT2(i)^BIT4(i)^BIT6(i)){xData|=0x2;}//p1_0                           
                  if(BIT2(i)^BIT3(i)^BIT6(i)^BIT7(i)){xData|=0x4;}//p2_1   
                  if(BIT0(i)^BIT1(i)^BIT4(i)^BIT5(i)){xData|=0x8;}//p2_0
                  if(BIT4(i)^BIT5(i)^BIT6(i)^BIT7(i)){xData|=0x10;}//p4_1
                  if(BIT0(i)^BIT1(i)^BIT2(i)^BIT3(i)){xData|=0x20;}//p4_0                           
                  if(BIT0(i)^BIT1(i)^BIT2(i)^BIT3(i)^BIT4(i)^BIT5(i)^BIT6(i)^BIT7(i))                        {
                  xData|=0x40;
                  }
                  Ecc_Table=xData;
      }
}
列校验码生成过程:
读取2048个字节,对每个字节查表Ecc_Table得到该字节的Ecc码,将其异或得所有列校验码
      for(i=0;i<2048;i++)
      {
                j=pData;                           //得到要检验的数值
                byte=Ecc_Table;                      //查表得到ECC结果
                list^=(byte&0x3f);                      //得到列检验码bit6位清零
      }
页: [1]
查看完整版本: 裸奔程序7(中)-NAND芯片的读写及ECC检验软硬件实现