|
|
@@ -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) |
|
|
|
{ |