WINCE6.0+SLC ECC产生和校验 .

原创地址:http://blog.csdn.net/loongembedded/article/details/24176643

 

备注:处理器为S3C2451,flash为K9K8G08U0D

 

1.     ECC分配标准

 

先来看三星NAND FLASH spare区域的分配标准:

 

图1

2.     StepldrECC的处理

 

Stepldr的写采用自己的函数FMD_LB_WriteSector_Steploader,stepldr采用8bit的ECC纠错,为什么呢?S3C2451 FLASH控制器部分给出说明:

1. Auto boot by: The boot code istransferred into 8-KB Steppingstone after reset. After the boot code is

transfered, boot code will beexecuted on the Steppingstone.

Note: IROMboot support 8Bit ECC correction on Nand device booting

此函数通过设置NFCONF[24:23]=1来支持8bit ECC。还有需要注意的是,这里采用另一组参数:

  1. <SPAN style="FONT-SIZE: 14px">#define  DEFAULT_TACLS               (1)          // 1 HCLK (7.5ns)  
  2. #define  DEFAULT_TWRPH0          (4)          // 5 HCLK(37.5ns)  
  3. #define  DEFAULT_TWRPH1          (1)          // 2 HCLK(15ns)</SPAN>  
<span style="font-size:14px;">#define  DEFAULT_TACLS               (1)          // 1 HCLK (7.5ns)
#define  DEFAULT_TWRPH0          (4)          // 5 HCLK(37.5ns)
#define  DEFAULT_TWRPH1          (1)          // 2 HCLK(15ns)</span>

2.1   写stepldr镜像文件时ECC的操作

 

当写入512字节(不包括spare数据)的数据后, 8bit ECC模块内部产生ECC奇偶校验码,这些校验码自动更新到NF8MECC0、NF8MECC1、NF8MECC2、NF8MECC3寄存器中,然后可以把校验码写入到spare区域,下面来看代码:

  1. <SPAN style="FONT-SIZE: 14px">typedef struct  
  2. {  
  3.     UINT32         n8MECC0;        // 8MECC0  
  4.     UINT32         n8MECC1;        // 8MECC1  
  5.     UINT32         n8MECC2;        // 8MECC2  
  6.     UINT8           n8MECC3;        // 8MECC3  
  7. } MECC8;</SPAN>  
<span style="font-size:14px;">typedef struct
{
    UINT32         n8MECC0;        // 8MECC0
    UINT32         n8MECC1;        // 8MECC1
    UINT32         n8MECC2;        // 8MECC2
    UINT8           n8MECC3;        // 8MECC3
} MECC8;</span>


 

此结构体的定位,为什么n8MECC3需要定义为8位的,见寄存器的说明:


图2


  1. <SPAN style="FONT-SIZE: 14px">MECC8 t8MECC[4];  
  2.    
  3. // initializevariable.   
  4.     for(i = 0; i < 4; i++) {  
  5.         t8MECC[i].n8MECC0 = 0x0;  
  6.         t8MECC[i].n8MECC1 = 0x0;  
  7.         t8MECC[i].n8MECC2 = 0x0;  
  8.         t8MECC[i].n8MECC3 = 0x0;  
  9.     }</SPAN>  
<span style="font-size:14px;">MECC8 t8MECC[4];
 
// initializevariable.
    for(i = 0; i < 4; i++) {
        t8MECC[i].n8MECC0 = 0x0;
        t8MECC[i].n8MECC1 = 0x0;
        t8MECC[i].n8MECC2 = 0x0;
        t8MECC[i].n8MECC3 = 0x0;
    }</span>


 

每往main区域写入512字节的数据,都产生ECC校验码并保存在t8MECC[nSectorLoop]中。

  1. <SPAN style="FONT-SIZE: 14px">    // Write each Sector in the Page. (4 Sectorper Page, Loop 4 times.)  
  2.     for (nSectorLoop = 0; nSectorLoop <SECTORS_PER_PAGE; nSectorLoop++)  
  3.     {  
  4.         // Initialize ECC register   
  5.         NF_MECC_UnLock();  
  6.         NF_RSTECC();  
  7.    
  8.         // Special case to handle un-alignedbuffer pointer.  
  9.         if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)  
  10.         {  
  11.             // Write the data   
  12.             for(i=0; i<SECTOR_SIZE/sizeof(DWORD);i++)  
  13.             {  
  14.                 wrdata =(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];  
  15.                 wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;  
  16.                 wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;  
  17.                 wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;  
  18.                 NF_WRDATA_WORD(wrdata);  
  19.             }  
  20.         }  
  21.         else  
  22.         {  
  23.            WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);  
  24.         }  
  25.    
  26.         NF_MECC_Lock();  
  27.    
  28.        while(!(s2450NAND->NFSTAT&(1<<7))) ;  
  29.         s2450NAND->NFSTAT|=(1<<7);  
  30.    
  31.         // Read out the ECC value generated by HW  
  32.         t8MECC[nSectorLoop].n8MECC0 =NF_8MECC0();  
  33.         t8MECC[nSectorLoop].n8MECC1 =NF_8MECC1();  
  34.         t8MECC[nSectorLoop].n8MECC2 =NF_8MECC2();  
  35.         t8MECC[nSectorLoop].n8MECC3 =(NF_8MECC3() & 0xff);  
  36.     }</SPAN>  
<span style="font-size:14px;">    // Write each Sector in the Page. (4 Sectorper Page, Loop 4 times.)
    for (nSectorLoop = 0; nSectorLoop <SECTORS_PER_PAGE; nSectorLoop++)
    {
        // Initialize ECC register
        NF_MECC_UnLock();
        NF_RSTECC();
 
        // Special case to handle un-alignedbuffer pointer.
        if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
        {
            // Write the data
            for(i=0; i<SECTOR_SIZE/sizeof(DWORD);i++)
            {
                wrdata =(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];
                wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;
                wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;
                wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;
                NF_WRDATA_WORD(wrdata);
            }
        }
        else
        {
           WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);
        }
 
        NF_MECC_Lock();
 
       while(!(s2450NAND->NFSTAT&(1<<7))) ;
        s2450NAND->NFSTAT|=(1<<7);
 
        // Read out the ECC value generated by HW
        t8MECC[nSectorLoop].n8MECC0 =NF_8MECC0();
        t8MECC[nSectorLoop].n8MECC1 =NF_8MECC1();
        t8MECC[nSectorLoop].n8MECC2 =NF_8MECC2();
        t8MECC[nSectorLoop].n8MECC3 =(NF_8MECC3() & 0xff);
    }</span>


 

这里要重点注意了,先来看数据手册的说明:


图3

也就是说,如果使用512字节的NAND FLASH memory,可以直接把校验码写入到spare区域,但如果使用多于512字节的NAND FLASH memory(上面的代码是写入4*512字节的数据),就需要先拷贝校验码到其他的存储空间(比如DRAM,这里对应局部变量数据t8MECC),等写完所有的main数据后,再把拷贝后的校验码写到spare区域。

 

//写完所有的main数据,现在写入到spare区域

  1. <SPAN style="FONT-SIZE: 14px">    for(nSectorLoop = 0; nSectorLoop < 4;nSectorLoop++)  
  2.     {  
  3.        NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC0); // 4 byte n8MECC0  
  4.        NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC1); // 4 byte n8MECC1  
  5.        NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC2); // 4 byte n8MECC2  
  6.        NF_WRDATA_BYTE((t8MECC[nSectorLoop].n8MECC3) & 0xff); // 1 byten8MECC3  
  7.     }</SPAN>  
<span style="font-size:14px;">    for(nSectorLoop = 0; nSectorLoop < 4;nSectorLoop++)
    {
       NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC0); // 4 byte n8MECC0
       NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC1); // 4 byte n8MECC1
       NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC2); // 4 byte n8MECC2
       NF_WRDATA_BYTE((t8MECC[nSectorLoop].n8MECC3) & 0xff); // 1 byten8MECC3
    }</span>


 

由此可知stepldr镜像文件对应的每页的16 字节spare区域安排如下:


图4

2.2   读stepldr镜像文件时ECC的操作

 

Sepldr内容是由S3C2451的IROM代码来读取的,读取时校验码的比较也是由IROM来完成的,为什么eboot在写入stepldr时采用8bit ECC,是因为:

Note: IROMboot support 8Bit ECC correction on Nand device booting

 

 

3.     EbootECC的处理

 

Eboot中写eboot和NK镜像文件采用1bit ECC

 

3.1   写Eboot和NK镜像文件时ECC的操作

由FMD_LB_WriteSector函数来实现,首先是写入main区域,然后重生ECC码,再写入spare区域。

 

  1. <SPAN style="FONT-SIZE: 14px">// Write eachSector in the Page. (4 Sector per Page, Loop 4 times.)  
  2.               for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)  
  3.               {  
  4.                              //  Initialize ECC register  
  5.                              NF_RSTECC();  
  6.                              NF_MECC_UnLock();  
  7.                
  8.                              // Special case tohandle un-aligned buffer pointer.  
  9.                              if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)  
  10.                              {  
  11.                                            //  Write the data  
  12.                                            for(i=0;i<SECTOR_SIZE/sizeof(DWORD); i++)  
  13.                                            {  
  14.                                                          wrdata= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];  
  15.                                                          wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;  
  16.                                                          wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;  
  17.                                                          wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;  
  18.                                                          NF_WRDATA_WORD(wrdata);  
  19.                                            }  
  20.                              }  
  21.                              else  
  22.                              {  
  23.                                            WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);  
  24.                              }  
  25.                
  26.                              NF_MECC_Lock();  
  27.                               
  28.                              //  Read out the ECC value generated by HW  
  29.                              MECCBuf[nSectorLoop]= NF_RDMECC0();    
  30.               }</SPAN>  
<span style="font-size:14px;">// Write eachSector in the Page. (4 Sector per Page, Loop 4 times.)
              for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)
              {
                             //  Initialize ECC register
                             NF_RSTECC();
                             NF_MECC_UnLock();
             
                             // Special case tohandle un-aligned buffer pointer.
                             if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
                             {
                                           //  Write the data
                                           for(i=0;i<SECTOR_SIZE/sizeof(DWORD); i++)
                                           {
                                                         wrdata= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];
                                                         wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;
                                                         wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;
                                                         wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;
                                                         NF_WRDATA_WORD(wrdata);
                                           }
                             }
                             else
                             {
                                           WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);
                             }
             
                             NF_MECC_Lock();
                            
                             //  Read out the ECC value generated by HW
                             MECCBuf[nSectorLoop]= NF_RDMECC0();  
              }</span>


 

当读或是写main数据(不包括spare数据)完成时,自动把ECC模块产生的校验码更新到NFMECC0、NFMECC1寄存器中,并且ECC状态寄存器的值不会改变。这时可以从这些寄存器中读取其值。

 

  1. <SPAN style="FONT-SIZE: 14px">// Write theSectorInfo data to the media  
  2.               // NOTE: This hardware is odd:only a byte can be written at a time and it must reside in the  
  3.               //       upper byte of a USHORT.  
  4.               if(pSectorInfoBuff)             // SectorInfoBuff啊 瞒 乐促搁, 角力 Sector Info甫持绰促.  
  5.               {  
  6. #if CHECK_SPAREECC   
  7.                              NF_RSTECC();  
  8.                              NF_SECC_UnLock();  
  9. #endif   
  10.    
  11.         // Write the first reserved field (DWORD)  
  12.                              NF_WRDATA_BYTE(pSectorInfoBuff->bBadBlock);  
  13.        NF_WRDATA_WORD(pSectorInfoBuff->dwReserved1);  
  14.                              NF_WRDATA_BYTE(pSectorInfoBuff->bOEMReserved);  
  15. #if CHECK_SPAREECC   
  16.                              NF_SECC_Lock();  
  17. #endif   
  18.                              NF_WRDATA_BYTE(pSectorInfoBuff->wReserved2&0xff);  
  19.                              NF_WRDATA_BYTE((pSectorInfoBuff->wReserved2>>8)&0xff);  
  20.               }  
  21.               else                                    // SectorInfoBuff啊 厚绢乐促搁, 歹固 data甫 持绰促. (0xffffffff ffffffff)  
  22.               {  
  23.                              // Make sure weadvance the Flash's write pointer (even though we aren't writing the SectorInfodata)  
  24.                              for(i=0;i<sizeof(SectorInfo)/sizeof(DWORD); i++)  
  25.                              {  
  26.                                            NF_WRDATA_WORD(0xffffffff);  
  27.                              }  
  28.               }</SPAN>  
<span style="font-size:14px;">// Write theSectorInfo data to the media
              // NOTE: This hardware is odd:only a byte can be written at a time and it must reside in the
              //       upper byte of a USHORT.
              if(pSectorInfoBuff)             // SectorInfoBuff啊 瞒 乐促搁, 角力 Sector Info甫持绰促.
              {
#if CHECK_SPAREECC
                             NF_RSTECC();
                             NF_SECC_UnLock();
#endif
 
        // Write the first reserved field (DWORD)
                             NF_WRDATA_BYTE(pSectorInfoBuff->bBadBlock);
       NF_WRDATA_WORD(pSectorInfoBuff->dwReserved1);
                             NF_WRDATA_BYTE(pSectorInfoBuff->bOEMReserved);
#if CHECK_SPAREECC
                             NF_SECC_Lock();
#endif
                             NF_WRDATA_BYTE(pSectorInfoBuff->wReserved2&0xff);
                             NF_WRDATA_BYTE((pSectorInfoBuff->wReserved2>>8)&0xff);
              }
              else                                    // SectorInfoBuff啊 厚绢乐促搁, 歹固 data甫 持绰促. (0xffffffff ffffffff)
              {
                             // Make sure weadvance the Flash's write pointer (even though we aren't writing the SectorInfodata)
                             for(i=0;i<sizeof(SectorInfo)/sizeof(DWORD); i++)
                             {
                                           NF_WRDATA_WORD(0xffffffff);
                             }
              }</span>


 

上面的内容是把SectorInfo结构体的数据写入到spare中,并且为这些数据产生ECC校验码,下面接着把main数据的ECC校验码接着写入spare中

  1. <SPAN style="FONT-SIZE: 14px">    // Write the ECC value to the flash  
  2.               NF_WRDATA_WORD(MECCBuf[0]);  
  3.               NF_WRDATA_WORD(MECCBuf[1]);  
  4.               NF_WRDATA_WORD(MECCBuf[2]);  
  5.               NF_WRDATA_WORD(MECCBuf[3]);</SPAN>  
<span style="font-size:14px;">    // Write the ECC value to the flash
              NF_WRDATA_WORD(MECCBuf[0]);
              NF_WRDATA_WORD(MECCBuf[1]);
              NF_WRDATA_WORD(MECCBuf[2]);
              NF_WRDATA_WORD(MECCBuf[3]);</span>

上面在写入SectorInfo结构体bBadBlock、dwReserved1和bOEMReserved数据到spare的时候,为这三个数据产生ECC校验码,下面从NFSECC寄存器中读取出ECC校验码并写入到spare中

  1. <SPAN style="FONT-SIZE: 14px">#if CHECK_SPAREECC  
  2.               if(pSectorInfoBuff)  
  3.               {  
  4.                              SECCBuf =NF_RDSECC();  
  5.                              NF_WRDATA_WORD(SECCBuf);  
  6.               }  
  7. #endif</SPAN>  
<span style="font-size:14px;">#if CHECK_SPAREECC
              if(pSectorInfoBuff)
              {
                             SECCBuf =NF_RDSECC();
                             NF_WRDATA_WORD(SECCBuf);
              }
#endif</span>


 

根据上面的代码,可以每页(2048字节=4*512)对应的spare区域安排如下:


图5

其中bBadBlock表示坏块信息,如果其值为0xFF表示是好块,如果不是则为坏块;dwReserved1用来保存逻辑页(2048字节)的数量,比如,如果是第1block的第1页,那么它的值=64页,因为我们的flash一个block=64页。bOEMReserved,我们可以用来设置block的属性,比如设置此block为预留block,或是只读block等。wReserved2用来为FAL只是数据是否有效(Indicates data is valid for the FAL( flash abstraction layer))。

 

3.2   读Eboot和NK镜像文件时ECC的操作

由FMD_LB_ReadSector函数来实现,先读取spare区域的数据

 

(1)  读取spare区域数据,并进行ECC校验

//读取图5中的前8字节的数据

  1. <SPAN style="FONT-SIZE: 14px">              if (pSectorInfoBuff)  
  2.               {  
  3. #if CHECK_SPAREECC   
  4.                              NF_RSTECC();  
  5.                              NF_SECC_UnLock();  
  6. #endif   
  7.    
  8.                              pSectorInfoBuff->bBadBlock= NF_RDDATA_BYTE();  
  9.                              pSectorInfoBuff->dwReserved1= NF_RDDATA_WORD();  
  10.                              pSectorInfoBuff->bOEMReserved= NF_RDDATA_BYTE();  
  11. #if CHECK_SPAREECC   
  12.                              NF_SECC_Lock();  
  13. #endif   
  14.                              pSectorInfoBuff->wReserved2= NF_RDDATA_BYTE();  
  15.                              pSectorInfoBuff->wReserved2|= (NF_RDDATA_BYTE()<<8);  
  16.               }  
  17.               // If there is noSectorInfoBuffer, Just read and waste.  
  18.               else         
  19.               {  
  20.                              for(i=0;i<sizeof(SectorInfo)/sizeof(DWORD); i++)  
  21.                              rddata = (DWORD)NF_RDDATA_WORD();                  // readand trash the data  
  22.               }</SPAN>  
<span style="font-size:14px;">              if (pSectorInfoBuff)
              {
#if CHECK_SPAREECC
                             NF_RSTECC();
                             NF_SECC_UnLock();
#endif
 
                             pSectorInfoBuff->bBadBlock= NF_RDDATA_BYTE();
                             pSectorInfoBuff->dwReserved1= NF_RDDATA_WORD();
                             pSectorInfoBuff->bOEMReserved= NF_RDDATA_BYTE();
#if CHECK_SPAREECC
                             NF_SECC_Lock();
#endif
                             pSectorInfoBuff->wReserved2= NF_RDDATA_BYTE();
                             pSectorInfoBuff->wReserved2|= (NF_RDDATA_BYTE()<<8);
              }
              // If there is noSectorInfoBuffer, Just read and waste.
              else       
              {
                             for(i=0;i<sizeof(SectorInfo)/sizeof(DWORD); i++)
                             rddata = (DWORD)NF_RDDATA_WORD();                  // readand trash the data
              }</span>


 

//接着读取保存MECC0校验数据(这是写入main数据时重生的ECC校验码)

  1. <SPAN style="FONT-SIZE: 14px"for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)  
  2.               {  
  3.                              MECCBuf[nSectorLoop]= NF_RDDATA_WORD();  
  4.               }</SPAN>  
<span style="font-size:14px;"> for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)
              {
                             MECCBuf[nSectorLoop]= NF_RDDATA_WORD();
              }</span>

//读取出spare的ECC,然后写入到NFSECCD中,并校验

  1. <SPAN style="FONT-SIZE: 14px">#if CHECK_SPAREECC  
  2.               if (pSectorInfoBuff)  
  3.               {  
  4.                              SECCBuf =NF_RDDATA_WORD();  
  5.                              NF_WRSECCD((SECCBuf&0xff)|((SECCBuf<<8)&0xff0000));  
  6.    
  7.                              nRetEcc =NF_ECC_ERR0;  
  8.    
  9.                              if(!ECC_CorrectData(startSectorAddr, (LPBYTE)pSectorInfoBuff, nRetEcc,ECC_CORRECT_SPARE))  
  10.                                            returnFALSE;  
  11.               }  
  12. #endif</SPAN>  
<span style="font-size:14px;">#if CHECK_SPAREECC
              if (pSectorInfoBuff)
              {
                             SECCBuf =NF_RDDATA_WORD();
                             NF_WRSECCD((SECCBuf&0xff)|((SECCBuf<<8)&0xff0000));
 
                             nRetEcc =NF_ECC_ERR0;
 
                             if(!ECC_CorrectData(startSectorAddr, (LPBYTE)pSectorInfoBuff, nRetEcc,ECC_CORRECT_SPARE))
                                           returnFALSE;
              }
#endif</span>


 

上面代码依据于数据手册下面的部分:


图6

当把数据写入到NFSECCD后,通过NFECCERR0来定为ECC出错的具体信息,如下图:


图7

 

下面重点来看ECC_CorrectData函数

  1. <SPAN style="FONT-SIZE: 14px">BOOLECC_CorrectData(SECTOR_ADDR sectoraddr, LPBYTE pData, UINT32 nRetEcc,ECC_CORRECT_TYPE nType)  
  2. {  
  3.               DWORD  nErrStatus;  
  4.               DWORD  nErrDataNo;  
  5.               DWORD  nErrBitNo;  
  6.               UINT32 nErrDataMask;  
  7.               UINT32 nErrBitMask = 0x7;  
  8.               BOOL bRet = TRUE;  
  9.    
  10.               if (nType == ECC_CORRECT_MAIN)  
  11.               {  
  12.                              //RETAILMSG(1,(TEXT("ECC_CorrectData()--->ECC_CORRECT_MAIN\r\n")));  
  13.                              nErrStatus   = 0;  
  14.                              nErrDataNo   = 7;  
  15.                              nErrBitNo    = 4;  
  16.                              nErrDataMask =0x7ff;  
  17.               }  
  18.               else if (nType ==ECC_CORRECT_SPARE)  
  19.               {  
  20.                              //RETAILMSG(1,(TEXT("ECC_CorrectData()--->ECC_CORRECT_SPARE\r\n")));  
  21.                  nErrStatus   = 2;  
  22.                  nErrDataNo   = 21;  
  23.                  nErrBitNo    = 18;  
  24.                  nErrDataMask = 0xf;  
  25.               }  
  26.               else  
  27.               {  
  28.                              //RETAILMSG(1,(TEXT("ECC_CorrectData()--->value=%d\r\n"),nType));  
  29.                  return FALSE;  
  30.               }  
  31.                
  32.               switch((nRetEcc>>nErrStatus)& 0x3)  
  33.               {  
  34.                              case 0:   // No Error  
  35.                              //RETAILMSG(1,(TEXT("ECC_CorrectData()--->noerror\r\n")));  
  36.                                            bRet= TRUE;  
  37.                                            break;  
  38.                              case 1:   // 1-bit Error(Correctable)  
  39.                                            RETAILMSG(1,(TEXT("%cECCcorrectable error(0x%x). Byte:%d, bit:%d\r\n"),((nType==ECC_CORRECT_MAIN)?'M':'S'), sectoraddr,(nRetEcc>>nErrDataNo)&nErrDataMask,(nRetEcc>>nErrBitNo)&nErrBitMask));  
  40.                                            (pData)[(nRetEcc>>nErrDataNo)&nErrDataMask]^= (1<<((nRetEcc>>nErrBitNo)&nErrBitMask));  
  41.                                            bRet= TRUE;                       
  42.                                            break;  
  43.                              case 2:   // Multiple Error  
  44.                                            RETAILMSG(1,(TEXT("%cECCUncorrectable error(0x%x)\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S'),sectoraddr));  
  45.                                            bRet= FALSE;                                    
  46.                                            break;  
  47.                              case 3:   // ECC area Error  
  48.                                            RETAILMSG(1,(TEXT("%cECCarea error\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S')));  
  49.                             default:  
  50.                                            bRet= FALSE;                                    
  51.                                            break;  
  52.               }  
  53.    
  54.               return bRet;  
  55. }</SPAN>  
<span style="font-size:14px;">BOOLECC_CorrectData(SECTOR_ADDR sectoraddr, LPBYTE pData, UINT32 nRetEcc,ECC_CORRECT_TYPE nType)
{
              DWORD  nErrStatus;
              DWORD  nErrDataNo;
              DWORD  nErrBitNo;
              UINT32 nErrDataMask;
              UINT32 nErrBitMask = 0x7;
              BOOL bRet = TRUE;
 
              if (nType == ECC_CORRECT_MAIN)
              {
                             //RETAILMSG(1,(TEXT("ECC_CorrectData()--->ECC_CORRECT_MAIN\r\n")));
                             nErrStatus   = 0;
                             nErrDataNo   = 7;
                             nErrBitNo    = 4;
                             nErrDataMask =0x7ff;
              }
              else if (nType ==ECC_CORRECT_SPARE)
              {
                             //RETAILMSG(1,(TEXT("ECC_CorrectData()--->ECC_CORRECT_SPARE\r\n")));
                 nErrStatus   = 2;
                 nErrDataNo   = 21;
                 nErrBitNo    = 18;
                 nErrDataMask = 0xf;
              }
              else
              {
                             //RETAILMSG(1,(TEXT("ECC_CorrectData()--->value=%d\r\n"),nType));
                 return FALSE;
              }
             
              switch((nRetEcc>>nErrStatus)& 0x3)
              {
                             case 0:   // No Error
                             //RETAILMSG(1,(TEXT("ECC_CorrectData()--->noerror\r\n")));
                                           bRet= TRUE;
                                           break;
                             case 1:   // 1-bit Error(Correctable)
                                           RETAILMSG(1,(TEXT("%cECCcorrectable error(0x%x). Byte:%d, bit:%d\r\n"),((nType==ECC_CORRECT_MAIN)?'M':'S'), sectoraddr,(nRetEcc>>nErrDataNo)&nErrDataMask,(nRetEcc>>nErrBitNo)&nErrBitMask));
                                           (pData)[(nRetEcc>>nErrDataNo)&nErrDataMask]^= (1<<((nRetEcc>>nErrBitNo)&nErrBitMask));
                                           bRet= TRUE;                     
                                           break;
                             case 2:   // Multiple Error
                                           RETAILMSG(1,(TEXT("%cECCUncorrectable error(0x%x)\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S'),sectoraddr));
                                           bRet= FALSE;                                  
                                           break;
                             case 3:   // ECC area Error
                                           RETAILMSG(1,(TEXT("%cECCarea error\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S')));
                            default:
                                           bRet= FALSE;                                  
                                           break;
              }
 
              return bRet;
}</span>

此函数需要密切结合NFECCERR0寄存器来理解,见下图:


图8

(2)  读取main区域数据,并进行ECC校验

这部分代码原理和上面的基本一样

  1. <SPAN style="FONT-SIZE: 14px">// Read eachSector in the Page. (4 Sector per Page, Loop 4 times.)  
  2.               for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)  
  3.               {  
  4.                              // calculate startaddress of each Sector  
  5.                              NewDataAddr =nSectorLoop * SECTOR_SIZE;  
  6.    
  7.                              // Set address forrandom access  
  8.                              NF_CMD(CMD_RDO);  
  9.                              NF_ADDR((NewDataAddr)&0xff);  
  10.                              NF_ADDR((NewDataAddr>>8)&0xff);  
  11.                              NF_CMD(CMD_RDO2);  
  12.    
  13.                              // Initialize ECCmodule  
  14.                              NF_RSTECC();  
  15.                              NF_MECC_UnLock();  
  16.                               
  17.                               // Special case to handle un-aligned bufferpointer.  
  18.                              if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)  
  19.                              {  
  20.                                            for(i=0;i<SECTOR_SIZE/sizeof(DWORD); i++)  
  21.                                            {  
  22.                                                          rddata= (DWORD) NF_RDDATA_WORD();  
  23.                                                          (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0]= (BYTE)(rddata & 0xff);  
  24.                                                          (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]= (BYTE)(rddata>>8 & 0xff);  
  25.                                                          (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]= (BYTE)(rddata>>16 & 0xff);  
  26.                                                          (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]= (BYTE)(rddata>>24 & 0xff);  
  27.                                            }  
  28.                              }  
  29.                              // usual case tohandle 4byte aligned buffer pointer  
  30.                              else  
  31.                              {  
  32.                                            RdPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);                                                                      // Read page/sector data.  
  33.                              }  
  34.                
  35.                              NF_MECC_Lock();  
  36.                               
  37.                              // Check ECC aboutMain Data with MECC parity codel  
  38.                              NF_WRMECCD0(((MECCBuf[nSectorLoop]&0xff00)<<8)|(MECCBuf[nSectorLoop]&0xff) );  
  39.                             NF_WRMECCD1(((MECCBuf[nSectorLoop]&0xff000000)>>8)|((MECCBuf[nSectorLoop]&0xff0000)>>16));  
  40.    
  41.                              nRetEcc =NF_ECC_ERR0;  
  42.                
  43.                              if(!ECC_CorrectData(startSectorAddr, pSectorBuff+nSectorLoop*SECTOR_SIZE,nRetEcc, ECC_CORRECT_MAIN))  
  44.                              {  
  45.                                            RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_LB_READSECTOR 7\r\n")));  
  46.                                            returnFALSE;  
  47.                              }  
  48.               }</SPAN>  
<span style="font-size:14px;">// Read eachSector in the Page. (4 Sector per Page, Loop 4 times.)
              for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)
              {
                             // calculate startaddress of each Sector
                             NewDataAddr =nSectorLoop * SECTOR_SIZE;
 
                             // Set address forrandom access
                             NF_CMD(CMD_RDO);
                             NF_ADDR((NewDataAddr)&0xff);
                             NF_ADDR((NewDataAddr>>8)&0xff);
                             NF_CMD(CMD_RDO2);
 
                             // Initialize ECCmodule
                             NF_RSTECC();
                             NF_MECC_UnLock();
                            
                              // Special case to handle un-aligned bufferpointer.
                             if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
                             {
                                           for(i=0;i<SECTOR_SIZE/sizeof(DWORD); i++)
                                           {
                                                         rddata= (DWORD) NF_RDDATA_WORD();
                                                         (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0]= (BYTE)(rddata & 0xff);
                                                         (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]= (BYTE)(rddata>>8 & 0xff);
                                                         (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]= (BYTE)(rddata>>16 & 0xff);
                                                         (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]= (BYTE)(rddata>>24 & 0xff);
                                           }
                             }
                             // usual case tohandle 4byte aligned buffer pointer
                             else
                             {
                                           RdPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);                                                                      // Read page/sector data.
                             }
             
                             NF_MECC_Lock();
                            
                             // Check ECC aboutMain Data with MECC parity codel
                             NF_WRMECCD0(((MECCBuf[nSectorLoop]&0xff00)<<8)|(MECCBuf[nSectorLoop]&0xff) );
                            NF_WRMECCD1(((MECCBuf[nSectorLoop]&0xff000000)>>8)|((MECCBuf[nSectorLoop]&0xff0000)>>16));
 
                             nRetEcc =NF_ECC_ERR0;
             
                             if(!ECC_CorrectData(startSectorAddr, pSectorBuff+nSectorLoop*SECTOR_SIZE,nRetEcc, ECC_CORRECT_MAIN))
                             {
                                           RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_LB_READSECTOR 7\r\n")));
                                           returnFALSE;
                             }
              }</span>


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值