找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 18717|回復(fù): 6
收起左側(cè)

STM32 ECC校驗(yàn)的一些心得

[復(fù)制鏈接]
ID:76190 發(fā)表于 2015-4-5 20:48 | 顯示全部樓層 |閱讀模式
      STM32FSMC功能支持SRAMNOR FLASH,NAND FLASH,是非常方便的。

當(dāng)然,要STM32F103VC及以上的芯片才支持FSMC功能的。

   在此寫(xiě)下一些調(diào)試使用FMMC調(diào)試NAND FLASH的心得及總結(jié),方便以后回顧,也便于大家一起交流學(xué)習(xí)。

在這里重點(diǎn)寫(xiě)下的是調(diào)試ECC這個(gè)功能。

 使用的NAND FLASH芯片K9F2G08U0C

     芯片大小是2Gbit,也就是容量256MB。一塊64頁(yè),一頁(yè)2K字節(jié)

     一頁(yè)2048字節(jié),其中,OOB區(qū)64字節(jié)。

     當(dāng)然,要能正常使用ECC功能,NAND_FLASH的讀寫(xiě)正常是前提。這里不作介紹。要ST公司提供的例子里有NAND_FLASH的讀寫(xiě)例子,一般可參照其配置再結(jié)合自己實(shí)際使用的NAND_FLASH芯片及電路設(shè)計(jì)修改。

   保證了能正常讀寫(xiě)頁(yè)功能,以及讀寫(xiě)OOB區(qū)數(shù)據(jù)功能,即可繼續(xù)調(diào)試ECC了。

   以下這段話(huà)就是來(lái)自STM32FSMC使用手冊(cè)里關(guān)于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個(gè)字節(jié)產(chǎn)生一個(gè)ECC數(shù)據(jù),這樣,當(dāng)這512字節(jié)里出錯(cuò)有一位錯(cuò)誤的時(shí)候,可以通過(guò)ECC來(lái)糾正。當(dāng)然,如果錯(cuò)了幾個(gè)位,就無(wú)法糾錯(cuò)了。雖然當(dāng)兩個(gè)位有錯(cuò),也知道,但不知道是哪兩個(gè)位出錯(cuò),也糾正不了。所以,只要關(guān)心怎么找出錯(cuò)誤,通過(guò)ECC怎么糾錯(cuò)。

 FSMCECC支持每256字節(jié),512字節(jié),1024,。。。8192字節(jié)產(chǎn)生一個(gè)ECC數(shù)據(jù)。

調(diào)試時(shí)使用每512字節(jié)產(chǎn)生一個(gè)ECC功能。

當(dāng)寫(xiě)入512個(gè)字節(jié)時(shí),產(chǎn)生一個(gè)ECC數(shù)據(jù),然后,再讀512個(gè)字節(jié)的時(shí)候,也會(huì)產(chǎn)生一個(gè)ECC數(shù)據(jù),通過(guò)這兩個(gè)數(shù)據(jù)相異或,產(chǎn)生一個(gè)ECC校驗(yàn)結(jié)果,通過(guò)這個(gè)判斷結(jié)果,就可以分析出有沒(méi)有錯(cuò),錯(cuò)在哪里,是錯(cuò)哪一位。當(dāng)然,知道哪一位錯(cuò)了,也就可以糾正了。

 

現(xiàn)在具體以實(shí)際的NAND_FLASH為例。

K9F2G08U0C這個(gè)芯片雖然是每頁(yè)2048個(gè)字節(jié),也就是4 個(gè)512字節(jié)。按理說(shuō)直接使用每2048字節(jié)產(chǎn)生一個(gè)ECC即可校驗(yàn),這樣也方便一些。但因?yàn)閷?shí)際使用中,是把這FLASH當(dāng)作U盤(pán)來(lái)使用,并使用了fat32文件系統(tǒng),將其作扇區(qū)處理了。一般扇區(qū)單位為512個(gè)字節(jié)。因此,這里就使用每512個(gè)字節(jié)產(chǎn)生一個(gè)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;

 

  然后在讀寫(xiě)NAND_FLASH,即可讀到ECC數(shù)據(jù)。

 

u32 write_ecc;

u32 read_ecc;

 for(i=0;i<512;i++)

 {

    buffer[i]=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);

//這是寫(xiě)入512個(gè)字節(jié)時(shí)候讀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個(gè)時(shí)候讀取ECC

  

 要保證讀取到正確的ECC數(shù)據(jù),要在讀之前先失能下ECC功能,把ECC數(shù)據(jù)清零,再使用ECC,然后再讀或?qū)?/span>NAND_FLASH。再讀到相應(yīng)的ECC。讀ECC后記得把ECC失能,以清空ECC數(shù)據(jù)。 

   這樣就可以讀到write_ecc了。當(dāng)然,這個(gè)數(shù)據(jù)會(huì)讀到的是0,為什么呢,所以很多時(shí)候我們測(cè)試數(shù)據(jù),都是用比較有規(guī)律的數(shù)據(jù)去測(cè)試,下面通過(guò)幾組數(shù)據(jù),來(lái)解讀下這個(gè)ECC的數(shù)據(jù)分析 

for(i=0;i<512;i++)

  {

    buffer[i]=0x11;

  }

ECC: 0

 

 

 512個(gè)字節(jié)里,都是0x11的話(huà),ECC數(shù)據(jù)是0。然后改變其中某個(gè)字節(jié)的某個(gè)位,再去讀ECC看。

for(i=0;i<512;i++)

  {

    buffer[i]=0x11;

  }

buffer [0]=0x10;

ECC: 0x55555555

這是改了第一個(gè)字節(jié)的第一個(gè)位。(但習(xí)慣上從0開(kāi)始比較習(xí)慣,改了第0個(gè)字節(jié)第0個(gè)位)

for(i=0;i<512;i++)

  {

    buffer[i]=0x11;

  }

buffer [0]=0x13;

ECC:0x55555556

改了第1個(gè)位

 

 

for(i=0;i<2048;i++)

  {

    buffer[i]=0x11;

  }

buffer [0]=0x15;

ECC:0x55555559

改了第2個(gè)位

 

 

for(i=0;i<2048;i++)

  {

    buffer[i]=0x11;

  }

buffer [0]=0x19;

ECC:0x5555555a

 

 

 

 

for(i=0;i<512;i++)

  {

    buffer[i]=0x11;

  }

buffer [511]=0x91;

ECC:0x55aaaaaa;

這里改了第4095個(gè)位,也就是(第511個(gè)字節(jié)的最高位,也就是512個(gè)字節(jié)里的最高一個(gè)位)

 

好了,有了以上這里數(shù)據(jù),就可以開(kāi)始解讀了,就算找不到例子,只要你的NAND_FLASH讀寫(xiě)正常了,能把這些看懂了,也就可以使用ECC功能了。

 

下面對(duì)這幾個(gè)ECC數(shù)據(jù)進(jìn)行解讀。

 

解讀前先看一下ECC結(jié)果寄存器。

   因?yàn)槲覀冊(cè)O(shè)置的是512個(gè)字節(jié)產(chǎn)生一個(gè)ECC。那么有效位是023。 

也就是前面讀到的ECC數(shù)據(jù)呢,只要低24位就可以了。

當(dāng)然,從這里還能看出其它數(shù)據(jù)。最高是8192字節(jié),占了32位,

4096字節(jié)占了30位。

這個(gè)規(guī)律就是從256字節(jié)開(kāi)始,每增一倍字節(jié)數(shù),ECC就多占用兩個(gè)位。

按常理說(shuō),只要多一個(gè)位,就可以表示多一倍的數(shù)據(jù)了。但是要表示多一個(gè)數(shù)據(jù),需要到兩個(gè)位,那,這里就有點(diǎn)玄機(jī)了。

甚至不需要去理解或弄明白它使用是漢明碼,什么BCH碼,只要看明白下這里,一直可以糾錯(cuò)。因?yàn),不要管它是什么糾錯(cuò)碼,就跟著這個(gè)規(guī)律去理解。

512個(gè)字節(jié)的ECC用了24位,512個(gè)字節(jié)共有512*8=4096個(gè)位。要表示到4096個(gè)數(shù),也就是剛好12位就可以了。所以,因此這里的玄機(jī)就是ECC數(shù)據(jù)里,用了2個(gè)位來(lái)表示一個(gè)位的數(shù)據(jù)。

這時(shí),再看一下關(guān)于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.

 

忘了說(shuō),我們這些測(cè)試數(shù)據(jù)呢,是以寫(xiě)入0x11為主,然后故意改錯(cuò)某一個(gè)位,再讀出ECC。因?yàn)閷?xiě)入全部的是0x11,因此寫(xiě)入時(shí)產(chǎn)生的ECC0x0。那么再將讀出來(lái)的ECC0x0異或,得到的,也就是ECC校驗(yàn)結(jié)果了。

當(dāng)錯(cuò)第0個(gè)位的時(shí)候,校驗(yàn)結(jié)果是0x55555555。取低24位,也就是0x555555。

 

對(duì)應(yīng)24位就是

010101010101010101010101

當(dāng)錯(cuò)第1個(gè)位的時(shí)候,校驗(yàn)結(jié)果是0x555556(取低24位)

對(duì)應(yīng)24位就是

010101010101010101010110

當(dāng)錯(cuò)第2個(gè)位對(duì)應(yīng)的24位是:

010101010101010101011001

當(dāng)錯(cuò)第3個(gè)位對(duì)應(yīng)的24位是:

010101010101010101011010

…………

當(dāng)錯(cuò)第4095個(gè)位(也就是第511個(gè)字節(jié)的最高位) 校驗(yàn)結(jié)果:0xaaaaaa。

對(duì)應(yīng)24位是:

101010101010101010101010

 

看到這里,大家估計(jì)很容易看出來(lái)規(guī)律了。

0個(gè)位錯(cuò)誤的24位數(shù)據(jù)解碼出來(lái)12位就是:0000 00000000,也就是0x0,就是第0個(gè)位錯(cuò)誤.

1個(gè)位錯(cuò)誤的24位數(shù)據(jù)解碼出來(lái)12位就是:0000 00000001,也就是0x1,就是第1個(gè)位錯(cuò)誤.

2個(gè)位錯(cuò)誤的24位數(shù)據(jù)解碼出來(lái)12位就是:0000 00000010,也就是0x2,就是第2個(gè)位錯(cuò)誤.

3個(gè)位錯(cuò)誤的24位數(shù)據(jù)解碼出來(lái)12位就是:0000 00000011,也就是0x3,就是第3個(gè)錯(cuò)誤.

4095個(gè)位錯(cuò)誤的24位數(shù)據(jù)解碼出來(lái)12位就是:1111 11111111,也就是0xfff,就是第4095個(gè)位錯(cuò)誤.

 

到了這一步,不知道有沒(méi)有明白糾正原理呢。當(dāng)知道是哪一個(gè)是錯(cuò)誤的了,剩下的就簡(jiǎn)單了,就把錯(cuò)誤的那一位把0變成1,或者把1變成0就行了。

可以寫(xiě)成一個(gè)函數(shù),ecc_data為校驗(yàn)結(jié)果。

 

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 如果兩個(gè)是0x10,則判斷是1

         location|=(1<<i);

        }

     else

        {

        // 如果不是兩種其一,剛說(shuō)明無(wú)法糾錯(cuò)

                   // 既然無(wú)法糾錯(cuò),其它的,就暫時(shí)不關(guān)心了

         return -1;

        }

     printf("location:%d..\r\n",location);

 

    }

  return location;

 

}

 

 

當(dāng)然,如果校驗(yàn)結(jié)果為0x00的時(shí)候,說(shuō)明讀出來(lái)的數(shù)據(jù)是對(duì)的。不需要調(diào)用這個(gè)函數(shù)了。調(diào)用這個(gè)函數(shù)時(shí),就可以返回錯(cuò)誤的位置。

到此,ECC的功能就調(diào)試的差不多了。剩下的,就是把那一位糾錯(cuò)出來(lái)就好了。重要的ECC校驗(yàn)結(jié)果出來(lái)了,知道是哪一位錯(cuò)誤了,剩下的還不好辦了。

 

對(duì)于NAND_FLASH呢,具體就可以這樣實(shí)現(xiàn)了。

一頁(yè)是2048個(gè)字節(jié)加OOB64個(gè)字節(jié)。

OOB區(qū)一般是存放ECC數(shù)據(jù),一般如果寫(xiě)到跑系統(tǒng)的是,用設(shè)計(jì)ECC layout的。

這里就簡(jiǎn)單作個(gè)layout吧。簡(jiǎn)單地說(shuō),就是把ECC放在哪里。

因?yàn)檫@里每512個(gè)字節(jié), 產(chǎn)生一個(gè)ECC,占4個(gè)字節(jié)。

1 個(gè)512字節(jié)產(chǎn)生的ECC就放到OOB區(qū)里的0x10,0x11,x12,0x13這四個(gè)地址里。

2 個(gè)512字節(jié)產(chǎn)生的ECC就放到OOB區(qū)里的0x14,0x15,x16,0x17這四個(gè)地址里。

3 個(gè)512字節(jié)產(chǎn)生的ECC就放到OOB區(qū)里的0x18,0x19,x1a,0x1b這四個(gè)地址里。

4 個(gè)512字節(jié)產(chǎn)生的ECC就放到OOB區(qū)里的0x1c,0x1d,x1e,0x1f這四個(gè)地址里。

    

     這樣,ECC layout就算是設(shè)置好了。因此只要在寫(xiě)入的時(shí)候,把ECC相應(yīng)地存入到OOB區(qū),然后在讀NAND_FLASH的時(shí)候,再讀新的ECC數(shù)據(jù),和之前寫(xiě)入到OOB里的ECC進(jìn)行異或,得到ECC校驗(yàn)結(jié)果。那,ECC的調(diào)試,就算告?zhèn)段落了。

如果有錯(cuò)誤之處,還請(qǐng)見(jiàn)諒。

特此寫(xiě)下以便日后可以回顧,而且網(wǎng)上涉及的也比較少,寫(xiě)出來(lái)也讓感興趣的人一起交流學(xué)習(xí)。


FSMC的使用手冊(cè)*(英文的),以及fsmc_nand.c的驅(qū)動(dòng)測(cè)試ECC一同上傳到了我的CSDN里了,有需要可下載 STM32 ECC調(diào)試及心得.zip (385.02 KB, 下載次數(shù): 76)

回復(fù)

使用道具 舉報(bào)

ID:161913 發(fā)表于 2017-1-15 19:10 | 顯示全部樓層
需要這個(gè)東西。謝謝分享!
回復(fù)

使用道具 舉報(bào)

ID:161913 發(fā)表于 2017-1-15 19:16 | 顯示全部樓層
很有用,非常感謝樓主分享。
回復(fù)

使用道具 舉報(bào)

ID:20697 發(fā)表于 2017-10-27 10:33 | 顯示全部樓層
學(xué)習(xí)了。
有個(gè)問(wèn)題,512字節(jié)寫(xiě)一次,2k的page要寫(xiě)4次嗎?
回復(fù)

使用道具 舉報(bào)

ID:20697 發(fā)表于 2017-10-27 10:34 | 顯示全部樓層
本帖最后由 hunancjz 于 2017-10-31 14:30 編輯

請(qǐng)問(wèn)一下ECC如何寫(xiě)到OOB?
我的理解是,data區(qū)分4次寫(xiě),得到4個(gè)ECC,再把4個(gè)ECC寫(xiě)到OOB。
就是說(shuō)寫(xiě)一頁(yè)要進(jìn)行5次寫(xiě)操作。
這樣理解對(duì)嗎?
回復(fù)

使用道具 舉報(bào)

ID:256228 發(fā)表于 2017-12-1 18:24 | 顯示全部樓層
我用的也是 4096Bytes/Page 的NANDFLASH,非常感謝樓主分享解了我的困惑。
回復(fù)

使用道具 舉報(bào)

ID:396291 發(fā)表于 2018-9-10 23:45 | 顯示全部樓層
正在學(xué)習(xí)這個(gè),謝謝樓主分享
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表