diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c index 2fb37cf634..c9a5cc793c 100644 --- a/quantum/dynamic_keymap.c +++ b/quantum/dynamic_keymap.c @@ -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 diff --git a/tmk_core/common/chibios/eeprom_stm32.c b/tmk_core/common/chibios/eeprom_stm32.c index e63a5c6f57..2b0c78f714 100644 --- a/tmk_core/common/chibios/eeprom_stm32.c +++ b/tmk_core/common/chibios/eeprom_stm32.c @@ -21,18 +21,24 @@ #include #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) diff --git a/tmk_core/common/chibios/eeprom_stm32.h b/tmk_core/common/chibios/eeprom_stm32.h index a9b2dc2e50..4fefd29f30 100644 --- a/tmk_core/common/chibios/eeprom_stm32.h +++ b/tmk_core/common/chibios/eeprom_stm32.h @@ -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);