Serialflash library usage

I'm hoping someone out there as some experience using this Serialflash library. It is part of the Arduino provided library download content so I suspect many have used it.

I am trying to adapt the RawHardwareTest.ino example to my sketch and to that end I have scavenged the hardware test to establish the serial flash chip is functional and the Read/Write functions to enable me to store and retrieve my data arrays.

Here is my dilemma, I can only seem to write to addresses that are previously erased. IOW unless I run the EraseEverything.ino example to clear the entire chip to all FFs the Write function won't actually change the address contents. I have been running a sequential write of live sensor data to the 1st 4096 addresses and once it finishes those initial writes it fails to overwrite the old data with new on the 2nd and subsequent passes.

I know I'm the newbiest of noobs but I swear it has to be a flag somewhere I am missing. I've examined the CPP file that holds the Read/Write functions and I simply don't see what more is needed than to call the function and provide it with a beginning address, data to write, and a length.

Any insight is greatly appreciated.

lavignema:
I'm hoping someone out there as some experience using this Serialflash library. It is part of the Arduino provided library download content so I suspect many have used it.

Hmm, I searched all relevant Arduino directories on my computer for RawHardwareTest.ino and it can't be found.

If you do a search for "serialflash" in the menu Sketch/Include Library/Manage Libraries of the Arduino IDE ver. 1.8.5 it provides you with SerialFlash by Paul Stoffregen ver. 0.5.0 as a download option.

I have a workaround but it is clunky at best. I can do a block erase of 4096 sequential addresses and then write to that block with my next 4096 collections. Like I said...clunky.

"Normally you should NOT access the flash memory directly,as this test program does."
-few lines above RawHardwareTest.ino

So create a file and try seek() function to move to area where you supposed to overwrite if it helps.
in CopyFromSD.ino it deletes the file if found already on flash by using

SerialFlash.remove(filename);

instead of overwriting.
So may be it doesn't support overwriting at all. Not sure.

there is a More info link in Library Manager for every library

Thanks to all for the input. I have pretty much determined that the minimum (useable) area on this chip is a 4096 byte sector. It also appears that the chip will only allow you to write to an address if it has been erased (FF).

I added a couple of functions to the SerialFlashChip.h/.cpp files to erase the 32K block (52h) and 4K sector (20h). I segmented my data collection to fill an individual sector and once the address gets to 4096 I trigger an erase function for the next sector in line. I read back the data for error checking and it has been running error free for days now. A single 32K block can store 1.99 hours of data.

Next step is connect the GSM phone to create a time stamp for the data.

I'm sure I will have several questions about that one coming soon. :slight_smile:

Mike

lavignema:
Thanks to all for the input. I have pretty much determined that the minimum (useable) area on this chip is a 4096 byte sector. It also appears that the chip will only allow you to write to an address if it has been erased (FF).

I added a couple of functions to the SerialFlashChip.h/.cpp files to erase the 32K block (52h) and 4K sector (20h). I segmented my data collection to fill an individual sector and once the address gets to 4096 I trigger an erase function for the next sector in line. I read back the data for error checking and it has been running error free for days now. A single 32K block can store 1.99 hours of data.

Next step is connect the GSM phone to create a time stamp for the data.

I'm sure I will have several questions about that one coming soon. :slight_smile:

Mike

that is how flash memories work. but you didn't use the SerialFlash library. the library hides flash pages handling

Not sure what you mean by "hides flash pages handling" but I adapted portions of the SerialFlashChip.h and .cpp files to accomplish my end. I use these portions to read/write to individual byte addresses :

void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len)
{
uint8_t *p = (uint8_t *)buf;
uint8_t b, f, status, cmd;
memset(p, 0, len);
f = flags;
SPIPORT.beginTransaction(SPICONFIG);
b = busy;
if (b) {
// read status register ... chip may no longer be busy
CSASSERT();
if (flags & FLAG_STATUS_CMD70) {
SPIPORT.transfer(0x70);
status = SPIPORT.transfer(0);
if ((status & 0x80)) b = 0;
} else {
SPIPORT.transfer(0x05);
status = SPIPORT.transfer(0);
if (!(status & 1)) b = 0;
}
CSRELEASE();
if (b == 0) {
// chip is no longer busy :slight_smile:
busy = 0;
} else if (b < 3) {
// TODO: this may not work on Spansion chips
// which apparently have 2 different suspend
// commands, for program vs erase
CSASSERT();
SPIPORT.transfer(0x06); // write enable (Micron req'd)
CSRELEASE();
delayMicroseconds(1);
cmd = 0x75; //Suspend program/erase for almost all chips
// but Spansion just has to be different for program suspend!
if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85;
CSASSERT();
SPIPORT.transfer(cmd); // Suspend command
CSRELEASE();
if (f & FLAG_STATUS_CMD70) {
// Micron chips don't actually suspend until flags read
CSASSERT();
SPIPORT.transfer(0x70);
do {
status = SPIPORT.transfer(0);
} while (!(status & 0x80));
CSRELEASE();
} else {
CSASSERT();
SPIPORT.transfer(0x05);
do {
status = SPIPORT.transfer(0);
} while ((status & 0x01));
CSRELEASE();
}
} else {
// chip is busy with an operation that can not suspend
SPIPORT.endTransaction(); // is this a good idea?
wait(); // should we wait without ending
b = 0; // the transaction??
SPIPORT.beginTransaction(SPICONFIG);
}
}
do {
uint32_t rdlen = len;
if (f & FLAG_MULTI_DIE) {
if ((addr & 0xFE000000) != ((addr + len - 1) & 0xFE000000)) {
rdlen = 0x2000000 - (addr & 0x1FFFFFF);
}
}
CSASSERT();
// TODO: FIFO optimize....
if (f & FLAG_32BIT_ADDR) {
SPIPORT.transfer(0x03);
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPIPORT.transfer16(0x0300 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
SPIPORT.transfer(p, rdlen);
CSRELEASE();
p += rdlen;
addr += rdlen;
len -= rdlen;
} while (len > 0);
if (b) {
CSASSERT();
SPIPORT.transfer(0x06); // write enable (Micron req'd)
CSRELEASE();
delayMicroseconds(1);
cmd = 0x7A;
if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A;
CSASSERT();
SPIPORT.transfer(cmd); // Resume program/erase
CSRELEASE();
}
SPIPORT.endTransaction();
}

void SerialFlashChip::write(uint32_t addr, const void *buf, uint32_t len)
{
const uint8_t *p = (const uint8_t *)buf;
uint32_t max, pagelen;
//Serial.printf("WR: addr %08X, len %d\n", addr, len);
do {
if (busy) wait();
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
// write enable command
SPIPORT.transfer(0x06);
CSRELEASE();
max = 256 - (addr & 0xFF);
pagelen = (len <= max) ? len : max;
//Serial.printf("WR: addr %08X, pagelen %d\n", addr, pagelen);
delayMicroseconds(1); // TODO: reduce this, but prefer safety first
CSASSERT();
if (flags & FLAG_32BIT_ADDR) {
SPIPORT.transfer(0x02); // program page command
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPIPORT.transfer16(0x0200 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
addr += pagelen;
len -= pagelen;
do {
SPIPORT.transfer(*p++);
} while (--pagelen > 0);
CSRELEASE();
busy = 4;
SPIPORT.endTransaction();
} while (len > 0);
}

I then added these lines to SerialFlachChip.cpp :

void SerialFlashChip::eraseBlock32(uint32_t addr)
{
uint8_t f = flags;
if (busy) wait();
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPIPORT.transfer(0x06); // write enable command
CSRELEASE();
delayMicroseconds(1);
CSASSERT();
if (f & FLAG_32BIT_ADDR) {
SPIPORT.transfer(0x52);
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPIPORT.transfer16(0xD800 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
CSRELEASE();
SPIPORT.endTransaction();
busy = 2;
}

void SerialFlashChip::eraseSector(uint32_t addr)
{
uint8_t f = flags;
if (busy) wait();
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPIPORT.transfer(0x06); // write enable command
CSRELEASE();
delayMicroseconds(1);
CSASSERT();
if (f & FLAG_32BIT_ADDR) {
SPIPORT.transfer(0x20);
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPIPORT.transfer16(0xD800 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
CSRELEASE();
SPIPORT.endTransaction();
busy = 2;
}

...and finally added these lines to SerialFlashChip.h :

static void eraseBlock32(uint32_t addr);
static void eraseSector(uint32_t addr);

Here is the 1st line of my sketch:
#include <SerialFlash.h>