From becf280d9a004493ab24a01e38c03ec220436eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Wed, 19 Feb 2020 20:59:26 +0100 Subject: [PATCH] flash_internal: fix, EEPROM now grows from the end since invalidating does not work --- lib/flash_internal.c | 98 ++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 58 deletions(-) diff --git a/lib/flash_internal.c b/lib/flash_internal.c index 2c8795e..74fd838 100644 --- a/lib/flash_internal.c +++ b/lib/flash_internal.c @@ -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); }