STM32 ECC校验的一些心得

[复制链接]
查看10 | 回复0 | 2021-8-13 18:22:40 | 显示全部楼层 |阅读模式
STM32的FSMC功能支持SRAM,NOR FLASH,NAND FLASH,是非常方便的。
在此写下一些调试使用FMMC调试NAND FLASH的心得及总结,方便以后回顾,也便于大家一起交流学习。
在这里重点写下的是调试ECC这个功能。
使用的NAND FLASH芯片是K9F2G08U0C
芯片大小是2Gbit,也就是容量256MB。一块64页,一页2K字节
一页2048字节,其中,OOB区64字节。
     当然,要能正常使用ECC功能,NAND_FLASH的读写正常是前提。这里不作介绍。要ST公司提供的例子里有NAND_FLASH的读写例子,一般可参照其配置再结合自己实际使用的NAND_FLASH芯片及电路设计修改。保证了能正常读写页功能,以及读写OOB区数据功能,即可继续调试ECC了。以下这段话就是来自STM32FSMC使用手册里关于ECC的介绍

The FSMC NAND Flash controller includes two pieces oferror correction code computation hardware, one for each NANDFlash memory block.
The ECC can be performed forpage sizes of 256, 512, 1024, 2048, 4096 or 8192 bytes,depending on the ECCpage sizeconfigured by the user. Depending on the configured page size, the ECC code will be 22,24, 26, 28, 30 or 32 bits.
To even improve the errorcoverage, the user can read/write the NAND Flash page with a   reduced ECC page size. This ispossible when starting and stopping the ECC computation   after the desired number ofbytes to check. In this case, the ECC code is only calculated for  the bytes written and read.

这里就不讲太官方的介绍了。
比如我要使用ECC功能,每512个字节产生一个ECC数据,这样,当这512字节里出错有一位错误的时候,可以通过ECC来纠正。当然,如果错了几个位,就无法纠错了。虽然当两个位有错,也知道,但不知道是哪两个位出错,也纠正不了。所以,只要关心怎么找出错误,通过ECC怎么纠错。
FSMC的ECC支持每256字节,512字节,1024,。。。8192字节产生一个ECC数据。
调试时使用每512字节产生一个ECC功能。
当写入512个字节时,产生一个ECC数据,然后,再读512个字节的时候,也会产生一个ECC数据,通过这两个数据相异或,产生一个ECC校验结果,通过这个判断结果,就可以分析出有没有错,错在哪里,是错哪一位。当然,知道哪一位错了,也就可以纠正了。

现在具体以实际的NAND_FLASH为例。
K9F2G08U0C这个芯片虽然是每页2048个字节,也就是4 个512字节。按理说直接使用每2048字节产生一个ECC即可校验,这样也方便一些。但因为实际使用中,是把这FLASH当作U盘来使用,并使用了fat32文件系统,将其作扇区处理了。一般扇区单位为512个字节。因此,这里就使用每512个字节产生一个ECC。

FSMC_NANDInitStructure.FSMC_Bank = FSMC_Bank2_NAND;
  FSMC_NANDInitStructure.FSMC_Waitfeature =FSMC_Waitfeature_Enable;
  FSMC_NANDInitStructure.FSMC_MemoryDataWidth =FSMC_MemoryDataWidth_8b;
  FSMC_NANDInitStructure.FSMC_ECC = FSMC_ECC_Enable;
FSMC_NANDInitStructure.FSMC_ECCPageSize = FSMC_ECCPageSize_512Bytes;
  FSMC_NANDInitStructure.FSMC_AddressLowMapping= FSMC_AddressLowMapping_Direct;
  FSMC_NANDInitStructure.FSMC_TCLRSetupTime =0x00;
  FSMC_NANDInitStructure.FSMC_TARSetupTime =0x00;
FSMC_NANDInitStructure.FSMC_CommonSpaceTimingStruct = &p;
  FSMC_NANDInitStructure.FSMC_AttributeSpaceTimingStruct= &p;

  FSMC_NANDInit(&FSMC_NANDInitStructure);

  /* FSMC NAND Bank Cmd Test */
  FSMC_NANDCmd(FSMC_Bank2_NAND, ENABLE);

  初始化主要为上述几句指令:
FSMC_NANDInitStructure.FSMC_ECC =FSMC_ECC_Enable;
FSMC_NANDInitStructure.FSMC_ECCPageSize = FSMC_ECCPageSize_512Bytes;

  然后在读写NAND_FLASH,即可读到ECC数据。

u32 write_ecc;
u32 read_ecc;
for(i=0;i<512;i++)
{
    buffer=i%256;
}

    FSMC_NANDECCCmd(FSMC_Bank2_NAND,ENABLE);
    FSMC_NAND_WritePage(buffer,0,512);
  while(FSMC_GetFlagStatus(FSMC_Bank2_NAND,FSMC_FLAG_FEMPT)==Bit_RESET);
   write_ecc = FSMC_GetECC(FSMC_Bank2_NAND);
   FSMC_NANDECCCmd(FSMC_Bank2_NAND,DISABLE);
//这是写入512个字节时候读ECC.

    FSMC_NANDECCCmd(FSMC_Bank2_NAND,ENABLE);
         FSMC_NAND_ReadPage(read,0,512);
   while(FSMC_GetFlagStatus(FSMC_Bank2_NAND,FSMC_FLAG_FEMPT)==Bit_RESET);
    read_ecc = FSMC_GetECC(FSMC_Bank2_NAND);
    FSMC_NANDECCCmd(FSMC_Bank2_NAND,DISABLE);
//这是读512个时候读取ECC

要保证读取到正确的ECC数据,要在读之前先失能下ECC功能,把ECC数据清零,再使用ECC,然后再读或写NAND_FLASH。再读到相应的ECC。读ECC后记得把ECC失能,以清空ECC数据。
这样就可以读到write_ecc了。当然,这个数据会读到的是0,为什么呢,所以很多时候我们测试数据,都是用比较有规律的数据去测试,下面通过几组数据,来解读下这个ECC的数据分析
for(i=0;i<512;i++)
  {
    buffer=0x11;
  }
ECC: 0


512个字节里,都是0x11的话,ECC数据是0。然后改变其中某个字节的某个位,再去读ECC看。
for(i=0;i<512;i++)
  {
    buffer=0x11;
  }
buffer [0]=0x10;
ECC: 0x55555555
这是改了第一个字节的第一个位。(但习惯上从0开始比较习惯,改了第0个字节第0个位)
for(i=0;i<512;i++)
  {
    buffer=0x11;
  }
buffer [0]=0x13;
ECC:0x55555556
改了第1个位


for(i=0;i<2048;i++)
  {
    buffer=0x11;
  }
buffer [0]=0x15;
ECC:0x55555559
改了第2个位


for(i=0;i<2048;i++)
  {
    buffer=0x11;
  }
buffer [0]=0x19;
ECC:0x5555555a
for(i=0;i<512;i++)
  {
    buffer=0x11;
  }
buffer [511]=0x91;
ECC:0x55aaaaaa;
这里改了第4095个位,也就是(第511个字节的最高位,也就是512个字节里的最高一个位)

好了,有了以上这里数据,就可以开始解读了,就算找不到例子,只要你的NAND_FLASH读写正常了,能把这些看懂了,也就可以使用ECC功能了。

下面对这几个ECC数据进行解读。

解读前先看一下ECC结果寄存器。

5451293632516.jpg

   因为我们设置的是512个字节产生一个ECC。那么有效位是0到23。
也就是前面读到的ECC数据呢,只要低24位就可以了。
当然,从这里还能看出其它数据。最高是8192字节,占了32位,
4096字节占了30位。
这个规律就是从256字节开始,每增一倍字节数,ECC就多占用两个位。
按常理说,只要多一个位,就可以表示多一倍的数据了。但是要表示多一个数据,需要到两个位,那,这里就有点玄机了。
甚至不需要去理解或弄明白它使用是汉明码,什么BCH码,只要看明白下这里,一直可以纠错。因为,不要管它是什么纠错码,就跟着这个规律去理解。
512个字节的ECC用了24位,512个字节共有512*8=4096个位。要表示到4096个数,也就是刚好12位就可以了。所以,因此这里的玄机就是ECC数据里,用了2个位来表示一个位的数据。
这时,再看一下关于STM32 ECC的介绍。
When an erroroccurs during the write operation, this error is either correctable or
uncorrectabledepending on the ECC XOR operation:
● Case of acorrectable error
The ECC XORoperation contains 11-bit data at 1. And each pair parity is 0x10 or
0x01.

忘了说,我们这些测试数据呢,是以写入0x11为主,然后故意改错某一个位,再读出ECC。因为写入全部的是0x11,因此写入时产生的ECC是0x0。那么再将读出来的ECC与0x0异或,得到的,也就是ECC校验结果了。
当错第0个位的时候,校验结果是0x55555555。取低24位,也就是0x555555。

对应24位就是
010101010101010101010101
当错第1个位的时候,校验结果是0x555556(取低24位)
对应24位就是
010101010101010101010110
当错第2个位对应的24位是:
010101010101010101011001
当错第3个位对应的24位是:
010101010101010101011010
…………
当错第4095个位(也就是第511个字节的最高位) 校验结果:0xaaaaaa。
对应24位是:
101010101010101010101010

看到这里,大家估计很容易看出来规律了。
第0个位错误的24位数据解码出来12位就是:0000 00000000,也就是0x0,就是第0个位错误.
第1个位错误的24位数据解码出来12位就是:0000 00000001,也就是0x1,就是第1个位错误.
第2个位错误的24位数据解码出来12位就是:0000 00000010,也就是0x2,就是第2个位错误.
第3个位错误的24位数据解码出来12位就是:0000 00000011,也就是0x3,就是第3个错误.
第4095个位错误的24位数据解码出来12位就是:1111 11111111,也就是0xfff,就是第4095个位错误.

到了这一步,不知道有没有明白纠正原理呢。当知道是哪一个是错误的了,剩下的就简单了,就把错误的那一位把0变成1,或者把1变成0就行了。
可以写成一个函数,ecc_data为校验结果。

intcheck_ecc(u32 ecc_data)
{
  u32 temp;
  int i;
  u8 data4;
  u32 location=0;
  temp=ecc_data&0xffffff;//只要24位


  for(i=0;i<24/2;i++)
    {
     data4=(temp>>(i*2))&0x3;
     if(data4==0x01)
        {
        // 如果两位是0x01,则判断是0
        }
     else if(data4==0x02)
        {
         // 1 如果两个是0x10,则判断是1
         location|=(1<<i);
        }
     else
        {
        // 如果不是两种其一,刚说明无法纠错
                   // 既然无法纠错,其它的,就暂时不关心了
         return -1;
        }
     printf("location:%d..\r\n",location);

    }
  return location;

}


当然,如果校验结果为0x00的时候,说明读出来的数据是对的。不需要调用这个函数了。调用这个函数时,就可以返回错误的位置。
到此,ECC的功能就调试的差不多了。剩下的,就是把那一位纠错出来就好了。重要的ECC校验结果出来了,知道是哪一位错误了,剩下的还不好办了。

对于NAND_FLASH呢,具体就可以这样实现了。
一页是2048个字节加OOB的64个字节。
OOB区一般是存放ECC数据,一般如果写到跑系统的是,用设计ECC layout的。
这里就简单作个layout吧。简单地说,就是把ECC放在哪里。
因为这里每512个字节, 产生一个ECC,占4个字节。
第1 个512字节产生的ECC就放到OOB区里的0x10,0x11,x12,0x13这四个地址里。
第2 个512字节产生的ECC就放到OOB区里的0x14,0x15,x16,0x17这四个地址里。
第3 个512字节产生的ECC就放到OOB区里的0x18,0x19,x1a,0x1b这四个地址里。
第4 个512字节产生的ECC就放到OOB区里的0x1c,0x1d,x1e,0x1f这四个地址里。

这样,ECC layout就算是设置好了。因此只要在写入的时候,把ECC相应地存入到OOB区,然后在读NAND_FLASH的时候,再读新的ECC数据,和之前写入到OOB里的ECC进行异或,得到ECC校验结果。那,ECC的调试,就算告个段落了。
如果有错误之处,还请见谅。
特此写下以便日后可以回顾,而且网上涉及的也比较少,写出来也让感兴趣的人一起交流学习。


FSMC的使用手册*(英文的),以及fsmc_nand.c的驱动测试ECC一同上传到了我的CSDN里了,有需要可下载
STM32 ECC调试及心得.zip (385.02 KB, 售价: 2 工控币)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则