This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Nand 4-bit ECC test

Other Parts Discussed in Thread: OMAPL138

Hi,

I modifed PDK_c6657_1_1_2_6 nand driver for 16bit NAND flash. The Nand page read and page write wokrs. And I would like to know how to test the 4-bit ECC detection and correction.

I tried the following  --

1. Erase a Nand page

1. Wirte a 256-words buffer { 0,1,2,3...255} into the same Nand page--following steps in SPRUZ3A page 3-7,  4-bit ECC calulation Writes (step 1-5)

2. Read the same Nand page. --following steps in SPRUZ3A page 3-7,  4-bit ECC calulation Reads (step 1-13)

3. Modify the above buffer, intentionally change one of words to 0, (Ex, { 0,1,2,3...255}), Overwrite the same Nand page with the modified buffer. During the overwrite, skip all ECC calulation and store steps, (Ex, with SPRUZ3A page 3-7,  4-bit ECC calulation Writes , perform step 2 only, skip step 1,3,4,5)

4. Read the same Nand page. --following steps in SPRUZ3A page 3-7,  4-bit ECC calulation Reads (step 1-13).

Since step 3 perform a overwrite without modifying the stored parity in sapre location, I expect that in step 4 it can detect and restore the overwitten word with the parity calculated for the original buffer.  The test show that it can detect the address of the overwritten word correctly, but fail to restore the original data.

Please advice what's the correct way to test the ECC.

 

GanZ

  • Ganz,

    As a pseudo code to test the ECC part on the NAND, I am attaching the source code we use for checking this feature on another device OMAPL138 that has the same EMIF peripheral. You can modify this test for creating your own test.

    /* --------------------------------------------------------------------------
        FILE        : nandtester.c                                                   
        PURPOSE     : NAND writer main program
        PROJECT     : Dm644x CCS NAND Flashing Utility
        AUTHOR      : Daniel Allred
        DESC        : CCS-based utility to flash the DM644x in preparation for 
                      NAND booting
     ----------------------------------------------------------------------------- */
    
    // C standard I/O library
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    // General type include
    #include "tistdtypes.h"
    
    // Device specific CSL
    #include "device.h"
    
    // This module's header file 
    #include "nandtester.h"
    
    // NAND driver include
    #include "nand.h"
    
    // Misc. utility function include
    #include "util.h"
    
    #include "debug.h"
    
    
    /************************************************************
    * Explicit External Declarations                            *
    ************************************************************/
    
    extern __FAR__ Uint32 NANDStart, ASYNC_CS2_END;
    
    /************************************************************
    * Local Macro Declarations                                  *
    ************************************************************/
    
    #define NANDWIDTH_8
    //#define BAD_BLOCK_MARK
    
    #define STARTING_BLOCK_NUM (1)
    #define STARTING_PAGE_NUM_FOR_ERRORS (2)
    
    
    /************************************************************
    * Local Typedef Declarations                                *
    ************************************************************/
    
    
    /************************************************************
    * Local Function Declarations                               *
    ************************************************************/
    
    static Uint32 nandtester(void);
    static Uint32 LOCAL_writeData(NAND_InfoHandle hNandInfo, Uint32 numDataErr, Uint32 numSpareErr, Uint8 *srcBuf, Uint32 totalPageCnt);
    
    /************************************************************
    * Global Variable Definitions
    ************************************************************/
    
    // Global variables for page buffers 
    static Uint8* gNandTx;
    static Uint8* gNandRx;
    
    #if (1)
    #else
      #pragma DATA_SECTION(ais,".testImage");
      #include "../../GNU/AISutils/t3_dsp_nandtest.h"
    #endif
    
    
    /************************************************************
    * Global Function Definitions                               *
    ************************************************************/
    
    void main( void )
    {
      int status;
    
      // Init memory alloc pointer
      UTIL_setCurrMemPtr(0);
    
      // System init
      if (DEVICE_init() !=E_PASS)
      {
        exit(1);
      }
    
      // Execute the NAND flashing
      status = nandtester();
    
      if (status != E_PASS)
      {
        DEBUG_printString("\n\nNAND ECC test failed!\r\n");
      }
      else
      {
        DEBUG_printString( "\n\nNAND ECC test passed!\r\n" );
      }
    }
    
    
    /************************************************************
    * Local Function Definitions                                *
    ************************************************************/
    
    static Uint32 nandtester()
    {
      Uint32 numPagesAIS;
    
      NAND_InfoHandle  hNandInfo;
    
      FILE  *fPtr;
      Uint8  *aisPtr;
      Int32  aisFileSize = 0,aisAllocSize = 0;
      Int8  fileName[256];
      Int32 i=0;
      Uint32 numDataErr;
      Uint32 numSpareErr;
      Uint32 badBlock;
    
      DEBUG_printString("Starting ");
      DEBUG_printString((String)devString);
      DEBUG_printString(" NANDWriter_ECC_Test.\r\n");
    
      // Initialize NAND Flash
    #if defined(NANDWIDTH_8)
      hNandInfo = NAND_open((Uint32)&NANDStart, DEVICE_BUSWIDTH_8BIT );
    #elif defined(NANDWIDTH_16)
      hNandInfo = NAND_open((Uint32)&NANDStart, DEVICE_BUSWIDTH_16BIT );
    #else
      #error "Must define one of NANDWIDTH_8 or NANDWIDTH_16"
    #endif
      
      if (hNandInfo == NULL)
      {
        DEBUG_printString( "\tERROR: NAND Initialization failed.\r\n" );
        return E_FAIL;
      }
    
      DEBUG_printString("Enter seed for the random number generator:");
      DEBUG_readHexInt(&numDataErr);
      srand(numDataErr);
      
      DEBUG_printString("How many bits of error do you want to test in each sector?\r\n");
      DEBUG_readHexInt(&numDataErr);
      
      DEBUG_printString("How many bits of error do you want to test in the spare area?\r\n");
      DEBUG_readHexInt(&numSpareErr);
    
    #if defined(BAD_BLOCK_MARK)
      DEBUG_printString("Enter block that you want to mark bad?\r\n");
      DEBUG_readHexInt(&badBlock);
    #endif
    
      // Read the file from host
    #if (1)  
      DEBUG_printString("Enter the binary AIS file name to flash (enter 'none' to skip) :\r\n");
      DEBUG_readString(fileName);
      fflush(stdin);
    
      if (strcmp(fileName,"none") != 0)
      {
        // Open an File from the hard drive
        fPtr = fopen(fileName, "rb");
        if(fPtr == NULL)
        {
          DEBUG_printString("\tERROR: File ");
          DEBUG_printString(fileName);
          DEBUG_printString(" open failed.\r\n");
          return E_FAIL;
        }
    
        // Read file size
        fseek(fPtr,0,SEEK_END);
        aisFileSize = ftell(fPtr);
    
        if(aisFileSize == 0)
        {
          DEBUG_printString("\tERROR: File read failed.. Closing program.\r\n");
          fclose (fPtr);
          return E_FAIL;
        }
    
        numPagesAIS = 0;
        while ( (numPagesAIS * hNandInfo->dataBytesPerPage)  < aisFileSize )
        {
          numPagesAIS++;
        }
    
        //We want to allocate an even number of pages.
        aisAllocSize = numPagesAIS * hNandInfo->dataBytesPerPage;
    
        // Setup pointer in RAM
        aisPtr = (Uint8 *) UTIL_allocMem(aisAllocSize);
    
        // Clear memory
        for (i=0; i<aisAllocSize; i++)
          aisPtr[i]=0xFF;
    
        // Go to start of file
        fseek(fPtr,0,SEEK_SET);
    
        // Read file data
        if (aisFileSize != fread(aisPtr, 1, aisFileSize, fPtr))
        {
          DEBUG_printString("\tWARNING: File Size mismatch.\r\n");
        }
    
        // Close file
        fclose (fPtr);
        
        
        
        if (LOCAL_writeData(hNandInfo,numDataErr,numSpareErr,aisPtr,numPagesAIS) != E_PASS)
        {
          printf("\tERROR: Write failed.\r\n");
          return E_FAIL;
        }
    #if defined(BAD_BLOCK_MARK)
        if (NAND_badBlockMark(hNandInfo, badBlock) != E_PASS)
        {
              printf("\tERROR: Marking Bad Block.\r\n");
              return E_FAIL;
        }
    #endif
    
      }
    #else
        aisFileSize = sizeof(ais);
        numPagesAIS = 0;
        while ( (numPagesAIS * hNandInfo->dataBytesPerPage)  < aisFileSize )
        {
          numPagesAIS++;
        }
        
        aisPtr = (Uint8 *) ais;
        
        if (LOCAL_writeData(hNandInfo,numDataErr,numSpareErr,aisPtr,numPagesAIS) != E_PASS)
        {
          printf("\tERROR: Write failed.\r\n");
          return E_FAIL;
        }
    
    #endif
      
      return E_PASS;
    }
    
    // Generic function to write a UBL or Application header and the associated data
    static Uint32 LOCAL_writeData(NAND_InfoHandle hNandInfo, Uint32 numDataErr, Uint32 numSpareErr, Uint8 *srcBuf, Uint32 totalPageCnt)
    {
      Uint32     blockNum,pageNum,pageCnt;
      Uint32     numBlks;
      Uint32     i,j;
      Uint8      *spareBytesBuff, *spareBytesPtr, *dataPtr, *srcBuf2, *dataPtr2;
    
      gNandTx = (Uint8 *) UTIL_allocMem(NAND_MAX_PAGE_SIZE);
      gNandRx = (Uint8 *) UTIL_allocMem(NAND_MAX_PAGE_SIZE);
    
      for (i=0; i<NAND_MAX_PAGE_SIZE; i++)  
      {
        gNandTx[i]=0xff;
        gNandRx[i]=0xff;
      }  
      
      // Get total number of blocks needed
      numBlks = 0;
      while ( (numBlks*hNandInfo->pagesPerBlock)  < totalPageCnt )
      {
        numBlks++;
      }
      DEBUG_printString("Number of blocks needed for data: ");
      DEBUG_printHexInt(numBlks);
      DEBUG_printString("\r\n");
    
      // Start in block 1 (leave block 0 alone)
      blockNum = STARTING_BLOCK_NUM;
    
      // Unprotect all blocks of the device
      if (NAND_unProtectBlocks(hNandInfo, blockNum, (hNandInfo->numBlocks-1)) != E_PASS)
      {
        blockNum++;
        DEBUG_printString("Unprotect failed.\r\n");
        return E_FAIL;
      }
      
      // Allocate memory for the sparebytes to be stored when they are read back
      spareBytesBuff = (Uint8 *) UTIL_allocMem(totalPageCnt * hNandInfo->spareBytesPerPage);
      srcBuf2 = (Uint8 *) UTIL_allocMem(totalPageCnt * hNandInfo->dataBytesPerPage);
      memcpy(srcBuf2,srcBuf,totalPageCnt * hNandInfo->dataBytesPerPage);
      
      while (blockNum < hNandInfo->numBlocks)
      {
        // Find first good block
        //while (NAND_badBlockCheck(hNandInfo,blockNum) != E_PASS)
        //{
        //  blockNum++;
        //}
    
        // Erase the current block
        NAND_eraseBlocks(hNandInfo,blockNum,1);
        NAND_reset(hNandInfo);
    
        // Start writing in page 0 of current block
        pageNum = 0;
        pageCnt = 0;
        blockNum = STARTING_BLOCK_NUM;
    
        // Setup data pointer
        dataPtr = srcBuf;
    
        // Start page writing loop
        do
        {
          DEBUG_printString((String)"Writing image data to block ");
          DEBUG_printHexInt(blockNum);
          DEBUG_printString((String)", page ");
          DEBUG_printHexInt(pageNum);
          DEBUG_printString((String)"\r\n");
    
          // Write the AIS image data to the NAND device
          if (NAND_writePage(hNandInfo, blockNum,  pageNum, dataPtr) != E_PASS)
          {
            DEBUG_printString("Write failed. Marking block as bad...\n");
            NAND_reset(hNandInfo);
            return E_FAIL;
          }
        
          UTIL_waitLoop(200);
        
          // Verify the page just written
          if (NAND_verifyPage(hNandInfo, blockNum, pageNum, dataPtr, gNandRx) != E_PASS)
          {
            DEBUG_printString("Verify failed. Marking block as bad...\n");
            NAND_reset(hNandInfo);
            return E_FAIL;
          }
        
          pageNum++;
          pageCnt++;
          dataPtr +=  hNandInfo->dataBytesPerPage;
      
          if (pageNum == hNandInfo->pagesPerBlock)
          {
            // A block transition needs to take place; go to next good block
            blockNum++;
            
            // Erase the current block
            NAND_eraseBlocks(hNandInfo,blockNum,1);
    
            pageNum = 0;
          }
        } while (pageCnt < totalPageCnt);
        
        // Start spare bytes reading
        spareBytesPtr = spareBytesBuff;
        pageNum = 0;
        pageCnt = 0;
        blockNum = STARTING_BLOCK_NUM;
        do
        {
          // Get good ECC from the spare bytes
          if (NAND_readSpareBytesOfPage(hNandInfo, blockNum, pageNum, spareBytesPtr) != E_PASS)
          {
            DEBUG_printString("Read spare bytes failed\n");
            return E_FAIL;
          }
          
          UTIL_waitLoop(200);
        
          pageNum++;
          pageCnt++;
          spareBytesPtr += hNandInfo->spareBytesPerPage;
            
          if (pageNum == hNandInfo->pagesPerBlock)
          {
            // A block transition needs to take place; go to next good block
            blockNum++;
            pageNum = 0;
          }
        } while (pageCnt < totalPageCnt);
        
        // Introduce errors into spare region data
        if (numSpareErr > 0)
        {
            spareBytesPtr = spareBytesBuff + (STARTING_PAGE_NUM_FOR_ERRORS * hNandInfo->spareBytesPerPage);
            pageCnt = STARTING_PAGE_NUM_FOR_ERRORS;
    
            while (pageCnt < totalPageCnt)
            {
              Uint8 *currSparePtr;
            
              for (i = 0; i< hNandInfo->numOpsPerPage; i++)
              {
                currSparePtr = spareBytesPtr + (i*hNandInfo->spareBytesPerOp);
                
                for (j=0; j<numSpareErr; j++)
                {
                  Uint16 bit = rand() % 80;
    
                  currSparePtr[(bit >> 3) + 6] = currSparePtr[(bit >> 3) + 6] ^ (0x1 << (bit & 0x7));
                  DEBUG_printString("Error introduced at byte ");
                  DEBUG_printHexInt((Uint32) (bit >> 3));
                  DEBUG_printString(",Bit ");
                  DEBUG_printHexInt((Uint32) (bit & 0x7));
                  DEBUG_printString(" of the ECC data of page ");
                  DEBUG_printHexInt((Uint32) pageCnt);
                  DEBUG_printString(", sector ");
                  DEBUG_printHexInt((Uint32) i);              
                  DEBUG_printString(".\r\n");              
                }
              }
    
              pageCnt++;
              spareBytesPtr +=  hNandInfo->spareBytesPerPage;
            }
        }
    
        // Introduce errors into main page data
        if (numDataErr > 0)
        {
            dataPtr2 = srcBuf2 + (STARTING_PAGE_NUM_FOR_ERRORS * hNandInfo->dataBytesPerPage);
            pageCnt = STARTING_PAGE_NUM_FOR_ERRORS;
            while (pageCnt < totalPageCnt)
            {
              Uint8 *currDataPtr;
            
              for (i = 0; i< hNandInfo->numOpsPerPage; i++)
              {
                currDataPtr = dataPtr2 + (i*hNandInfo->dataBytesPerOp);
                
                for (j=0; j<numDataErr; j++)
                {
                  Uint16 bit = rand() % 4096;
                  currDataPtr[bit >> 3] = currDataPtr[bit >> 3] ^ (0x1 << (bit & 0x7));          
                  DEBUG_printString("Error introduced at Byte: ");
                  DEBUG_printHexInt((Uint32) (currDataPtr + (bit >> 3) - srcBuf2));
                  DEBUG_printString(",Bit: ");
                  DEBUG_printHexInt((Uint32) (bit & 0x7));
                  DEBUG_printString(".\r\n");
                }
              }
    
              pageCnt++;
              dataPtr2 +=  hNandInfo->dataBytesPerPage;
            }
        }
        
        // Writing main page data and spare data back with any introduced errors
        if ((numDataErr + numSpareErr) > 0)
        {
    		spareBytesPtr = spareBytesBuff;
    		dataPtr = srcBuf;
    		dataPtr2 = srcBuf2;
    		pageNum = 0;
    		pageCnt = 0;
    		blockNum = STARTING_BLOCK_NUM;
    
    		NAND_eraseBlocks(hNandInfo,blockNum,1);
    		do
    		{
    		  DEBUG_printString((String)"Writing errored image data to block ");
    		  DEBUG_printHexInt(blockNum);
    		  DEBUG_printString((String)", page ");
    		  DEBUG_printHexInt(pageNum);
    		  DEBUG_printString((String)"\r\n");
    
    		  // Write data with the intentional errors in it
    		  if (NAND_writePageWithSpareBytes(hNandInfo, blockNum, pageNum, dataPtr2, spareBytesPtr) != E_PASS)
    		  {
    			DEBUG_printString("Raw Writing with spare bytes data failed\n");
    			NAND_reset(hNandInfo);
    			return E_FAIL;
    		  }
    
    		  UTIL_waitLoop(200);
    
    		  // Verify the page just written (see if correction happens as expected)
    		  if (NAND_verifyPage(hNandInfo, blockNum, pageNum, dataPtr, gNandRx) != E_PASS)
    		  {
    			DEBUG_printString("Verify of errored data failed.\n");
    			NAND_reset(hNandInfo);
    			return E_FAIL;
    		  }
    
    	#if (0)
    		  for(i=0; i<hNandInfo->dataBytesPerPage; i++)
    		  {
    			if (dataPtr2[i] != gNandRx[i])
    			{
    			  Uint32 j = 0;
    			  Uint8 testVal;
    			  // Assume a correction took place
    			  DEBUG_printString("Correction at Byte: ");
    			  DEBUG_printHexInt(i+(Uint32)(dataPtr - srcBuf));
    			  testVal = dataPtr2[i] ^ gNandRx[i];
    			  while (((testVal >> j) & 0x1) != 0x1)
    			  {
    				j++;
    			  }
    
    			  if ((testVal >> j) != 0x1)
    			  {
    				DEBUG_printString("Correction Failed.\r\n");
    				return E_FAIL;
    			  }
    			  else
    			  {
    				DEBUG_printString(", Bit: ");
    				DEBUG_printHexInt(j);
    				DEBUG_printString(".\r\n");
    			  }
    			}
    		  }
    	#endif
    
    		  pageNum++;
    		  pageCnt++;
    		  dataPtr +=  hNandInfo->dataBytesPerPage;
    		  dataPtr2 +=  hNandInfo->dataBytesPerPage;
    		  spareBytesPtr += hNandInfo->spareBytesPerPage;
    
    		  if (pageNum == hNandInfo->pagesPerBlock)
    		  {
    			// A block transition needs to take place; go to next good block
    			blockNum++;
    
    			// Erase the current block
    			NAND_eraseBlocks(hNandInfo,blockNum,1);
    
    			pageNum = 0;
    		  }
    		} while (pageCnt < totalPageCnt);
        }
        break;
      }
      
      NAND_protectBlocks(hNandInfo);
    
      return E_PASS;
    }
    
    
    /***********************************************************
    * End file                                                 
    ************************************************************/
    
    

    Hope this helps.

    Regards,

    Rahul