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;
uint32_t sectorBaseAddr;
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
sectorBaseAddr = EXT_FLASH_SECTOR_BASE_ADDR(address);
EXT_FLASH_read(sectorBaseAddr, temp, EXT_FLASH_ERASE_SECTOR_SIZE);
// Erase the sector on the chip
EXT_FLASH_erase(address, EXT_FLASH_ERASE_SECTOR_SIZE);
ilen = EXT_FLASH_PROGRAM_PAGE_SIZE
- (address % EXT_FLASH_PROGRAM_PAGE_SIZE);
if (length < ilen)
ilen = length;
memcpy(temp + (address - sectorBaseAddr), buf + bufIndex, length);
bufIndex += ilen;
address += ilen;
length -= ilen;
tries = 0;
if (EXT_FLASH_writeEnable() != 0) {
if (tries == EXT_FLASH_MAX_TRIES) {
return 1;
}
tries++;
}
tries = 0;
while (EXT_FLASH_waitReady() != 2) {
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;
wbuf[1] = ((sectorBaseAddr
+ (pageIterations * EXT_FLASH_PROGRAM_PAGE_SIZE)) >> 16)
& 0xff;
wbuf[2] = ((sectorBaseAddr
+ (pageIterations * EXT_FLASH_PROGRAM_PAGE_SIZE)) >> 8)
& 0xff;
wbuf[3] = (sectorBaseAddr
+ (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;
}