flash_internal: add emulated EEPROM functionnality

This commit is contained in:
King Kévin 2020-01-02 18:26:12 +01:00
parent 0a8b23069a
commit 08cba3cd71
2 changed files with 122 additions and 0 deletions

View File

@ -31,6 +31,13 @@
#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;
/** start address of flash memory used for the emulated EEPROM */
static uint32_t flash_internal_eeprom_start = 0;
/** start address of emulated EEPROM */
static uint32_t flash_internal_eeprom_address = 0;
/** verify if the data is in the internal flash area
* @param[in] address start address of the data to read
* @param[in] size how much data to read or write, in bytes
@ -217,3 +224,101 @@ int32_t flash_internal_write(uint32_t address, const uint8_t *buffer, size_t siz
return written;
}
void flash_internal_eeprom_setup(uint16_t pages)
{
flash_internal_eeprom_pages = pages; // just need to remember the number of pages
// get allocated memory address
if ((uint32_t)&__flash_end > (FLASH_BASE + DESIG_FLASH_SIZE * 1024)) { // user specified larger flash than advertised by chip
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 -= flash_internal_eeprom_start % flash_internal_page_size(); // ensure it starts at start of page
// 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
}
}
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) {
return false;
}
if (size + 2U > flash_internal_eeprom_pages * flash_internal_page_size()) { // not enough space
return false;
}
if (size != *(uint16_t*)flash_internal_eeprom_address) { // check if size match
return false;
}
return flash_internal_read(flash_internal_eeprom_address + 2, eeprom, size); // read data
}
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) {
return -1;
}
if (size + 2U > flash_internal_eeprom_pages * flash_internal_page_size()) { // 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 (identical) { // no need to write since it's identical
return size;
}
}
// 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);
if (2 != rc) {
return (-10 + rc);
}
rc = flash_internal_write(flash_internal_eeprom_address + 2, eeprom, size, false);
if (size != rc) {
return (-10 + rc);
}
return rc;
}

View File

@ -40,3 +40,20 @@ int32_t flash_internal_write(uint32_t address, const uint8_t *buffer, size_t siz
* @return flash page size (in bytes)
*/
uint16_t flash_internal_page_size(void);
/** setup the emulated EEPROM area
* @param[in] pages number of flash pages to allocate for the emulated EEPROM
* @warn area must be at least 4 bytes larger than the structure to write
*/
void flash_internal_eeprom_setup(uint16_t pages);
/** read emulated EEPROM area
* @param[out] eeprom where to store the EEPROM data
* @param[in] size size of the EEPROM area (in bytes)
*/
bool flash_internal_eeprom_read(uint8_t *eeprom, uint16_t size);
/** write emulated EEPROM area
* @param[in] eeprom EEPROM data to be stored
* @param[in] size size of the EEPROM area (in bytes)
* @return number of bytes written (including preserved data), or negative in case of error
*/
int32_t flash_internal_eeprom_write(const uint8_t *eeprom, uint16_t size);