Efficient way of writing to flash memory without losing data

For my project, I am writing some code that gets some results and I want to store these results on external flash memory. The external flash memory in question is a MX25R8035F. I found that writing without erasing only works the first time I wrote something to an address.

But because of this I'm running into some memory issues. The smallest erase is a sector erase (4096 bytes.) If I want to write to a specific address I would first need to read the sector that contains that address, change the bytes that I want to be changed and then write the whole sector (writing is only per page.)

Is there a more efficient way of using this external flash memory? Specifically using less memory to change one or two bytes.

The function I use now this can be found below:

uint8_t EXT_FLASH_write(size_t address, uint8_t *buf, size_t length) {

/*
* The entire sector will be erased when writing to an offset inside that sector
* Therefore this function will first retrieve all data inside the sector and update the retrieved
* data with the values inside buff which and will then write the entire content back to the sector
*/

uint8_t wbuf[4];
SPI_Transaction transaction;
uint8_t temp[EXT_FLASH_ERASE_SECTOR_SIZE];
uint8_t tries;
size_t ilen; /* interim length per instruction */
uint32_t bufIndex = 0;
uint8_t pageIterations;

while (length > 0) {
// first retrieve entire sector so it can be erased on the chip

// Erase the sector on the chip

ilen = EXT_FLASH_PROGRAM_PAGE_SIZE
if (length < ilen)
ilen = length;

bufIndex += ilen;
length -= ilen;

tries = 0;
if (EXT_FLASH_writeEnable() != 0) {
if (tries == EXT_FLASH_MAX_TRIES) {
return 1;
}
tries++;
}
tries = 0;
if (tries == EXT_FLASH_MAX_TRIES) {
return 1;
}
EXT_FLASH_writeEnable();
tries++;
}

// programming the external flash can only be done in pages
// so divide current sector into pages and write each page separately
for (pageIterations = 0;
pageIterations * EXT_FLASH_PROGRAM_PAGE_SIZE
< EXT_FLASH_ERASE_SECTOR_SIZE; pageIterations++) {
EXT_FLASH_select();

wbuf[0] = EXT_FLASH_CODE_PROGRAM;
+ (pageIterations * EXT_FLASH_PROGRAM_PAGE_SIZE)) >> 16)
& 0xff;
+ (pageIterations * EXT_FLASH_PROGRAM_PAGE_SIZE)) >> 8)
& 0xff;
+ (pageIterations * EXT_FLASH_PROGRAM_PAGE_SIZE)) & 0xff;

// Configure the transaction
transaction.count = sizeof(wbuf);
transaction.txBuf = wbuf;
transaction.rxBuf = NULL;

if (!SPI_transfer(masterSpi, &transaction)) {
/* failure */
EXT_FLASH_deselect();
return 1;
}
// Configure the transaction
transaction.count = EXT_FLASH_PROGRAM_PAGE_SIZE;
transaction.txBuf = temp
+ (pageIterations * EXT_FLASH_PROGRAM_PAGE_SIZE);
transaction.rxBuf = NULL;

if (!SPI_transfer(masterSpi, &transaction)) {
/* failure */
EXT_FLASH_deselect();
return 1;
}

EXT_FLASH_deselect();
}
}
return 0;
}

• You have mis-characterized the part and mis-titled your question, this is not an EEPROM, but rather a flash device. With such a memory you don't "change a few bytes" as that is indeed very wasteful. Re-think how you are doing things and find a method that doesn't require that, perhaps something of a journal. – Chris Stratton Apr 30 '20 at 8:54
• Um, Flash is a type of EEPROM – Marcus Müller Apr 30 '20 at 10:11
• The big erase size is a well-known problem with flash memories, often making them unsuitable to store changing data. Memory manufacturers typically have special kinds of memory marketed as "data flash" with smaller erase sizes, similar to what was previously called EEPROM back in the days. For the purpose of logging etc with a lot of writes, you might wanna consider alternative memory types though, such as "FRAM" or "MRAM" that various companies have developed in later years. They don't have the write cycle limitation and data retention problem of flash memories. – Lundin Apr 30 '20 at 13:30