flash_internal: fix, EEPROM now grows from the end since invalidating does not work

This commit is contained in:
King Kévin 2020-02-19 20:59:26 +01:00
parent b7e72bba67
commit becf280d9a
1 changed files with 40 additions and 58 deletions

View File

@ -31,8 +31,6 @@
#include "flash_internal.h" // flash storage library API
#include "global.h" // global definitions
/** number of flash pages, located at the end of flash memory, to use for EEPROM functionality */
static uint16_t flash_internal_eeprom_pages = 0;
/** flash page size */
static uint16_t flash_internal_page = 0;
/** end address of flash */
@ -228,45 +226,40 @@ int32_t flash_internal_write(uint32_t address, const uint8_t *buffer, size_t siz
return written;
}
/* the EEPROM allocated area is erased at first
* the EEPROM data starts at the end of the allocated memory
* each time it is written, the next data segment is placed before the existing one
* a data segment start with the size, which help detecting the segment since the data can be the same as erased data (0xffff)
*/
void flash_internal_eeprom_setup(uint16_t pages)
{
flash_internal_eeprom_pages = pages; // just need to remember the number of pages
if (0 == flash_internal_page || 0 == flash_internal_end) {
flash_internal_init(); // get page size and flash end
}
// get allocated memory address
if ((uint32_t)&__flash_end >= FLASH_BASE) { // check if the end for the internal flash is enforced by the linker script
flash_internal_eeprom_start = (uint32_t)&__flash_end - flash_internal_eeprom_pages * flash_internal_page_size();
} else {
flash_internal_eeprom_start = (FLASH_BASE + DESIG_FLASH_SIZE * 1024) - flash_internal_eeprom_pages * flash_internal_page_size();
flash_internal_eeprom_start = 0; // reset start address
flash_internal_eeprom_address = 0; // reset EEPROM address
if (pages > DESIG_FLASH_SIZE * 1024 / flash_internal_page) { // not enough pages are available
return;
}
flash_internal_eeprom_start -= flash_internal_eeprom_start % flash_internal_page_size(); // ensure it starts at start of page
flash_internal_eeprom_start = flash_internal_end - flash_internal_page * pages; // set EEPROM start (page aligned)
// find EEPROM in flash
flash_internal_eeprom_address = flash_internal_eeprom_start; // by default start with start of allocated flash memory
for (uint32_t addr = flash_internal_eeprom_start; addr < flash_internal_eeprom_start + flash_internal_eeprom_pages * flash_internal_page_size() - 2; addr += 2) {
if (0 != *(uint16_t*)addr) { // 0 is invalidated flash
flash_internal_eeprom_address = addr; // we found a valid address, which should be the size of the EEPROM
break;
}
}
uint16_t size = *(uint16_t*)flash_internal_eeprom_address;
if (size + 2U > flash_internal_eeprom_pages * flash_internal_page_size()) { // there is not enough space
flash_internal_eeprom_address = flash_internal_eeprom_start; // set back to start
}
if (0 != size && flash_internal_eeprom_address + 2U + size > flash_internal_eeprom_start + flash_internal_eeprom_pages * flash_internal_page_size()) { // the size seems to be valid to there is not enough remaining space
flash_internal_eeprom_address = flash_internal_eeprom_start; // set back to start
}
// find EEPROM in flash (first non-erased word)
for (flash_internal_eeprom_address = flash_internal_eeprom_start; flash_internal_eeprom_address < flash_internal_end && 0xffff == *(uint16_t*)flash_internal_eeprom_address; flash_internal_eeprom_address += 2);
}
bool flash_internal_eeprom_read(uint8_t *eeprom, uint16_t size)
{
// sanity checks
if (NULL == eeprom || 0 == size || 0 == flash_internal_eeprom_pages || 0 == flash_internal_eeprom_start || 0 == flash_internal_eeprom_address) {
if (NULL == eeprom || 0 == size || 0xffff == size || 0 == flash_internal_eeprom_start || 0 == flash_internal_eeprom_address) {
return false;
}
if (size + 2U > flash_internal_eeprom_pages * flash_internal_page_size()) { // not enough space
if (size + 2U > flash_internal_end - flash_internal_eeprom_start) { // not enough space
return false;
}
if (size + 2U > flash_internal_end - flash_internal_eeprom_address) { // EEPROM size is too large
return false;
}
if (size != *(uint16_t*)flash_internal_eeprom_address) { // check if size match
return false;
}
@ -277,49 +270,38 @@ bool flash_internal_eeprom_read(uint8_t *eeprom, uint16_t size)
int32_t flash_internal_eeprom_write(const uint8_t *eeprom, uint16_t size)
{
// sanity checks
if (NULL == eeprom || 0 == size || 0 == flash_internal_eeprom_pages || 0 == flash_internal_eeprom_start || 0 == flash_internal_eeprom_address) {
if (NULL == eeprom || 0 == size || 0xffff == size || 0 == flash_internal_eeprom_start || 0 == flash_internal_eeprom_address) {
return -1;
}
if (size + 2U > flash_internal_eeprom_pages * flash_internal_page_size()) { // not enough space
if (size + 2U > flash_internal_end - flash_internal_eeprom_start) { // not enough space
return -2;
}
uint16_t current_size = *(uint16_t*)flash_internal_eeprom_address;
if (size == current_size) { // check if it already the same
bool identical = true;
for (uint16_t i = 0; i < size; i++) {
if (eeprom[i] != *((uint8_t*)flash_internal_eeprom_address + 2 + i)) {
identical = false;
break;
if (flash_internal_eeprom_start + size + 2U > flash_internal_eeprom_address) { // there is not enough free space
// erase all EEPROM allocated pages
flash_unlock(); // unlock flash to be able to erase it
for (uint32_t page_start = flash_internal_eeprom_start; page_start < flash_internal_end; page_start += flash_internal_page) {
flash_erase_page(page_start); // erase current page
if (flash_get_status_flags() != FLASH_SR_EOP) { // operation went wrong
flash_lock(); // lock back flash to protect it
return -3;
}
}
if (identical) { // no need to write since it's identical
return size;
}
flash_internal_eeprom_address = flash_internal_end; // put address back as the end
}
flash_internal_eeprom_address -= (size + 2U); // get new start of data segment
if (flash_internal_eeprom_address % 2) { // have segment word aligned
flash_internal_eeprom_address--;
}
if (flash_internal_eeprom_address < flash_internal_eeprom_start) { // just to be sure
return -4;
}
// one optimisation would be to check if we just need to flip bits to 0, than we could reuse the same location
// invalidate current EEPROM
const uint8_t zero[2] = {0, 0};
flash_internal_write(flash_internal_eeprom_address, zero, 2, false);
flash_internal_eeprom_address += 2;
while (current_size && flash_internal_eeprom_address < flash_internal_eeprom_start + flash_internal_eeprom_pages * flash_internal_page_size()) {
flash_internal_write(flash_internal_eeprom_address, zero, 2, false);
current_size -= 2;
flash_internal_eeprom_address += 2;
}
// go to start if there is not enough remaining space
if (flash_internal_eeprom_address + size + 2U > flash_internal_eeprom_start + flash_internal_eeprom_pages * flash_internal_page_size()) {
flash_internal_eeprom_address = flash_internal_eeprom_start;
}
int32_t rc = flash_internal_write(flash_internal_eeprom_address, (uint8_t*)&size, 2, false);
int32_t rc = flash_internal_write(flash_internal_eeprom_address, (uint8_t*)&size, 2, false); // write size
if (2 != rc) {
return (-10 + rc);
}
rc = flash_internal_write(flash_internal_eeprom_address + 2, eeprom, size, false);
rc = flash_internal_write(flash_internal_eeprom_address + 2, eeprom, size, false); // write data
if (size != rc) {
return (-10 + rc);
}