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 "flash_internal.h" // flash storage library API
|
||||||
#include "global.h" // global definitions
|
#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
|
/** verify if the data is in the internal flash area
|
||||||
* @param[in] address start address of the data to read
|
* @param[in] address start address of the data to read
|
||||||
* @param[in] size how much data to read or write, in bytes
|
* @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;
|
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)
|
* @return flash page size (in bytes)
|
||||||
*/
|
*/
|
||||||
uint16_t flash_internal_page_size(void);
|
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