| @@ -1,10 +1,30 @@ | |||
| // RawHardwareTest - Check if a SPI Flash chip is compatible | |||
| // with SerialFlash by performing many read and write tests | |||
| // to its memory. | |||
| // | |||
| // The chip should be fully erased before running this test. | |||
| // Use the EraseEverything to do a (slow) full chip erase. | |||
| // | |||
| // Normally you should NOT access the flash memory directly, | |||
| // as this test program does. You should create files and | |||
| // read and write the files. File creation allocates space | |||
| // with program & erase boundaries within the chip, to allow | |||
| // reading from any other files while a file is busy writing | |||
| // or erasing (if created as erasable). | |||
| // | |||
| // If you discover an incompatible chip, please report it here: | |||
| // https://github.com/PaulStoffregen/SerialFlash/issues | |||
| // You MUST post the complete output of this program, and | |||
| // the exact part number and manufacturer of the chip. | |||
| #include <SerialFlash.h> | |||
| #include <SPI.h> | |||
| SerialFlashFile file; | |||
| //const unsigned long testIncrement = 4096; | |||
| const unsigned long testIncrement = 4194304; | |||
| const unsigned long testIncrement = 4096; | |||
| void setup() { | |||
| @@ -21,45 +41,11 @@ void setup() { | |||
| test(); | |||
| } | |||
| void print_signature(const unsigned char *data) | |||
| { | |||
| Serial.print("data="); | |||
| for (unsigned char i=0; i < 8; i++) { | |||
| Serial.print(data[i]); | |||
| Serial.print(" "); | |||
| } | |||
| Serial.println(); | |||
| } | |||
| void create_signature(unsigned long address, unsigned char *data) | |||
| { | |||
| data[0] = address >> 24; | |||
| data[1] = address >> 16; | |||
| data[2] = address >> 8; | |||
| data[3] = address; | |||
| unsigned long hash = 2166136261ul; | |||
| for (unsigned char i=0; i < 4; i++) { | |||
| hash ^= data[i]; | |||
| hash *= 16777619ul; | |||
| } | |||
| data[4] = hash; | |||
| data[5] = hash >> 8; | |||
| data[6] = hash >> 16; | |||
| data[7] = hash >> 24; | |||
| } | |||
| bool equal_signatures(const unsigned char *data1, const unsigned char *data2) | |||
| { | |||
| for (unsigned char i=0; i < 8; i++) { | |||
| if (data1[i] != data2[i]) return false; | |||
| } | |||
| return true; | |||
| } | |||
| bool test() { | |||
| unsigned char buf[16], sig[16], erased[16]; | |||
| unsigned long address, count, chipsize; | |||
| unsigned char buf[256], sig[256], buf2[8]; | |||
| unsigned long address, count, chipsize, blocksize; | |||
| unsigned long usec; | |||
| bool first; | |||
| // Read the chip identification | |||
| @@ -79,32 +65,19 @@ bool test() { | |||
| Serial.print(chipsize); | |||
| Serial.println(" bytes"); | |||
| if (chipsize == 0) return false; | |||
| //chipsize = 0x20000; | |||
| //Serial.println("erasing a couple small blocks...."); | |||
| //SerialFlash.eraseBlock(0x00000000); | |||
| //SerialFlash.eraseBlock(0x00010000); | |||
| //while (!SerialFlash.ready()); // wait | |||
| //Serial.println(); | |||
| //Serial.println("read locations in memory..."); | |||
| //SerialFlash.read(0x0000000, buf, 12); | |||
| //printbuf(buf, 12); | |||
| //SerialFlash.read(0x1000000, buf, 12); | |||
| //printbuf(buf, 12); | |||
| //SerialFlash.read(0x2000000, buf, 12); | |||
| //printbuf(buf, 12); | |||
| //SerialFlash.read(0x3000000, buf, 12); | |||
| //printbuf(buf, 12); | |||
| Serial.print(" Block Size: "); | |||
| blocksize = SerialFlash.blockSize(); | |||
| Serial.print(blocksize); | |||
| Serial.println(" bytes"); | |||
| // Read the entire chip. Every test location must be | |||
| // erased, or have a previously tested signature | |||
| for (unsigned char i=0; i < 8; i++) { | |||
| erased[i] = 255; | |||
| } | |||
| Serial.println(); | |||
| Serial.println("Reading Chip..."); | |||
| memset(buf, 0, sizeof(buf)); | |||
| memset(sig, 0, sizeof(sig)); | |||
| memset(buf2, 0, sizeof(buf2)); | |||
| address = 0; | |||
| count = 0; | |||
| first = true; | |||
| @@ -115,7 +88,7 @@ bool test() { | |||
| //Serial.print(", data = "); | |||
| //printbuf(buf, 8); | |||
| create_signature(address, sig); | |||
| if (equal_signatures(buf, erased) == false) { | |||
| if (is_erased(buf, 8) == false) { | |||
| if (equal_signatures(buf, sig) == false) { | |||
| Serial.print(" Previous data found at address "); | |||
| Serial.println(address); | |||
| @@ -124,8 +97,6 @@ bool test() { | |||
| printbuf(buf, 8); | |||
| Serial.print(" correct: "); | |||
| printbuf(sig, 8); | |||
| Serial.print(" erased: "); | |||
| printbuf(erased, 8); | |||
| return false; | |||
| } | |||
| } else { | |||
| @@ -140,20 +111,24 @@ bool test() { | |||
| } | |||
| } | |||
| // Write any signatures that were blank on the original check | |||
| if (count > 0) { | |||
| Serial.println(); | |||
| Serial.print("Writing "); | |||
| Serial.print(count); | |||
| Serial.println(" signatures"); | |||
| memset(buf, 0, sizeof(buf)); | |||
| memset(sig, 0, sizeof(sig)); | |||
| memset(buf2, 0, sizeof(buf2)); | |||
| address = 0; | |||
| first = true; | |||
| while (address < chipsize) { | |||
| SerialFlash.read(address, buf, 8); | |||
| if (equal_signatures(buf, erased)) { | |||
| if (is_erased(buf, 8)) { | |||
| create_signature(address, sig); | |||
| Serial.printf("write %08X: data: ", address); | |||
| printbuf(sig, 8); | |||
| //Serial.printf("write %08X: data: ", address); | |||
| //printbuf(sig, 8); | |||
| SerialFlash.write(address, sig, 8); | |||
| while (!SerialFlash.ready()) ; // wait | |||
| SerialFlash.read(address, buf, 8); | |||
| @@ -179,9 +154,14 @@ bool test() { | |||
| Serial.println(" all signatures present from prior tests"); | |||
| } | |||
| // Read all the signatures again, just to be sure | |||
| // checks prior writing didn't corrupt any other data | |||
| Serial.println(); | |||
| Serial.println("Double Checking All Signatures:"); | |||
| memset(buf, 0, sizeof(buf)); | |||
| memset(sig, 0, sizeof(sig)); | |||
| memset(buf2, 0, sizeof(buf2)); | |||
| count = 0; | |||
| address = 0; | |||
| first = true; | |||
| @@ -210,9 +190,14 @@ bool test() { | |||
| Serial.print(count); | |||
| Serial.println(" signatures read ok"); | |||
| // Read pairs of adjacent signatures | |||
| // check read works across boundaries | |||
| Serial.println(); | |||
| Serial.println("Checking Signature Pairs"); | |||
| memset(buf, 0, sizeof(buf)); | |||
| memset(sig, 0, sizeof(sig)); | |||
| memset(buf2, 0, sizeof(buf2)); | |||
| count = 0; | |||
| address = testIncrement - 8; | |||
| first = true; | |||
| @@ -237,6 +222,136 @@ bool test() { | |||
| Serial.println(" signature pairs read ok"); | |||
| // Write data and read while write in progress | |||
| Serial.println(); | |||
| Serial.println("Checking Read-While-Write (Program Suspend)"); | |||
| address = 256; | |||
| while (address < chipsize) { // find a blank space | |||
| SerialFlash.read(address, buf, 256); | |||
| if (is_erased(buf, 256)) break; | |||
| address = address + 256; | |||
| } | |||
| if (address >= chipsize) { | |||
| Serial.println(" error, unable to find any blank space!"); | |||
| return false; | |||
| } | |||
| for (int i=0; i < 256; i += 8) { | |||
| create_signature(address + i, sig + i); | |||
| } | |||
| Serial.print(" write 256 bytes at "); | |||
| Serial.println(address); | |||
| Serial.flush(); | |||
| SerialFlash.write(address, sig, 256); | |||
| usec = micros(); | |||
| if (SerialFlash.ready()) { | |||
| Serial.println(" error, chip did not become busy after write"); | |||
| return false; | |||
| } | |||
| SerialFlash.read(0, buf2, 8); // read while busy writing | |||
| while (!SerialFlash.ready()) ; // wait | |||
| usec = micros() - usec; | |||
| Serial.print(" write time was "); | |||
| Serial.print(usec); | |||
| Serial.println(" microseconds."); | |||
| SerialFlash.read(address, buf, 256); | |||
| if (memcmp(buf, sig, 256) != 0) { | |||
| Serial.println(" error writing to flash"); | |||
| Serial.print(" Read this: "); | |||
| printbuf(buf, 256); | |||
| Serial.print(" Expected: "); | |||
| printbuf(sig, 256); | |||
| return false; | |||
| } | |||
| create_signature(0, sig); | |||
| if (memcmp(buf2, sig, 8) != 0) { | |||
| Serial.println(" error, incorrect read while writing"); | |||
| Serial.print(" Read this: "); | |||
| printbuf(buf2, 256); | |||
| Serial.print(" Expected: "); | |||
| printbuf(sig, 256); | |||
| return false; | |||
| } | |||
| Serial.print(" read-while-writing: "); | |||
| printbuf(buf2, 8); | |||
| Serial.println(" test passed, good read while writing"); | |||
| // Erase a block and read while erase in progress | |||
| if (chipsize >= 262144 + blocksize + testIncrement) { | |||
| Serial.println(); | |||
| Serial.println("Checking Read-While-Erase (Erase Suspend)"); | |||
| memset(buf, 0, sizeof(buf)); | |||
| memset(sig, 0, sizeof(sig)); | |||
| memset(buf2, 0, sizeof(buf2)); | |||
| SerialFlash.eraseBlock(262144); | |||
| usec = micros(); | |||
| delayMicroseconds(50); | |||
| if (SerialFlash.ready()) { | |||
| Serial.println(" error, chip did not become busy after erase"); | |||
| return false; | |||
| } | |||
| SerialFlash.read(0, buf2, 8); // read while busy writing | |||
| while (!SerialFlash.ready()) ; // wait | |||
| usec = micros() - usec; | |||
| Serial.print(" erase time was "); | |||
| Serial.print(usec); | |||
| Serial.println(" microseconds."); | |||
| // read all signatures, check ones in this block got | |||
| // erased, and all the others are still intact | |||
| address = 0; | |||
| first = true; | |||
| while (address < chipsize) { | |||
| SerialFlash.read(address, buf, 8); | |||
| if (address >= 262144 && address < 262144 + blocksize) { | |||
| if (is_erased(buf, 8) == false) { | |||
| Serial.print(" error in erasing at "); | |||
| Serial.println(address); | |||
| Serial.print(" Read this: "); | |||
| printbuf(buf, 8); | |||
| return false; | |||
| } | |||
| } else { | |||
| create_signature(address, sig); | |||
| if (equal_signatures(buf, sig) == false) { | |||
| Serial.print(" error in signature at "); | |||
| Serial.println(address); | |||
| Serial.print(" Read this: "); | |||
| printbuf(buf, 8); | |||
| Serial.print(" Expected: "); | |||
| printbuf(sig, 8); | |||
| return false; | |||
| } | |||
| } | |||
| if (first) { | |||
| address = address + (testIncrement - 8); | |||
| first = false; | |||
| } else { | |||
| address = address + 8; | |||
| first = true; | |||
| } | |||
| } | |||
| Serial.print(" erase correctly erased "); | |||
| Serial.print(blocksize); | |||
| Serial.println(" bytes"); | |||
| // now check if the data we read during erase is good | |||
| create_signature(0, sig); | |||
| if (memcmp(buf2, sig, 8) != 0) { | |||
| Serial.println(" error, incorrect read while erasing"); | |||
| Serial.print(" Read this: "); | |||
| printbuf(buf2, 256); | |||
| Serial.print(" Expected: "); | |||
| printbuf(sig, 256); | |||
| return false; | |||
| } | |||
| Serial.print(" read-while-erasing: "); | |||
| printbuf(buf2, 8); | |||
| Serial.println(" test passed, good read while erasing"); | |||
| } else { | |||
| Serial.println("Skip Read-While-Erase, this chip is too small"); | |||
| } | |||
| @@ -305,6 +420,50 @@ const char * id2chip(const unsigned char *id) | |||
| return "(unknown chip)"; | |||
| } | |||
| void print_signature(const unsigned char *data) | |||
| { | |||
| Serial.print("data="); | |||
| for (unsigned char i=0; i < 8; i++) { | |||
| Serial.print(data[i]); | |||
| Serial.print(" "); | |||
| } | |||
| Serial.println(); | |||
| } | |||
| void create_signature(unsigned long address, unsigned char *data) | |||
| { | |||
| data[0] = address >> 24; | |||
| data[1] = address >> 16; | |||
| data[2] = address >> 8; | |||
| data[3] = address; | |||
| unsigned long hash = 2166136261ul; | |||
| for (unsigned char i=0; i < 4; i++) { | |||
| hash ^= data[i]; | |||
| hash *= 16777619ul; | |||
| } | |||
| data[4] = hash; | |||
| data[5] = hash >> 8; | |||
| data[6] = hash >> 16; | |||
| data[7] = hash >> 24; | |||
| } | |||
| bool equal_signatures(const unsigned char *data1, const unsigned char *data2) | |||
| { | |||
| for (unsigned char i=0; i < 8; i++) { | |||
| if (data1[i] != data2[i]) return false; | |||
| } | |||
| return true; | |||
| } | |||
| bool is_erased(const unsigned char *data, unsigned int len) | |||
| { | |||
| while (len > 0) { | |||
| if (*data++ != 255) return false; | |||
| len = len - 1; | |||
| } | |||
| return true; | |||
| } | |||
| void printbuf(const void *buf, uint32_t len) | |||
| { | |||