flash_internal: add emulated EEPROM functionnality
This commit is contained in:
parent
0a8b23069a
commit
08cba3cd71
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue