| // 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 <SerialFlash.h> | ||||
| #include <SPI.h> | #include <SPI.h> | ||||
| SerialFlashFile file; | SerialFlashFile file; | ||||
| //const unsigned long testIncrement = 4096; | |||||
| const unsigned long testIncrement = 4194304; | |||||
| const unsigned long testIncrement = 4096; | |||||
| void setup() { | void setup() { | ||||
| test(); | 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() { | 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; | bool first; | ||||
| // Read the chip identification | // Read the chip identification | ||||
| Serial.print(chipsize); | Serial.print(chipsize); | ||||
| Serial.println(" bytes"); | Serial.println(" bytes"); | ||||
| if (chipsize == 0) return false; | 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 | // Read the entire chip. Every test location must be | ||||
| // erased, or have a previously tested signature | // erased, or have a previously tested signature | ||||
| for (unsigned char i=0; i < 8; i++) { | |||||
| erased[i] = 255; | |||||
| } | |||||
| Serial.println(); | Serial.println(); | ||||
| Serial.println("Reading Chip..."); | Serial.println("Reading Chip..."); | ||||
| memset(buf, 0, sizeof(buf)); | |||||
| memset(sig, 0, sizeof(sig)); | |||||
| memset(buf2, 0, sizeof(buf2)); | |||||
| address = 0; | address = 0; | ||||
| count = 0; | count = 0; | ||||
| first = true; | first = true; | ||||
| //Serial.print(", data = "); | //Serial.print(", data = "); | ||||
| //printbuf(buf, 8); | //printbuf(buf, 8); | ||||
| create_signature(address, sig); | create_signature(address, sig); | ||||
| if (equal_signatures(buf, erased) == false) { | |||||
| if (is_erased(buf, 8) == false) { | |||||
| if (equal_signatures(buf, sig) == false) { | if (equal_signatures(buf, sig) == false) { | ||||
| Serial.print(" Previous data found at address "); | Serial.print(" Previous data found at address "); | ||||
| Serial.println(address); | Serial.println(address); | ||||
| printbuf(buf, 8); | printbuf(buf, 8); | ||||
| Serial.print(" correct: "); | Serial.print(" correct: "); | ||||
| printbuf(sig, 8); | printbuf(sig, 8); | ||||
| Serial.print(" erased: "); | |||||
| printbuf(erased, 8); | |||||
| return false; | return false; | ||||
| } | } | ||||
| } else { | } else { | ||||
| } | } | ||||
| } | } | ||||
| // Write any signatures that were blank on the original check | // Write any signatures that were blank on the original check | ||||
| if (count > 0) { | if (count > 0) { | ||||
| Serial.println(); | Serial.println(); | ||||
| Serial.print("Writing "); | Serial.print("Writing "); | ||||
| Serial.print(count); | Serial.print(count); | ||||
| Serial.println(" signatures"); | Serial.println(" signatures"); | ||||
| memset(buf, 0, sizeof(buf)); | |||||
| memset(sig, 0, sizeof(sig)); | |||||
| memset(buf2, 0, sizeof(buf2)); | |||||
| address = 0; | address = 0; | ||||
| first = true; | first = true; | ||||
| while (address < chipsize) { | while (address < chipsize) { | ||||
| SerialFlash.read(address, buf, 8); | SerialFlash.read(address, buf, 8); | ||||
| if (equal_signatures(buf, erased)) { | |||||
| if (is_erased(buf, 8)) { | |||||
| create_signature(address, sig); | 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); | SerialFlash.write(address, sig, 8); | ||||
| while (!SerialFlash.ready()) ; // wait | while (!SerialFlash.ready()) ; // wait | ||||
| SerialFlash.read(address, buf, 8); | SerialFlash.read(address, buf, 8); | ||||
| Serial.println(" all signatures present from prior tests"); | Serial.println(" all signatures present from prior tests"); | ||||
| } | } | ||||
| // Read all the signatures again, just to be sure | // Read all the signatures again, just to be sure | ||||
| // checks prior writing didn't corrupt any other data | |||||
| Serial.println(); | Serial.println(); | ||||
| Serial.println("Double Checking All Signatures:"); | Serial.println("Double Checking All Signatures:"); | ||||
| memset(buf, 0, sizeof(buf)); | |||||
| memset(sig, 0, sizeof(sig)); | |||||
| memset(buf2, 0, sizeof(buf2)); | |||||
| count = 0; | count = 0; | ||||
| address = 0; | address = 0; | ||||
| first = true; | first = true; | ||||
| Serial.print(count); | Serial.print(count); | ||||
| Serial.println(" signatures read ok"); | Serial.println(" signatures read ok"); | ||||
| // Read pairs of adjacent signatures | // Read pairs of adjacent signatures | ||||
| // check read works across boundaries | |||||
| Serial.println(); | Serial.println(); | ||||
| Serial.println("Checking Signature Pairs"); | Serial.println("Checking Signature Pairs"); | ||||
| memset(buf, 0, sizeof(buf)); | |||||
| memset(sig, 0, sizeof(sig)); | |||||
| memset(buf2, 0, sizeof(buf2)); | |||||
| count = 0; | count = 0; | ||||
| address = testIncrement - 8; | address = testIncrement - 8; | ||||
| first = true; | first = true; | ||||
| Serial.println(" signature pairs read ok"); | 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"); | |||||
| } | |||||
| return "(unknown chip)"; | 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) | void printbuf(const void *buf, uint32_t len) | ||||
| { | { |