//--------------------------------------------------------- // SST39VFxxxx Flash: XJEase device file // SST39VFxxxx.xje Revision: 1.13 // (c)2001-2008 XJTAG Limited // // Disclaimer: XJTAG makes no guarantees whatsoever // about this code. You use it at your own risk ... // This code requires XJTAG version 1.4 or later. // // This file tests Non-JTAG Flash using TestNonDestructive()(INT result) // TestDestructive()(INT result) //--------------------------------------------------------- DEVICE NAME := "SST39VFxxxx" PINS /* // Standard 48-pin TSOP (SST39VF1601/1602) ADDR := 9, 16, 17, 48, 1, 2, 3, 4, 5, 6, 7, 8, 18, 19, 20, 21, 22, 23, 24, 25; DATA := 45, 43, 41, 39, 36, 34, 32, 30, 44, 42, 40, 38, 35, 33, 31, 29; NCE := 26; NOE := 28; NWE := 11; NRESET := 12; nWP := 14; // Standard 48-pin TSOP (SST39VF3201/3202) ADDR := 10, 9, 16, 17, 48, 1, 2, 3, 4, 5, 6, 7, 8, 18, 19, 20, 21, 22, 23, 24, 25; DATA := 45, 43, 41, 39, 36, 34, 32, 30, 44, 42, 40, 38, 35, 33, 31, 29; NCE := 26; NOE := 28; NWE := 11; NRESET := 12; nWP := 14; // Standard 48-pin TSOP (SST39VF6401/6402) ADDR := 13, 10, 9, 16, 17, 48, 1, 2, 3, 4, 5, 6, 7, 8, 18, 19, 20, 21, 22, 23, 24, 25; DATA := 45, 43, 41, 39, 36, 34, 32, 30, 44, 42, 40, 38, 35, 33, 31, 29; NCE := 26; NOE := 28; NWE := 11; NRESET := 12; nWP := 14; // 64-ball fine-pitch BGA (SST39VF1601/1602) ADDR := D4, C3, B2, E6, D6, C6, A6, B6, D5, C5, A5, B5, A2, C2, D2, B1, A1, C1, D1, E1; DATA := G6, F5, G5, F4, G3, F3, G2, F2, E5, H5, E4, H4, H3, E3, H2, E2; NCE := F1; NOE := G1; NWE := B3; NRESET := B4; nWP := B3; */ // 64-ball fine-pitch BGA (SST39VF3201/3202) ADDR := D3, D4, C3, B2, E6, D6, C6, A6, B6, D5, C5, A5, B5, A2, C2, D2, B1, A1, C1, D1, E1; DATA := G6, F5, G5, F4, G3, F3, G2, F2, E5, H5, E4, H4, H3, E3, H2, E2; NCE := F1; NOE := G1; NWE := B3; NRESET := B4; nWP := B3; /* // 64-ball fine-pitch BGA (SST39VF6401/6402) ADDR := C4, D3, D4, C3, B2, E6, D6, C6, A6, B6, D5, C5, A5, B5, A2, C2, D2, B1, A1, C1, D1, E1; DATA := G6, F5, G5, F4, G3, F3, G2, F2, E5, H5, E4, H4, H3, E3, H2, E2; NCE := F1; NOE := G1; NWE := B3; NRESET := B4; nWP := B3; */ END; DISABLE DEVICE NCE := 1; NOE := 1; END; TEST COVERAGE ADDR := SHORTS OPEN HI LO; DATA := SHORTS OPEN HI LO; NCE := OPEN HI LO; NOE := OPEN HI LO; NWE := OPEN HI LO; END; FILES "memtestFlash.xje"; //"DataReader.xje"; END; END; // Commands: address INT ADDR_UNLOCK_1 := 0x5555; INT ADDR_UNLOCK_2 := 0x2AAA; INT ADDR_AUTOSELECT := 0x5555; INT ADDR_PROGRAM := 0x5555; INT ADDR_ERASE_SETUP := 0x5555; INT ADDR_ERASE := 0x5555; INT ADDR_MAN_ID := 0x0000; INT ADDR_DEV_ID := 0x0001; INT DATA_UNLOCK_1 := 0xAA; INT DATA_UNLOCK_2 := 0x55; INT DATA_AUTOSELECT := 0x90; INT DATA_PROGRAM := 0xA0; INT DATA_ERASE_SETUP := 0x80; INT DATA_ERASE_ALL := 0x10; INT DATA_ERASE_BLOCK := 0x50; INT DATA_ERASE_SEC := 0x30; // SST39VFxxxx IDs INT MANUFACTURER_ID := 0xBF; //INT DEVICE_ID := 0x234B; // SST39VF1601 //INT DEVICE_ID := 0x234A; // SST39VF1602 //INT DEVICE_ID := 0x235B; // SST39VF3201 INT DEVICE_ID := 0x235A; // SST39VF3202 //INT DEVICE_ID := 0x236B; // SST39VF6401 //INT DEVICE_ID := 0x236A; // SST39VF6402 CONST INT DATA_BUS_WIDTH := WIDTHOF(DATA); CONST INT ADDR_BUS_WIDTH := WIDTHOF(ADDR); CONST INT FLASH_SIZE := (1<<ADDR_BUS_WIDTH)*DATA_BUS_WIDTH; CONST INT BLOCK_LENGTH := (0x10000/DATA_BUS_WIDTH)*8; // For boot sector devices, use larger block size CONST INT RESULT_PASS := FALSE; CONST INT RESULT_FAIL := TRUE; CONST INT FLASH_PROG_LEVEL_NONE := 0; // Flash erased everywhere CONST INT FLASH_PROG_LEVEL_SOME := 1; // Flash programmed enough to verify data/addr bus for opens/stucks and data bus // for shorts. Ie. Data written to a single block, or small number of blocks. CONST INT FLASH_PROG_LEVEL_LOTS := 2; // Flash programmed enough to data/addr bus for opens/stucks and shorts. // Ie. Data written to a large number of blocks. //------------------------------------------------------------------------ // The higher this level is set, the more test coverage will be attained. // The aim is to set the highest level possible with the test still passing. // If the flash is totally erased, the test will only pass if this variable // is set to FLASH_PROG_LEVEL_NONE. //------------------------------------------------------------------------ CONST INT FLASH_PROG_LEVEL := FLASH_PROG_LEVEL_NONE; // Globals INT DEBUG := FALSE; INT ALL_ONES WIDTH FLASH_SIZE := ~0[(FLASH_SIZE-1)..0]; INT dataSet WIDTH FLASH_SIZE; //------------------------------------------------------------------------ // Includes Read ID test and optional Readonly Data and Address bus tests. // The optional test only be used if the flash has been sufficiently // programmed (by setting FlASH_PROGRAMMED to TRUE). // Much quicker alternative to Destructive test. //------------------------------------------------------------------------ TestNonDestructive()(INT result) INT tempResult; result := RESULT_PASS; IF (WRITEABLE(NRESET)) THEN SET NRESET := 0; SET NRESET := 1; END; PRINT("\n\nStarting Read ID test...\n"); ReadIDtest()(result); IF (FLASH_PROG_LEVEL > FLASH_PROG_LEVEL_NONE) THEN PRINT("\nStarting Non-Destructive memory test\n"); MemTestNonDestructive()(tempResult); IF tempResult = RESULT_FAIL THEN result := RESULT_FAIL; END; ELSE PRINT("FLASH_PROG_LEVEL currently set to FLASH_PROG_LEVEL_NONE\nAlthough the ReadID test excersises the data/addr bus and control lines,\na more comprehensive test can be done by changing FLASH_PROG_LEVEL\nThis can only be done if the flash is progammed (see device file for more information).\n\n"); END; IF result = RESULT_FAIL THEN PRINT("Non Destructive Memory Test FAILED...\n\n"); ELSE PRINT("Non Destructive Memory Test PASSED...\n\n"); END; END; //------------------------------------------------------------------------ // Includes Read ID test, and optimised destructive memory test. // Slower than non destructive test, but more reliable. //------------------------------------------------------------------------ TestDestructive()(INT result) INT tempResult; result := RESULT_PASS; IF (WRITEABLE(NRESET)) THEN SET NRESET := 0; SET NRESET := 1; END; PRINT("\n\nStarting Read ID test...\n"); ReadIDtest()(result); PRINT("\nStarting Destructive memory test\n"); IF (result = RESULT_PASS) THEN MemTestDestructive()(tempResult); IF tempResult = RESULT_FAIL THEN result := RESULT_FAIL; END; ELSE TestDetail(TRUE)(); END; IF ((result = RESULT_PASS) && WRITEABLE(NCE)) THEN PRINT("\nTesting Chip Enable\n"); TestChipEnable()(result); IF result = RESULT_FAIL THEN PRINT("Chip Enable - pin: ",PINNUM(NCE)," stuck low\n"); END; END; IF result = RESULT_FAIL THEN PRINT("Destructive Memory Test FAILED...\n"); ELSE PRINT("Destructive Memory Test PASSED...\n"); END; END; //------------------------------------------------------ // ReadIDTest //------------------------------------------------------ ReadIDtest()(INT result) INT manufacturer; INT device; PRINT ("Checking Flash ", DEVICE_REF, " ID codes...\n "); ResetFlash()(); result := RESULT_FAIL; // Read Flash IDs. ReadID()(manufacturer, device); ResetFlash()(); manufacturer := manufacturer[7..0]; IF DEBUG THEN PRINT("Manufacturer ID = 0x", HEX(manufacturer), ", "); PRINT("Device ID = 0x", HEX(device), ", \n"); END; // Check the IDs. IF ((manufacturer != MANUFACTURER_ID) || (device != DEVICE_ID)) THEN PRINT("Read Manufacturer ID : 0x", HEX(manufacturer), ", expected to read 0x",HEX(MANUFACTURER_ID),"\n"); PRINT("Read Device ID = 0x", HEX(device), ", expected to read 0x", HEX(DEVICE_ID),"\n"); PRINT("failed.\n"); result := RESULT_FAIL; RETURN; END; PRINT("Flash IDs verified\n"); result := RESULT_PASS; END; //------------------------------------------------------ // EraseAll //------------------------------------------------------ EraseAll()(INT result) IF DEBUG THEN PRINT("Erasing all flash contents.\n"); END; ResetFlash()(); // Two unlock cycles WriteCycle(ADDR_UNLOCK_1, DATA_UNLOCK_1); WriteCycle(ADDR_UNLOCK_2, DATA_UNLOCK_2); // Set-up command WriteCycle(ADDR_ERASE_SETUP, DATA_ERASE_SETUP); // Two unlock write cycles WriteCycle(ADDR_UNLOCK_1, DATA_UNLOCK_1); WriteCycle(ADDR_UNLOCK_2, DATA_UNLOCK_2); // Chip erase command WriteCycle(ADDR_ERASE, DATA_ERASE_ALL); // Poll for erase complete WaitReady(0xffff, 0xffffffff)(result); IF (result != RESULT_PASS) THEN PRINT("Flash not ready after EraseAll\n"); RETURN; END; ResetFlash()(); result := RESULT_PASS; IF DEBUG THEN PRINT("Erased all OK\n"); END; END; //------------------------------------------------------ // EraseBlock //------------------------------------------------------ EraseBlock(INT address)(INT result) result := RESULT_FAIL; IF DEBUG THEN PRINT ("Erase flash block at 0x", HEX(address), "\n"); END; // Two unlock cycles WriteCycle(ADDR_UNLOCK_1, DATA_UNLOCK_1); WriteCycle(ADDR_UNLOCK_2, DATA_UNLOCK_2); // Set-up command WriteCycle(ADDR_ERASE_SETUP, DATA_ERASE_SETUP); // Two unlock write cycles WriteCycle(ADDR_UNLOCK_1, DATA_UNLOCK_1); WriteCycle(ADDR_UNLOCK_2, DATA_UNLOCK_2); // Chip erase command WriteCycle(address, DATA_ERASE_SEC); WaitReady(0xffff, 5000)(result); // data is effectively FF, since erasing sets to 1s IF (result != RESULT_PASS) THEN PRINT("Flash not ready after erase.\n"); RETURN; END; result := RESULT_PASS; IF DEBUG THEN PRINT("Block erased.\n"); END; END; //------------------------------------------------------ // Checks the chip enable pin isn't stuck low //------------------------------------------------------ TestChipEnable()(INT result) INT data; INT temp; result := RESULT_PASS; EraseBlock(0)(temp); WriteCycle(ADDR_UNLOCK_1, DATA_UNLOCK_1); WriteCycle(ADDR_UNLOCK_2, DATA_UNLOCK_2); WriteCycle(ADDR_PROGRAM, DATA_PROGRAM); // try programming with nCE held high SET ADDR := 0; SET NWE := 0, NCE := 1, NOE := 1, DATA := 0; SET NCE := 1, NOE := 1, DATA := I, NWE := 1; WaitReady(0x80, 100)(temp); ReadWord(0)(data); IF data = 0 THEN result := RESULT_FAIL; END; END; //------------------------------------------------------ // ProgramWord // Write a word to the flash //------------------------------------------------------ ProgramWord(INT address, INT data)(INT result) INT read_data; IF DEBUG THEN PRINT ("Program 0x", HEX(data), " to 0x", HEX(address), "\n"); END; WriteCycle(ADDR_UNLOCK_1, DATA_UNLOCK_1); WriteCycle(ADDR_UNLOCK_2, DATA_UNLOCK_2); WriteCycle(ADDR_PROGRAM, DATA_PROGRAM); WriteCycle(address, data); WaitReady(data, 100)(result); IF (result != RESULT_PASS) THEN PRINT("Flash not ready after program byte.\n"); RETURN; END; result := RESULT_PASS; IF DEBUG THEN PRINT("Word programmed OK.\n"); END; END; //------------------------------------------------------ // ReadWord // Read a word from the flash //------------------------------------------------------ ReadWord(INT address)(INT data) ResetFlash()(); ReadCycle(address)(data); IF DEBUG THEN PRINT ("Read addr 0x", HEX(address), " = 0x", HEX(data), "\n"); END; END; //------------------------------------------------------ // ResetFlash //------------------------------------------------------ ResetFlash()() WriteCycle(0, 0xF0); // Reset and switch to read array mode. END; //------------------------------------------------------ // ReadID // Read the manufacturer and device IDs. //------------------------------------------------------ ReadID()(INT manufacturer, INT device) INT timeout; // Go into autoselect mode. WriteCycle(ADDR_UNLOCK_1, DATA_UNLOCK_1); WriteCycle(ADDR_UNLOCK_2, DATA_UNLOCK_2); WriteCycle(ADDR_AUTOSELECT, DATA_AUTOSELECT); // Read the manufacturer ID. ReadCycle(ADDR_MAN_ID)(manufacturer); // Read the device ID. ReadCycle(ADDR_DEV_ID)(device); END; //------------------------------------------------------ WaitReady (INT data, INT delay)(INT result) //------------------------------------------------------ INT status; INT timeout := NOW() + delay; result := RESULT_PASS; DO ReadCycle(0)(status); WHILE (status[7] != data[7]) IF NOW() > timeout THEN result := RESULT_FAIL; PRINT("\n*** Timeout waiting for flash ready ***\n"); RETURN; END; END; END; //------------------------------------------------------ // WriteCycle // Address latched on falling edge of nWE or nCE // Data latched on rising edge of nWE //------------------------------------------------------ WriteCycle(INT address, INT code)() SET ADDR := address[ADDR_BUS_WIDTH-1..0]; SET NWE := 0, NCE := 0, NOE := 1, DATA := code[DATA_BUS_WIDTH-1..0]; SET NCE := 1, NOE := 1, DATA := I, NWE := 1; END; //------------------------------------------------------ // ReadCycle // Address latched on falling edge of NCE // Data latched on rising edge of nCE //------------------------------------------------------ ReadCycle(INT address)(INT result) SET ADDR := address[ADDR_BUS_WIDTH-1..0], DATA := I; SET NWE := 1, NCE := 0, NOE := 0; SET result := DATA, NCE := 1, NOE := 1, NWE := 1; END; //---------------------------------------------------------------------------------- // Functions required for use of device file with memtestFlash.xje //---------------------------------------------------------------------------------- PrintData(INT i)() PRINT(PINNUM(DATA[i])); END; PrintAddr(INT i)() PRINT(PINNUM(ADDR[i])); END; /*********************FLASH PROGRAMMING*********************************** //------------------------------------------------------ // ProgramFromSRecordFile // Program the flash from an S Record file //------------------------------------------------------ ProgramFromSRecordFile(STRING fileName)(INT result) INT addrLow; INT addrHigh; INT address; PRINT("\n\nStarting flash programming from file ",fileName,"\n"); dataSet := ALL_ONES; ReadSRecordFile(fileName, 0, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); ProgramFlash(addrLow, addrHigh - addrLow, dataSet)(result); // optional verification of memory written to flash VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // ProgramFromHexFile // Program the flash from a HEX file //------------------------------------------------------ ProgramFromHexFile(STRING fileName)(INT result) INT addrLow; INT addrHigh; INT address; dataSet := ALL_ONES; ReadHEXFile(fileName, 0, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); ProgramFlash(addrLow, addrHigh - addrLow, dataSet)(result); // optional verification of memory written to flash VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // ProgramFromBinFile // Program the flash from a BIN file //------------------------------------------------------ ProgramFromBINFile(STRING fileName)(INT result) INT addrLow; INT addrHigh; INT address; dataSet := ALL_ONES; ReadBINFile(fileName, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); ProgramFlash(addrLow, addrHigh - addrLow, dataSet)(result); // optional verification of memory written to flash VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // Program Flash using "dataSet" variable. //------------------------------------------------------ ProgramFlash(INT addrLow, INT numAddresses, INT dataSet)(INT result) //------------------------------------------------------ INT address; INT count := 0; INT tempCount :=0; result := RESULT_FAIL; address := addrLow; FOR address := addrLow FOR numAddresses ProgramWord(address, dataSet[(address+1)*DATA_BUS_WIDTH -1..address*DATA_BUS_WIDTH])(result); IF (result != RESULT_PASS) THEN PRINT("ProgramWord failed in ProgramFile\n"); RETURN; END; tempCount := ((address - addrLow)*100)/numAddresses; IF (tempCount != count && tempCount%5 = 0) THEN PRINT(tempCount, " percent programming complete\r"); count := tempCount; END; END; PRINT("Programming complete \n"); END; //----------------------------------------------------------------- // VerifyFlash with a given dataSet //----------------------------------------------------------------- VerifyFlash(INT dataSet, INT addrLow, INT numAddresses)(INT result) //----------------------------------------------------------------- INT data WIDTH DATA_BUS_WIDTH; INT expectedData WIDTH DATA_BUS_WIDTH; INT address; INT count := 0; INT tempCount :=0; result := RESULT_FAIL; PRINT("Attempting to verify programmed data\n"); ResetFlash()(); FOR address := addrLow FOR numAddresses ReadCycle(address)(data); expectedData := dataSet[(address+1)*DATA_BUS_WIDTH-1..address*DATA_BUS_WIDTH]; IF (expectedData != data) THEN result := RESULT_FAIL; PRINT("\n*** Verify error at address 0x", HEX(address), ", data=0x", HEX(data), ", expected data=0x", HEX(expectedData), " ***\n"); RETURN; END; tempCount := ((address - addrLow)*100)/numAddresses; IF (tempCount != count && tempCount%5 = 0) THEN PRINT(tempCount, " percent verifying complete\r"); count := tempCount; END; END; PRINT("Verified OK. \n"); result := RESULT_PASS; END; //------------------------------------------------------ // Verify flash from a BIN file //------------------------------------------------------ VerifyFlashFromBINFile(STRING fileName)(INT result) //------------------------------------------------------ INT addrLow; INT addrHigh; result := RESULT_FAIL; dataSet := ALL_ONES; ReadBINFile(fileName, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); IF (result = RESULT_FAIL) THEN PRINT("BIN file failed to be read\n"); END; VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // Verify flash from a HEX file //------------------------------------------------------ VerifyFlashFromHEXFile(STRING fileName)(INT result) //------------------------------------------------------ INT addrLow; INT addrHigh; result := RESULT_FAIL; dataSet := ALL_ONES; ReadHEXFile(fileName, 0, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); IF (result = RESULT_FAIL) THEN PRINT("HEX file failed to be read\n"); END; VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // Verify flash from an S Record file //------------------------------------------------------ VerifyFlashFromSRecordFile(STRING fileName)(INT result) //------------------------------------------------------ INT addrLow; INT addrHigh; result := RESULT_FAIL; dataSet := ALL_ONES; ReadSRecordFile(fileName, 0, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); IF (result = RESULT_FAIL) THEN PRINT("S-Record file failed to be read\n"); END; VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // ReadFlash // Read the flash and write contents in binary // format to an open file //------------------------------------------------------ ReadFlash(FILE fp, INT address, INT length)(INT result) INT endAddress := address + length; INT data; IF DEBUG THEN PRINT("Reading Flash\n"); END; ResetFlash()(); result := RESULT_FAIL; DO WHILE address <= endAddress ReadCycle(address)(data); FWRITE(fp, data[0..(DATA_BUS_WIDTH-1)])(); address := address + 1; END; result := RESULT_PASS; IF DEBUG THEN PRINT("Read completed OK\n"); END; END; *************************************************************************/