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.
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