eeprom_stm32: implement denser emulation, default to 4k

This commit is contained in:
Ilya Zhuravlev 2021-07-11 14:44:46 -04:00
parent cdf16e79a3
commit ae1d581ca7
3 changed files with 65 additions and 44 deletions

View File

@ -22,6 +22,10 @@
#include "dynamic_keymap.h"
#include "via.h" // for default VIA_EEPROM_ADDR_END
#ifdef STM32_EEPROM_ENABLE
# include "eeprom_stm32.h"
#endif
#ifdef VIAL_ENABLE
#include "vial.h"
#endif
@ -41,6 +45,8 @@
# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 4095
# elif defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATtiny85__)
# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 511
# elif defined(FEE_DENSITY_BYTES)
# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR FEE_DENSITY_BYTES-1
# else
# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 1023
# endif

View File

@ -21,18 +21,24 @@
#include <string.h>
#include "eeprom_stm32.h"
/* In-memory contents of emulated eeprom for faster access */
#define SNAPSHOT_START (FEE_BASE_ADDRESS)
#define SNAPSHOT_END (FEE_BASE_ADDRESS+FEE_SNAPSHOT_SIZE)
#define WRITELOG_START (SNAPSHOT_END)
#define WRITELOG_END (WRITELOG_START+FEE_WRITELOG_SIZE)
/* In-memory contents of emulated eeprom for direct faster access */
static uint8_t DataBuf[FEE_DENSITY_BYTES];
/* Pointer to the first available slot within flash area */
/* Pointer to the first available slot within the writelog */
static uint8_t *empty_slot;
void EEPROM_Init(void) {
memset(DataBuf, 0, sizeof(DataBuf));
/* First, load the snapshot directly from flash */
memcpy(DataBuf, (void*)FEE_BASE_ADDRESS, FEE_SNAPSHOT_SIZE);
/* Load emulated eeprom contents from flash into memory */
/* Then, process writelog to update DataBuf entries */
uint8_t *addr;
for (addr = (uint8_t*)FEE_PAGE_BASE_ADDRESS; addr < (uint8_t*)FEE_LAST_PAGE_ADDRESS; addr += 4) {
for (addr = (uint8_t*)WRITELOG_START; addr < (uint8_t*)WRITELOG_END; addr += 4) {
uint16_t address;
uint8_t value;
memcpy(&address, addr, sizeof(address));
@ -46,16 +52,16 @@ void EEPROM_Init(void) {
empty_slot = addr;
}
/* Clear flash contents (doesn't touch in-memory DataBuf) */
/* Erase flash contents so we can put updated data in (doesn't touch in-memory DataBuf) */
static void eeprom_clear(void) {
FLASH_Unlock();
for (uint32_t page_num = 0; page_num < FEE_DENSITY_PAGES; ++page_num)
FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE));
for (uint32_t erase_address = SNAPSHOT_START; erase_address < WRITELOG_END; erase_address += FEE_PAGE_SIZE)
FLASH_ErasePage(erase_address);
FLASH_Lock();
empty_slot = (void*)FEE_PAGE_BASE_ADDRESS;
empty_slot = (void*)WRITELOG_START;
}
/* Erase emulated eeprom */
@ -67,29 +73,28 @@ void EEPROM_Erase(void) {
static void eeprom_writedatabyte(uint16_t Address, uint8_t DataByte);
/* Dump in-memory contents into flash */
static void eeprom_restore(void) {
for (uint32_t i = 0; i < FEE_DENSITY_BYTES; ++i) {
/* don't bother writing zeroes */
if (DataBuf[i]) {
eeprom_writedatabyte(i, DataBuf[i]);
}
/* Dump in-memory eeprom contents into the snapshot area */
static void eeprom_write_snapshot(void) {
FLASH_Unlock();
for (uint32_t i = 0; i < FEE_DENSITY_BYTES; i += 2) {
uint16_t halfword;
memcpy(&halfword, &DataBuf[i], sizeof(halfword));
FLASH_ProgramHalfWord(SNAPSHOT_START + i, halfword);
}
FLASH_Lock();
}
static void eeprom_writedatabyte(uint16_t Address, uint8_t DataByte) {
/* if couldn't find an empty spot, we must re-initialize emulated eeprom */
if (empty_slot >= (uint8_t*)FEE_LAST_PAGE_ADDRESS) {
/* ensure that the following call to eeprom_restore will write our desired byte value */
DataBuf[Address] = DataByte;
if (empty_slot >= (uint8_t*)WRITELOG_END) {
/* fully erase emulated eeprom */
eeprom_clear();
/* and then write DataBuf contents back into flash */
eeprom_restore();
/* don't need to do anything else as eeprom_restore already wrote our value */
eeprom_write_snapshot();
return;
}
@ -106,7 +111,7 @@ static void eeprom_writedatabyte(uint16_t Address, uint8_t DataByte) {
empty_slot += 4;
}
void EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) {
static void EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) {
/* if the address is out-of-bounds, do nothing */
if (Address >= FEE_DENSITY_BYTES)
return;
@ -115,14 +120,14 @@ void EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) {
if (DataBuf[Address] == DataByte)
return;
/* perform the write into flash memory */
eeprom_writedatabyte(Address, DataByte);
/* keep DataBuf cache in sync */
DataBuf[Address] = DataByte;
/* perform the write into flash memory */
eeprom_writedatabyte(Address, DataByte);
}
uint8_t EEPROM_ReadDataByte(uint16_t Address) {
static uint8_t EEPROM_ReadDataByte(uint16_t Address) {
uint8_t DataByte = 0x00;
if (Address < FEE_DENSITY_BYTES)

View File

@ -37,11 +37,10 @@
# define MCU_STM32F072CB
#elif defined(EEPROM_EMU_STM32F042x6)
# define MCU_STM32F042K6
#else
# error "not implemented."
#endif
#ifndef EEPROM_PAGE_SIZE
/* The page_size * density_pages should provide 8k of space, split 4k/4k between snapshot and writelog in the default config */
#ifndef FEE_DENSITY_PAGES
# if defined(MCU_STM32F103RB) || defined(MCU_STM32F042K6)
# define FEE_PAGE_SIZE (uint16_t)0x400 // Page size = 1KByte
# define FEE_DENSITY_PAGES 8 // How many pages are used
@ -49,11 +48,13 @@
# define FEE_PAGE_SIZE (uint16_t)0x800 // Page size = 2KByte
# define FEE_DENSITY_PAGES 4 // How many pages are used
# else
# error "No MCU type specified. Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)."
# error "No MCU type specified and FEE_DENSITY_PAGES not defined.\
Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)\
or define FEE_DENSITY_PAGES yourself."
# endif
#endif
#ifndef EEPROM_START_ADDRESS
#ifndef FEE_MCU_FLASH_SIZE
# if defined(MCU_STM32F103RB) || defined(MCU_STM32F072CB)
# define FEE_MCU_FLASH_SIZE 128 // Size in Kb
# elif defined(MCU_STM32F042K6)
@ -65,23 +66,32 @@
# elif defined(MCU_STM32F303CC)
# define FEE_MCU_FLASH_SIZE 256 // Size in Kb
# else
# error "No MCU type specified. Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)."
# error "No MCU type specified and FEE_MCU_FLASH_SIZE not defined.\
Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)\
or define FEE_MCU_FLASH_SIZE yourself."
# endif
#endif
/* Start of the emulated eeprom flash area */
#define FEE_PAGE_BASE_ADDRESS ((uint32_t)(0x8000000 + FEE_MCU_FLASH_SIZE * 1024 - FEE_DENSITY_PAGES * FEE_PAGE_SIZE))
/* End of the emulated eeprom flash area */
#define FEE_LAST_PAGE_ADDRESS (FEE_PAGE_BASE_ADDRESS + (FEE_PAGE_SIZE * FEE_DENSITY_PAGES))
/* Size of emulated eeprom */
#define FEE_DENSITY_BYTES 1024
#ifndef FEE_BASE_ADDRESS
/* Start of the emulated eeprom flash area, place it at the end of the flash memory */
#define FEE_BASE_ADDRESS ((uint32_t)(0x8000000 + FEE_MCU_FLASH_SIZE * 1024 - FEE_DENSITY_PAGES * FEE_PAGE_SIZE))
#endif
#ifndef FEE_SNAPSHOT_SIZE
/* Size of eeprom snapshot, in bytes. This is equal to emulated eeprom size. */
#define FEE_SNAPSHOT_SIZE 4096
#endif
#ifndef FEE_WRITELOG_SIZE
/* Size of eeprom writelog, in bytes */
#define FEE_WRITELOG_SIZE 4096
#endif
/* Flash word value after erase */
#define FEE_EMPTY_WORD ((uint16_t)0xFFFF)
_Static_assert(FEE_DENSITY_PAGES * FEE_PAGE_SIZE >= FEE_DENSITY_BYTES * 8,
"flash memory for emulated eeprom is too small; for correct functionality ensure it is at least 8x FEE_DENSITY_BYTES");
/* Size of emulated eeprom */
#define FEE_DENSITY_BYTES FEE_SNAPSHOT_SIZE
void EEPROM_Init(void);
void EEPROM_Erase(void);
void EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte);
uint8_t EEPROM_ReadDataByte(uint16_t Address);