From b3d02592c016b33432ff06db4992584b56fe4630 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sun, 12 Sep 2021 12:58:42 -0400 Subject: [PATCH] Revert "eeprom_stm32: implement high density wear leveling (#12567)" This reverts commit e756a21636149ad47c19c659d04be93cf3071dab. --- build_test.mk | 1 - keyboards/nk65/config.h | 3 - quantum/eeconfig.h | 2 +- testlist.mk | 1 - tmk_core/common/chibios/eeprom_stm32.c | 806 +++----------------- tmk_core/common/chibios/eeprom_stm32.h | 61 +- tmk_core/common/chibios/flash_stm32.h | 7 +- tmk_core/common/test/eeprom_stm32_tests.cpp | 438 ----------- tmk_core/common/test/flash_stm32_mock.c | 50 -- tmk_core/common/test/rules.mk | 23 - tmk_core/common/test/testlist.mk | 1 - util/stm32eeprom_parser.py | 317 -------- 12 files changed, 179 insertions(+), 1531 deletions(-) delete mode 100644 tmk_core/common/test/eeprom_stm32_tests.cpp delete mode 100644 tmk_core/common/test/flash_stm32_mock.c delete mode 100644 tmk_core/common/test/rules.mk delete mode 100644 tmk_core/common/test/testlist.mk delete mode 100755 util/stm32eeprom_parser.py diff --git a/build_test.mk b/build_test.mk index 037577bf90..b6b8782174 100644 --- a/build_test.mk +++ b/build_test.mk @@ -56,7 +56,6 @@ include $(TMK_PATH)/common.mk include $(QUANTUM_PATH)/debounce/tests/rules.mk include $(QUANTUM_PATH)/sequencer/tests/rules.mk include $(QUANTUM_PATH)/serial_link/tests/rules.mk -include $(TMK_PATH)/common/test/rules.mk ifneq ($(filter $(FULL_TESTS),$(TEST)),) include build_full_test.mk endif diff --git a/keyboards/nk65/config.h b/keyboards/nk65/config.h index a178307cc0..fa14e9ffbf 100755 --- a/keyboards/nk65/config.h +++ b/keyboards/nk65/config.h @@ -148,9 +148,6 @@ along with this program. If not, see . * both 128kb and 256kb versions of F303. * Register 0x1FFFF7CC holds the size of the flash memory. */ -#ifndef FLASHSIZE_BASE -# define FLASHSIZE_BASE ((uint32_t)0x1FFFF7CCU) /*!< FLASH Size register base address */ -#endif #define EEPROM_START_ADDRESS #define FEE_MCU_FLASH_SIZE \ ({ \ diff --git a/quantum/eeconfig.h b/quantum/eeconfig.h index bd39971b2c..a88071729d 100644 --- a/quantum/eeconfig.h +++ b/quantum/eeconfig.h @@ -21,7 +21,7 @@ along with this program. If not, see . #include #ifndef EECONFIG_MAGIC_NUMBER -# define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEE9 // When changing, decrement this value to avoid future re-init issues +# define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEEA // When changing, decrement this value to avoid future re-init issues #endif #define EECONFIG_MAGIC_NUMBER_OFF (uint16_t)0xFFFF diff --git a/testlist.mk b/testlist.mk index b66b93d295..d256f4c815 100644 --- a/testlist.mk +++ b/testlist.mk @@ -4,7 +4,6 @@ FULL_TESTS := $(TEST_LIST) include $(ROOT_DIR)/quantum/debounce/tests/testlist.mk include $(ROOT_DIR)/quantum/sequencer/tests/testlist.mk include $(ROOT_DIR)/quantum/serial_link/tests/testlist.mk -include $(ROOT_DIR)/tmk_core/common/test/testlist.mk define VALIDATE_TEST_LIST ifneq ($1,) diff --git a/tmk_core/common/chibios/eeprom_stm32.c b/tmk_core/common/chibios/eeprom_stm32.c index 5bf852fde1..ea51989728 100644 --- a/tmk_core/common/chibios/eeprom_stm32.c +++ b/tmk_core/common/chibios/eeprom_stm32.c @@ -14,751 +14,185 @@ * Artur F. * * Modifications for QMK and STM32F303 by Yiancar - * Modifications to add flash wear leveling by Ilya Zhuravlev - * Modifications to increase flash density by Don Kjer */ #include -#include -#include "debug.h" +#include #include "eeprom_stm32.h" -#include "flash_stm32.h" +/***************************************************************************** + * Allows to use the internal flash to store non volatile data. To initialize + * the functionality use the EEPROM_Init() function. Be sure that by reprogramming + * of the controller just affected pages will be deleted. In other case the non + * volatile data will be lost. + ******************************************************************************/ -/* - * We emulate eeprom by writing a snapshot compacted view of eeprom contents, - * followed by a write log of any change since that snapshot: - * - * === SIMULATED EEPROM CONTENTS === - * - * ┌─ Compacted ┬ Write Log ─┐ - * │............│[BYTE][BYTE]│ - * │FFFF....FFFF│[WRD0][WRD1]│ - * │FFFFFFFFFFFF│[WORD][NEXT]│ - * │....FFFFFFFF│[BYTE][WRD0]│ - * ├────────────┼────────────┤ - * └──PAGE_BASE │ │ - * PAGE_LAST─┴─WRITE_BASE │ - * WRITE_LAST ┘ - * - * Compacted contents are the 1's complement of the actual EEPROM contents. - * e.g. An 'FFFF' represents a '0000' value. - * - * The size of the 'compacted' area is equal to the size of the 'emulated' eeprom. - * The size of the compacted-area and write log are configurable, and the combined - * size of Compacted + WriteLog is a multiple FEE_PAGE_SIZE, which is MCU dependent. - * Simulated Eeprom contents are located at the end of available flash space. - * - * The following configuration defines can be set: - * - * FEE_DENSITY_PAGES # Total number of pages to use for eeprom simulation (Compact + Write log) - * FEE_DENSITY_BYTES # Size of simulated eeprom. (Defaults to half the space allocated by FEE_DENSITY_PAGES) - * NOTE: The current implementation does not include page swapping, - * and FEE_DENSITY_BYTES will consume that amount of RAM as a cached view of actual EEPROM contents. - * - * The maximum size of FEE_DENSITY_BYTES is currently 16384. The write log size equals - * FEE_DENSITY_PAGES * FEE_PAGE_SIZE - FEE_DENSITY_BYTES. - * The larger the write log, the less frequently the compacted area needs to be rewritten. - * - * - * *** General Algorithm *** - * - * During initialization: - * The contents of the Compacted-flash area are loaded and the 1's complement value - * is cached into memory (e.g. 0xFFFF in Flash represents 0x0000 in cache). - * Write log entries are processed until a 0xFFFF is reached. - * Each log entry updates a byte or word in the cache. - * - * During reads: - * EEPROM contents are given back directly from the cache in memory. - * - * During writes: - * The contents of the cache is updated first. - * If the Compacted-flash area corresponding to the write address is unprogrammed, the 1's complement of the value is written directly into Compacted-flash - * Otherwise: - * If the write log is full, erase both the Compacted-flash area and the Write log, then write cached contents to the Compacted-flash area. - * Otherwise a Write log entry is constructed and appended to the next free position in the Write log. - * - * - * *** Write Log Structure *** - * - * Write log entries allow for optimized byte writes to addresses below 128. Writing 0 or 1 words are also optimized when word-aligned. - * - * === WRITE LOG ENTRY FORMATS === - * - * ╔═══ Byte-Entry ══╗ - * ║0XXXXXXX║YYYYYYYY║ - * ║ └──┬──┘║└──┬───┘║ - * ║ Address║ Value ║ - * ╚════════╩════════╝ - * 0 <= Address < 0x80 (128) - * - * ╔ Word-Encoded 0 ╗ - * ║100XXXXXXXXXXXXX║ - * ║ │└─────┬─────┘║ - * ║ │Address >> 1 ║ - * ║ └── Value: 0 ║ - * ╚════════════════╝ - * 0 <= Address <= 0x3FFE (16382) - * - * ╔ Word-Encoded 1 ╗ - * ║101XXXXXXXXXXXXX║ - * ║ │└─────┬─────┘║ - * ║ │Address >> 1 ║ - * ║ └── Value: 1 ║ - * ╚════════════════╝ - * 0 <= Address <= 0x3FFE (16382) - * - * ╔═══ Reserved ═══╗ - * ║110XXXXXXXXXXXXX║ - * ╚════════════════╝ - * - * ╔═══════════ Word-Next ═══════════╗ - * ║111XXXXXXXXXXXXX║YYYYYYYYYYYYYYYY║ - * ║ └─────┬─────┘║└───────┬──────┘║ - * ║(Address-128)>>1║ ~Value ║ - * ╚════════════════╩════════════════╝ - * ( 0 <= Address < 0x0080 (128): Reserved) - * 0x80 <= Address <= 0x3FFE (16382) - * - * Write Log entry ranges: - * 0x0000 ... 0x7FFF - Byte-Entry; address is (Entry & 0x7F00) >> 4; value is (Entry & 0xFF) - * 0x8000 ... 0x9FFF - Word-Encoded 0; address is (Entry & 0x1FFF) << 1; value is 0 - * 0xA000 ... 0xBFFF - Word-Encoded 1; address is (Entry & 0x1FFF) << 1; value is 1 - * 0xC000 ... 0xDFFF - Reserved - * 0xE000 ... 0xFFBF - Word-Next; address is (Entry & 0x1FFF) << 1 + 0x80; value is ~(Next_Entry) - * 0xFFC0 ... 0xFFFE - Reserved - * 0xFFFF - Unprogrammed - * - */ - -/* These bits are used for optimizing encoding of bytes, 0 and 1 */ -#define FEE_WORD_ENCODING 0x8000 -#define FEE_VALUE_NEXT 0x6000 -#define FEE_VALUE_RESERVED 0x4000 -#define FEE_VALUE_ENCODED 0x2000 -#define FEE_BYTE_RANGE 0x80 - -// HACK ALERT. This definition may not match your processor -// To Do. Work out correct value for EEPROM_PAGE_SIZE on the STM32F103CT6 etc -#if defined(EEPROM_EMU_STM32F303xC) -# define MCU_STM32F303CC -#elif defined(EEPROM_EMU_STM32F103xB) -# define MCU_STM32F103RB -#elif defined(EEPROM_EMU_STM32F072xB) -# define MCU_STM32F072CB -#elif defined(EEPROM_EMU_STM32F042x6) -# define MCU_STM32F042K6 -#elif !defined(FEE_PAGE_SIZE) || !defined(FEE_DENSITY_PAGES) || !defined(FEE_MCU_FLASH_SIZE) -# error "not implemented." -#endif - -#if !defined(FEE_PAGE_SIZE) || !defined(FEE_DENSITY_PAGES) -# if defined(MCU_STM32F103RB) || defined(MCU_STM32F042K6) -# ifndef FEE_PAGE_SIZE -# define FEE_PAGE_SIZE 0x400 // Page size = 1KByte -# endif -# ifndef FEE_DENSITY_PAGES -# define FEE_DENSITY_PAGES 2 // How many pages are used -# endif -# elif defined(MCU_STM32F103ZE) || defined(MCU_STM32F103RE) || defined(MCU_STM32F103RD) || defined(MCU_STM32F303CC) || defined(MCU_STM32F072CB) -# ifndef FEE_PAGE_SIZE -# define FEE_PAGE_SIZE 0x800 // Page size = 2KByte -# endif -# ifndef FEE_DENSITY_PAGES -# define FEE_DENSITY_PAGES 4 // How many pages are used -# endif -# else -# error "No MCU type specified. Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)." -# endif -#endif - -#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) -# define FEE_MCU_FLASH_SIZE 32 // Size in Kb -# elif defined(MCU_STM32F103ZE) || defined(MCU_STM32F103RE) -# define FEE_MCU_FLASH_SIZE 512 // Size in Kb -# elif defined(MCU_STM32F103RD) -# define FEE_MCU_FLASH_SIZE 384 // Size in Kb -# 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)." -# endif -#endif - -#define FEE_XSTR(x) FEE_STR(x) -#define FEE_STR(x) #x - -/* Size of combined compacted eeprom and write log pages */ -#define FEE_DENSITY_MAX_SIZE (FEE_DENSITY_PAGES * FEE_PAGE_SIZE) -/* Addressable range 16KByte: 0 <-> (0x1FFF << 1) */ -#define FEE_ADDRESS_MAX_SIZE 0x4000 - -#ifndef EEPROM_START_ADDRESS /* *TODO: Get rid of this check */ -# if FEE_DENSITY_MAX_SIZE > (FEE_MCU_FLASH_SIZE * 1024) -# pragma message FEE_XSTR(FEE_DENSITY_MAX_SIZE) " > " FEE_XSTR(FEE_MCU_FLASH_SIZE * 1024) -# error emulated eeprom: FEE_DENSITY_PAGES is greater than available flash size -# endif -#endif - -/* Size of emulated eeprom */ -#ifdef FEE_DENSITY_BYTES -# if (FEE_DENSITY_BYTES > FEE_DENSITY_MAX_SIZE) -# pragma message FEE_XSTR(FEE_DENSITY_BYTES) " > " FEE_XSTR(FEE_DENSITY_MAX_SIZE) -# error emulated eeprom: FEE_DENSITY_BYTES exceeds FEE_DENSITY_MAX_SIZE -# endif -# if (FEE_DENSITY_BYTES == FEE_DENSITY_MAX_SIZE) -# pragma message FEE_XSTR(FEE_DENSITY_BYTES) " == " FEE_XSTR(FEE_DENSITY_MAX_SIZE) -# warning emulated eeprom: FEE_DENSITY_BYTES leaves no room for a write log. This will greatly increase the flash wear rate! -# endif -# if FEE_DENSITY_BYTES > FEE_ADDRESS_MAX_SIZE -# pragma message FEE_XSTR(FEE_DENSITY_BYTES) " > " FEE_XSTR(FEE_ADDRESS_MAX_SIZE) -# error emulated eeprom: FEE_DENSITY_BYTES is greater than FEE_ADDRESS_MAX_SIZE allows -# endif -# if ((FEE_DENSITY_BYTES) % 2) == 1 -# error emulated eeprom: FEE_DENSITY_BYTES must be even -# endif -#else -/* Default to half of allocated space used for emulated eeprom, half for write log */ -# define FEE_DENSITY_BYTES (FEE_DENSITY_PAGES * FEE_PAGE_SIZE / 2) -#endif - -/* Size of write log */ -#define FEE_WRITE_LOG_BYTES (FEE_DENSITY_PAGES * FEE_PAGE_SIZE - FEE_DENSITY_BYTES) - -/* Start of the emulated eeprom compacted flash area */ -#ifndef FEE_FLASH_BASE -# define FEE_FLASH_BASE 0x8000000 -#endif -#define FEE_PAGE_BASE_ADDRESS ((uintptr_t)(FEE_FLASH_BASE) + FEE_MCU_FLASH_SIZE * 1024 - FEE_WRITE_LOG_BYTES - FEE_DENSITY_BYTES) -/* End of the emulated eeprom compacted flash area */ -#define FEE_PAGE_LAST_ADDRESS (FEE_PAGE_BASE_ADDRESS + FEE_DENSITY_BYTES) -/* Start of the emulated eeprom write log */ -#define FEE_WRITE_LOG_BASE_ADDRESS FEE_PAGE_LAST_ADDRESS -/* End of the emulated eeprom write log */ -#define FEE_WRITE_LOG_LAST_ADDRESS (FEE_WRITE_LOG_BASE_ADDRESS + FEE_WRITE_LOG_BYTES) - -/* Flash word value after erase */ -#define FEE_EMPTY_WORD ((uint16_t)0xFFFF) - -#if defined(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) && (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR >= FEE_DENSITY_BYTES) -# error emulated eeprom: DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is greater than the FEE_DENSITY_BYTES available -#endif - -/* In-memory contents of emulated eeprom for faster access */ -/* *TODO: Implement page swapping */ -static uint16_t WordBuf[FEE_DENSITY_BYTES / 2]; -static uint8_t *DataBuf = (uint8_t *)WordBuf; - -/* Pointer to the first available slot within the write log */ -static uint16_t *empty_slot; - -// #define DEBUG_EEPROM_OUTPUT - -/* - * Debug print utils - */ - -#if defined(DEBUG_EEPROM_OUTPUT) - -# define debug_eeprom debug_enable -# define eeprom_println(s) println(s) -# define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__); - -#else /* NO_DEBUG */ - -# define debug_eeprom false -# define eeprom_println(s) -# define eeprom_printf(fmt, ...) - -#endif /* NO_DEBUG */ - -void print_eeprom(void) { -#ifndef NO_DEBUG - int empty_rows = 0; - for (uint16_t i = 0; i < FEE_DENSITY_BYTES; i++) { - if (i % 16 == 0) { - if (i >= FEE_DENSITY_BYTES - 16) { - /* Make sure we display the last row */ - empty_rows = 0; - } - /* Check if this row is uninitialized */ - ++empty_rows; - for (uint16_t j = 0; j < 16; j++) { - if (DataBuf[i + j]) { - empty_rows = 0; - break; - } - } - if (empty_rows > 1) { - /* Repeat empty row */ - if (empty_rows == 2) { - /* Only display the first repeat empty row */ - println("*"); - } - i += 15; - continue; - } - xprintf("%04x", i); - } - if (i % 8 == 0) print(" "); - - xprintf(" %02x", DataBuf[i]); - if ((i + 1) % 16 == 0) { - println(""); - } - } -#endif -} +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Functions -----------------------------------------------------------------*/ +uint8_t DataBuf[FEE_PAGE_SIZE]; +/***************************************************************************** + * Delete Flash Space used for user Data, deletes the whole space between + * RW_PAGE_BASE_ADDRESS and the last uC Flash Page + ******************************************************************************/ uint16_t EEPROM_Init(void) { - /* Load emulated eeprom contents from compacted flash into memory */ - uint16_t *src = (uint16_t *)FEE_PAGE_BASE_ADDRESS; - uint16_t *dest = (uint16_t *)DataBuf; - for (; src < (uint16_t *)FEE_PAGE_LAST_ADDRESS; ++src, ++dest) { - *dest = ~*src; - } + // unlock flash + FLASH_Unlock(); - if (debug_eeprom) { - println("EEPROM_Init Compacted Pages:"); - print_eeprom(); - println("EEPROM_Init Write Log:"); - } - - /* Replay write log */ - uint16_t *log_addr; - for (log_addr = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; log_addr < (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS; ++log_addr) { - uint16_t address = *log_addr; - if (address == FEE_EMPTY_WORD) { - break; - } - /* Check for lowest 128-bytes optimization */ - if (!(address & FEE_WORD_ENCODING)) { - uint8_t bvalue = (uint8_t)address; - address >>= 8; - DataBuf[address] = bvalue; - eeprom_printf("DataBuf[0x%02x] = 0x%02x;\n", address, bvalue); - } else { - uint16_t wvalue; - /* Check if value is in next word */ - if ((address & FEE_VALUE_NEXT) == FEE_VALUE_NEXT) { - /* Read value from next word */ - if (++log_addr >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) { - break; - } - wvalue = ~*log_addr; - if (!wvalue) { - eeprom_printf("Incomplete write at log_addr: 0x%04x;\n", (uint32_t)log_addr); - /* Possibly incomplete write. Ignore and continue */ - continue; - } - address &= 0x1FFF; - address <<= 1; - /* Writes to addresses less than 128 are byte log entries */ - address += FEE_BYTE_RANGE; - } else { - /* Reserved for future use */ - if (address & FEE_VALUE_RESERVED) { - eeprom_printf("Reserved encoded value at log_addr: 0x%04x;\n", (uint32_t)log_addr); - continue; - } - /* Optimization for 0 or 1 values. */ - wvalue = (address & FEE_VALUE_ENCODED) >> 13; - address &= 0x1FFF; - address <<= 1; - } - if (address < FEE_DENSITY_BYTES) { - eeprom_printf("DataBuf[0x%04x] = 0x%04x;\n", address, wvalue); - *(uint16_t *)(&DataBuf[address]) = wvalue; - } else { - eeprom_printf("DataBuf[0x%04x] cannot be set to 0x%04x [BAD ADDRESS]\n", address, wvalue); - } - } - } - - empty_slot = log_addr; - - if (debug_eeprom) { - println("EEPROM_Init Final DataBuf:"); - print_eeprom(); - } + // Clear Flags + // FLASH_ClearFlag(FLASH_SR_EOP|FLASH_SR_PGERR|FLASH_SR_WRPERR); return FEE_DENSITY_BYTES; } - -/* Clear flash contents (doesn't touch in-memory DataBuf) */ -static void eeprom_clear(void) { - FLASH_Unlock(); - - for (uint16_t page_num = 0; page_num < FEE_DENSITY_PAGES; ++page_num) { - eeprom_printf("FLASH_ErasePage(0x%04x)\n", (uint32_t)(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE))); - FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE)); - } - - FLASH_Lock(); - - empty_slot = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; - eeprom_printf("eeprom_clear empty_slot: 0x%08x\n", (uint32_t)empty_slot); -} - -/* Erase emulated eeprom */ +/***************************************************************************** + * Erase the whole reserved Flash Space used for user Data + ******************************************************************************/ void EEPROM_Erase(void) { - eeprom_println("EEPROM_Erase"); - /* Erase compacted pages and write log */ - eeprom_clear(); - /* re-initialize to reset DataBuf */ - EEPROM_Init(); + int page_num = 0; + + // delete all pages from specified start page to the last page + do { + FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE)); + page_num++; + } while (page_num < FEE_DENSITY_PAGES); } +/***************************************************************************** + * Writes once data byte to flash on specified address. If a byte is already + * written, the whole page must be copied to a buffer, the byte changed and + * the manipulated buffer written after PageErase. + *******************************************************************************/ +uint16_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) { + FLASH_Status FlashStatus = FLASH_COMPLETE; -/* Compact write log */ -static uint8_t eeprom_compact(void) { - /* Erase compacted pages and write log */ - eeprom_clear(); + uint32_t page; + int i; - FLASH_Unlock(); - - FLASH_Status final_status = FLASH_COMPLETE; - - /* Write emulated eeprom contents from memory to compacted flash */ - uint16_t *src = (uint16_t *)DataBuf; - uintptr_t dest = FEE_PAGE_BASE_ADDRESS; - uint16_t value; - for (; dest < FEE_PAGE_LAST_ADDRESS; ++src, dest += 2) { - value = *src; - if (value) { - eeprom_printf("FLASH_ProgramHalfWord(0x%04x, 0x%04x)\n", (uint32_t)dest, ~value); - FLASH_Status status = FLASH_ProgramHalfWord(dest, ~value); - if (status != FLASH_COMPLETE) final_status = status; - } + // exit if desired address is above the limit (e.G. under 2048 Bytes for 4 pages) + if (Address > FEE_DENSITY_BYTES) { + return 0; } - FLASH_Lock(); + // calculate which page is affected (Pagenum1/Pagenum2...PagenumN) + page = FEE_ADDR_OFFSET(Address) / FEE_PAGE_SIZE; - if (debug_eeprom) { - println("eeprom_compacted:"); - print_eeprom(); - } - - return final_status; -} - -static uint8_t eeprom_write_direct_entry(uint16_t Address) { - /* Check if we can just write this directly to the compacted flash area */ - uintptr_t directAddress = FEE_PAGE_BASE_ADDRESS + (Address & 0xFFFE); - if (*(uint16_t *)directAddress == FEE_EMPTY_WORD) { - /* Write the value directly to the compacted area without a log entry */ - uint16_t value = ~*(uint16_t *)(&DataBuf[Address & 0xFFFE]); - /* Early exit if a write isn't needed */ - if (value == FEE_EMPTY_WORD) return FLASH_COMPLETE; - - FLASH_Unlock(); - - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x) [DIRECT]\n", (uint32_t)directAddress, value); - FLASH_Status status = FLASH_ProgramHalfWord(directAddress, value); - - FLASH_Lock(); - return status; - } - return 0; -} - -static uint8_t eeprom_write_log_word_entry(uint16_t Address) { - FLASH_Status final_status = FLASH_COMPLETE; - - uint16_t value = *(uint16_t *)(&DataBuf[Address]); - eeprom_printf("eeprom_write_log_word_entry(0x%04x): 0x%04x\n", Address, value); - - /* MSB signifies the lowest 128-byte optimization is not in effect */ - uint16_t encoding = FEE_WORD_ENCODING; - uint8_t entry_size; - if (value <= 1) { - encoding |= value << 13; - entry_size = 2; + // if current data is 0xFF, the byte is empty, just overwrite with the new one + if ((*(__IO uint16_t *)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address))) == FEE_EMPTY_WORD) { + FlashStatus = FLASH_ProgramHalfWord(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address), (uint16_t)(0x00FF & DataByte)); } else { - encoding |= FEE_VALUE_NEXT; - entry_size = 4; - /* Writes to addresses less than 128 are byte log entries */ - Address -= FEE_BYTE_RANGE; - } + // Copy Page to a buffer + memcpy(DataBuf, (uint8_t *)FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE), FEE_PAGE_SIZE); // !!! Calculate base address for the desired page - /* if we can't find an empty spot, we must compact emulated eeprom */ - if (empty_slot > (uint16_t *)(FEE_WRITE_LOG_LAST_ADDRESS - entry_size)) { - /* compact the write log into the compacted flash area */ - return eeprom_compact(); - } - - /* Word log writes should be word-aligned. Take back a bit */ - Address >>= 1; - Address |= encoding; - - /* ok we found a place let's write our data */ - FLASH_Unlock(); - - /* address */ - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, Address); - final_status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, Address); - - /* value */ - if (encoding == (FEE_WORD_ENCODING | FEE_VALUE_NEXT)) { - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, ~value); - FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, ~value); - if (status != FLASH_COMPLETE) final_status = status; - } - - FLASH_Lock(); - - return final_status; -} - -static uint8_t eeprom_write_log_byte_entry(uint16_t Address) { - eeprom_printf("eeprom_write_log_byte_entry(0x%04x): 0x%02x\n", Address, DataBuf[Address]); - - /* if couldn't find an empty spot, we must compact emulated eeprom */ - if (empty_slot >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) { - /* compact the write log into the compacted flash area */ - return eeprom_compact(); - } - - /* ok we found a place let's write our data */ - FLASH_Unlock(); - - /* Pack address and value into the same word */ - uint16_t value = (Address << 8) | DataBuf[Address]; - - /* write to flash */ - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, value); - FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, value); - - FLASH_Lock(); - - return status; -} - -uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) { - /* if the address is out-of-bounds, do nothing */ - if (Address >= FEE_DENSITY_BYTES) { - eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [BAD ADDRESS]\n", Address, DataByte); - return FLASH_BAD_ADDRESS; - } - - /* if the value is the same, don't bother writing it */ - if (DataBuf[Address] == DataByte) { - eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [SKIP SAME]\n", Address, DataByte); - return 0; - } - - /* keep DataBuf cache in sync */ - DataBuf[Address] = DataByte; - eeprom_printf("EEPROM_WriteDataByte DataBuf[0x%04x] = 0x%02x\n", Address, DataBuf[Address]); - - /* perform the write into flash memory */ - /* First, attempt to write directly into the compacted flash area */ - FLASH_Status status = eeprom_write_direct_entry(Address); - if (!status) { - /* Otherwise append to the write log */ - if (Address < FEE_BYTE_RANGE) { - status = eeprom_write_log_byte_entry(Address); - } else { - status = eeprom_write_log_word_entry(Address & 0xFFFE); + // check if new data is differ to current data, return if not, proceed if yes + if (DataByte == *(__IO uint8_t *)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address))) { + return 0; } - } - if (status != 0 && status != FLASH_COMPLETE) { - eeprom_printf("EEPROM_WriteDataByte [STATUS == %d]\n", status); - } - return status; -} -uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord) { - /* if the address is out-of-bounds, do nothing */ - if (Address >= FEE_DENSITY_BYTES) { - eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [BAD ADDRESS]\n", Address, DataWord); - return FLASH_BAD_ADDRESS; - } + // manipulate desired data byte in temp data array if new byte is differ to the current + DataBuf[FEE_ADDR_OFFSET(Address) % FEE_PAGE_SIZE] = DataByte; - /* Check for word alignment */ - FLASH_Status final_status = FLASH_COMPLETE; - if (Address % 2) { - final_status = EEPROM_WriteDataByte(Address, DataWord); - FLASH_Status status = EEPROM_WriteDataByte(Address + 1, DataWord >> 8); - if (status != FLASH_COMPLETE) final_status = status; - if (final_status != 0 && final_status != FLASH_COMPLETE) { - eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status); - } - return final_status; - } + // Erase Page + FlashStatus = FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE)); - /* if the value is the same, don't bother writing it */ - uint16_t oldValue = *(uint16_t *)(&DataBuf[Address]); - if (oldValue == DataWord) { - eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [SKIP SAME]\n", Address, DataWord); - return 0; - } - - /* keep DataBuf cache in sync */ - *(uint16_t *)(&DataBuf[Address]) = DataWord; - eeprom_printf("EEPROM_WriteDataWord DataBuf[0x%04x] = 0x%04x\n", Address, *(uint16_t *)(&DataBuf[Address])); - - /* perform the write into flash memory */ - /* First, attempt to write directly into the compacted flash area */ - final_status = eeprom_write_direct_entry(Address); - if (!final_status) { - /* Otherwise append to the write log */ - /* Check if we need to fall back to byte write */ - if (Address < FEE_BYTE_RANGE) { - final_status = FLASH_COMPLETE; - /* Only write a byte if it has changed */ - if ((uint8_t)oldValue != (uint8_t)DataWord) { - final_status = eeprom_write_log_byte_entry(Address); + // Write new data (whole page) to flash if data has been changed + for (i = 0; i < (FEE_PAGE_SIZE / 2); i++) { + if ((__IO uint16_t)(0xFF00 | DataBuf[FEE_ADDR_OFFSET(i)]) != 0xFFFF) { + FlashStatus = FLASH_ProgramHalfWord((FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE)) + (i * 2), (uint16_t)(0xFF00 | DataBuf[FEE_ADDR_OFFSET(i)])); } - FLASH_Status status = FLASH_COMPLETE; - /* Only write a byte if it has changed */ - if ((oldValue >> 8) != (DataWord >> 8)) { - status = eeprom_write_log_byte_entry(Address + 1); - } - if (status != FLASH_COMPLETE) final_status = status; - } else { - final_status = eeprom_write_log_word_entry(Address); } } - if (final_status != 0 && final_status != FLASH_COMPLETE) { - eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status); - } - return final_status; + return FlashStatus; } - +/***************************************************************************** + * Read once data byte from a specified address. + *******************************************************************************/ uint8_t EEPROM_ReadDataByte(uint16_t Address) { uint8_t DataByte = 0xFF; - if (Address < FEE_DENSITY_BYTES) { - DataByte = DataBuf[Address]; - } - - eeprom_printf("EEPROM_ReadDataByte(0x%04x): 0x%02x\n", Address, DataByte); + // Get Byte from specified address + DataByte = (*(__IO uint8_t *)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address))); return DataByte; } -uint16_t EEPROM_ReadDataWord(uint16_t Address) { - uint16_t DataWord = 0xFFFF; - - if (Address < FEE_DENSITY_BYTES - 1) { - /* Check word alignment */ - if (Address % 2) { - DataWord = DataBuf[Address] | (DataBuf[Address + 1] << 8); - } else { - DataWord = *(uint16_t *)(&DataBuf[Address]); - } - } - - eeprom_printf("EEPROM_ReadDataWord(0x%04x): 0x%04x\n", Address, DataWord); - - return DataWord; -} - /***************************************************************************** * Wrap library in AVR style functions. *******************************************************************************/ -uint8_t eeprom_read_byte(const uint8_t *Address) { return EEPROM_ReadDataByte((const uintptr_t)Address); } +uint8_t eeprom_read_byte(const uint8_t *Address) { + const uint16_t p = (const uint32_t)Address; + return EEPROM_ReadDataByte(p); +} -void eeprom_write_byte(uint8_t *Address, uint8_t Value) { EEPROM_WriteDataByte((uintptr_t)Address, Value); } +void eeprom_write_byte(uint8_t *Address, uint8_t Value) { + uint16_t p = (uint32_t)Address; + EEPROM_WriteDataByte(p, Value); +} -void eeprom_update_byte(uint8_t *Address, uint8_t Value) { EEPROM_WriteDataByte((uintptr_t)Address, Value); } +void eeprom_update_byte(uint8_t *Address, uint8_t Value) { + uint16_t p = (uint32_t)Address; + EEPROM_WriteDataByte(p, Value); +} -uint16_t eeprom_read_word(const uint16_t *Address) { return EEPROM_ReadDataWord((const uintptr_t)Address); } +uint16_t eeprom_read_word(const uint16_t *Address) { + const uint16_t p = (const uint32_t)Address; + return EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p + 1) << 8); +} -void eeprom_write_word(uint16_t *Address, uint16_t Value) { EEPROM_WriteDataWord((uintptr_t)Address, Value); } +void eeprom_write_word(uint16_t *Address, uint16_t Value) { + uint16_t p = (uint32_t)Address; + EEPROM_WriteDataByte(p, (uint8_t)Value); + EEPROM_WriteDataByte(p + 1, (uint8_t)(Value >> 8)); +} -void eeprom_update_word(uint16_t *Address, uint16_t Value) { EEPROM_WriteDataWord((uintptr_t)Address, Value); } +void eeprom_update_word(uint16_t *Address, uint16_t Value) { + uint16_t p = (uint32_t)Address; + EEPROM_WriteDataByte(p, (uint8_t)Value); + EEPROM_WriteDataByte(p + 1, (uint8_t)(Value >> 8)); +} uint32_t eeprom_read_dword(const uint32_t *Address) { - const uint16_t p = (const uintptr_t)Address; - /* Check word alignment */ - if (p % 2) { - /* Not aligned */ - return (uint32_t)EEPROM_ReadDataByte(p) | (uint32_t)(EEPROM_ReadDataWord(p + 1) << 8) | (uint32_t)(EEPROM_ReadDataByte(p + 3) << 24); - } else { - /* Aligned */ - return EEPROM_ReadDataWord(p) | (EEPROM_ReadDataWord(p + 2) << 16); - } + const uint16_t p = (const uint32_t)Address; + return EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p + 1) << 8) | (EEPROM_ReadDataByte(p + 2) << 16) | (EEPROM_ReadDataByte(p + 3) << 24); } void eeprom_write_dword(uint32_t *Address, uint32_t Value) { - uint16_t p = (const uintptr_t)Address; - /* Check word alignment */ - if (p % 2) { - /* Not aligned */ + uint16_t p = (const uint32_t)Address; + EEPROM_WriteDataByte(p, (uint8_t)Value); + EEPROM_WriteDataByte(p + 1, (uint8_t)(Value >> 8)); + EEPROM_WriteDataByte(p + 2, (uint8_t)(Value >> 16)); + EEPROM_WriteDataByte(p + 3, (uint8_t)(Value >> 24)); +} + +void eeprom_update_dword(uint32_t *Address, uint32_t Value) { + uint16_t p = (const uint32_t)Address; + uint32_t existingValue = EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p + 1) << 8) | (EEPROM_ReadDataByte(p + 2) << 16) | (EEPROM_ReadDataByte(p + 3) << 24); + if (Value != existingValue) { EEPROM_WriteDataByte(p, (uint8_t)Value); - EEPROM_WriteDataWord(p + 1, (uint16_t)(Value >> 8)); + EEPROM_WriteDataByte(p + 1, (uint8_t)(Value >> 8)); + EEPROM_WriteDataByte(p + 2, (uint8_t)(Value >> 16)); EEPROM_WriteDataByte(p + 3, (uint8_t)(Value >> 24)); - } else { - /* Aligned */ - EEPROM_WriteDataWord(p, (uint16_t)Value); - EEPROM_WriteDataWord(p + 2, (uint16_t)(Value >> 16)); } } -void eeprom_update_dword(uint32_t *Address, uint32_t Value) { eeprom_write_dword(Address, Value); } - void eeprom_read_block(void *buf, const void *addr, size_t len) { - const uint8_t *src = (const uint8_t *)addr; + const uint8_t *p = (const uint8_t *)addr; uint8_t * dest = (uint8_t *)buf; - - /* Check word alignment */ - if (len && (uintptr_t)src % 2) { - /* Read the unaligned first byte */ - *dest++ = eeprom_read_byte(src++); - --len; - } - - uint16_t value; - bool aligned = ((uintptr_t)dest % 2 == 0); - while (len > 1) { - value = eeprom_read_word((uint16_t *)src); - if (aligned) { - *(uint16_t *)dest = value; - dest += 2; - } else { - *dest++ = value; - *dest++ = value >> 8; - } - src += 2; - len -= 2; - } - if (len) { - *dest = eeprom_read_byte(src); + while (len--) { + *dest++ = eeprom_read_byte(p++); } } void eeprom_write_block(const void *buf, void *addr, size_t len) { - uint8_t * dest = (uint8_t *)addr; - const uint8_t *src = (const uint8_t *)buf; - - /* Check word alignment */ - if (len && (uintptr_t)dest % 2) { - /* Write the unaligned first byte */ - eeprom_write_byte(dest++, *src++); - --len; - } - - uint16_t value; - bool aligned = ((uintptr_t)src % 2 == 0); - while (len > 1) { - if (aligned) { - value = *(uint16_t *)src; - } else { - value = *(uint8_t *)src | (*(uint8_t *)(src + 1) << 8); - } - eeprom_write_word((uint16_t *)dest, value); - dest += 2; - src += 2; - len -= 2; - } - - if (len) { - eeprom_write_byte(dest, *src); + uint8_t * p = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + while (len--) { + eeprom_write_byte(p++, *src++); } } -void eeprom_update_block(const void *buf, void *addr, size_t len) { eeprom_write_block(buf, addr, len); } +void eeprom_update_block(const void *buf, void *addr, size_t len) { + uint8_t * p = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + while (len--) { + eeprom_write_byte(p++, *src++); + } +} diff --git a/tmk_core/common/chibios/eeprom_stm32.h b/tmk_core/common/chibios/eeprom_stm32.h index 8fcfb556b8..4dac7c1b59 100644 --- a/tmk_core/common/chibios/eeprom_stm32.h +++ b/tmk_core/common/chibios/eeprom_stm32.h @@ -23,11 +23,62 @@ #pragma once +#include +#include +#include "flash_stm32.h" + +// HACK ALERT. This definition may not match your processor +// To Do. Work out correct value for EEPROM_PAGE_SIZE on the STM32F103CT6 etc +#if defined(EEPROM_EMU_STM32F303xC) +# define MCU_STM32F303CC +#elif defined(EEPROM_EMU_STM32F103xB) +# define MCU_STM32F103RB +#elif defined(EEPROM_EMU_STM32F072xB) +# define MCU_STM32F072CB +#elif defined(EEPROM_EMU_STM32F042x6) +# define MCU_STM32F042K6 +#else +# error "not implemented." +#endif + +#ifndef EEPROM_PAGE_SIZE +# if defined(MCU_STM32F103RB) || defined(MCU_STM32F042K6) +# define FEE_PAGE_SIZE (uint16_t)0x400 // Page size = 1KByte +# define FEE_DENSITY_PAGES 2 // How many pages are used +# elif defined(MCU_STM32F103ZE) || defined(MCU_STM32F103RE) || defined(MCU_STM32F103RD) || defined(MCU_STM32F303CC) || defined(MCU_STM32F072CB) +# 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)." +# endif +#endif + +#ifndef EEPROM_START_ADDRESS +# if defined(MCU_STM32F103RB) || defined(MCU_STM32F072CB) +# define FEE_MCU_FLASH_SIZE 128 // Size in Kb +# elif defined(MCU_STM32F042K6) +# define FEE_MCU_FLASH_SIZE 32 // Size in Kb +# elif defined(MCU_STM32F103ZE) || defined(MCU_STM32F103RE) +# define FEE_MCU_FLASH_SIZE 512 // Size in Kb +# elif defined(MCU_STM32F103RD) +# define FEE_MCU_FLASH_SIZE 384 // Size in Kb +# 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)." +# endif +#endif + +// DONT CHANGE +// Choose location for the first EEPROM Page address on the top of flash +#define FEE_PAGE_BASE_ADDRESS ((uint32_t)(0x8000000 + FEE_MCU_FLASH_SIZE * 1024 - FEE_DENSITY_PAGES * FEE_PAGE_SIZE)) +#define FEE_DENSITY_BYTES ((FEE_PAGE_SIZE / 2) * FEE_DENSITY_PAGES - 1) +#define FEE_LAST_PAGE_ADDRESS (FEE_PAGE_BASE_ADDRESS + (FEE_PAGE_SIZE * FEE_DENSITY_PAGES)) +#define FEE_EMPTY_WORD ((uint16_t)0xFFFF) +#define FEE_ADDR_OFFSET(Address) (Address * 2) // 1Byte per Word will be saved to preserve Flash + +// Use this function to initialize the functionality uint16_t EEPROM_Init(void); void EEPROM_Erase(void); -uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte); -uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord); +uint16_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte); uint8_t EEPROM_ReadDataByte(uint16_t Address); -uint16_t EEPROM_ReadDataWord(uint16_t Address); - -void print_eeprom(void); diff --git a/tmk_core/common/chibios/flash_stm32.h b/tmk_core/common/chibios/flash_stm32.h index 9c6a7cc50f..90d5bff47e 100644 --- a/tmk_core/common/chibios/flash_stm32.h +++ b/tmk_core/common/chibios/flash_stm32.h @@ -22,11 +22,8 @@ extern "C" { #endif -#include - -#ifdef FLASH_STM32_MOCKED -extern uint8_t FlashBuf[MOCK_FLASH_SIZE]; -#endif +#include +#include typedef enum { FLASH_BUSY = 1, FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_ERROR_OPT, FLASH_COMPLETE, FLASH_TIMEOUT, FLASH_BAD_ADDRESS } FLASH_Status; diff --git a/tmk_core/common/test/eeprom_stm32_tests.cpp b/tmk_core/common/test/eeprom_stm32_tests.cpp deleted file mode 100644 index aa84492b87..0000000000 --- a/tmk_core/common/test/eeprom_stm32_tests.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* Copyright 2021 by Don Kjer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gtest/gtest.h" - -extern "C" { -#include "flash_stm32.h" -#include "eeprom_stm32.h" -#include "eeprom.h" -} - -/* Mock Flash Parameters: - * - * === Large Layout === - * flash size: 65536 - * page size: 2048 - * density pages: 16 - * Simulated EEPROM size: 16384 - * - * FlashBuf Layout: - * [Unused | Compact | Write Log ] - * [0......|32768......|49152......65535] - * - * === Tiny Layout === - * flash size: 1024 - * page size: 512 - * density pages: 1 - * Simulated EEPROM size: 256 - * - * FlashBuf Layout: - * [Unused | Compact | Write Log ] - * [0......|512......|768......1023] - * - */ - -#define EEPROM_SIZE (FEE_PAGE_SIZE * FEE_DENSITY_PAGES / 2) -#define LOG_SIZE EEPROM_SIZE -#define LOG_BASE (MOCK_FLASH_SIZE - LOG_SIZE) -#define EEPROM_BASE (LOG_BASE - EEPROM_SIZE) - -/* Log encoding helpers */ -#define BYTE_VALUE(addr, value) (((addr) << 8) | (value)) -#define WORD_ZERO(addr) (0x8000 | ((addr) >> 1)) -#define WORD_ONE(addr) (0xA000 | ((addr) >> 1)) -#define WORD_NEXT(addr) (0xE000 | (((addr)-0x80) >> 1)) - -class EepromStm32Test : public testing::Test { - public: - EepromStm32Test() {} - ~EepromStm32Test() {} - - protected: - void SetUp() override { EEPROM_Erase(); } - - void TearDown() override { -#ifdef EEPROM_DEBUG - dumpEepromDataBuf(); -#endif - } -}; - -TEST_F(EepromStm32Test, TestErase) { - EEPROM_WriteDataByte(0, 0x42); - EEPROM_Erase(); - EXPECT_EQ(EEPROM_ReadDataByte(0), 0); - EXPECT_EQ(EEPROM_ReadDataByte(1), 0); -} - -TEST_F(EepromStm32Test, TestReadGarbage) { - uint8_t garbage = 0x3c; - for (int i = 0; i < MOCK_FLASH_SIZE; ++i) { - garbage ^= 0xa3; - garbage += i; - FlashBuf[i] = garbage; - } - EEPROM_Init(); // Just verify we don't crash -} - -TEST_F(EepromStm32Test, TestWriteBadAddress) { - EXPECT_EQ(EEPROM_WriteDataByte(EEPROM_SIZE, 0x42), FLASH_BAD_ADDRESS); - EXPECT_EQ(EEPROM_WriteDataWord(EEPROM_SIZE - 1, 0xbeef), FLASH_BAD_ADDRESS); - EXPECT_EQ(EEPROM_WriteDataWord(EEPROM_SIZE, 0xbeef), FLASH_BAD_ADDRESS); -} - -TEST_F(EepromStm32Test, TestReadBadAddress) { - EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE), 0xFF); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 1), 0xFFFF); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE), 0xFFFF); - EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0); - EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 3)), 0xFF000000); - EXPECT_EQ(eeprom_read_dword((uint32_t*)EEPROM_SIZE), 0xFFFFFFFF); -} - -TEST_F(EepromStm32Test, TestReadByte) { - /* Direct compacted-area baseline: Address < 0x80 */ - FlashBuf[EEPROM_BASE + 2] = ~0xef; - FlashBuf[EEPROM_BASE + 3] = ~0xbe; - /* Direct compacted-area baseline: Address >= 0x80 */ - FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2] = ~0x78; - FlashBuf[EEPROM_BASE + EEPROM_SIZE - 1] = ~0x56; - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef); - EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe); - EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x78); - EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56); - /* Write Log byte value */ - FlashBuf[LOG_BASE] = 0x65; - FlashBuf[LOG_BASE + 1] = 3; - /* Write Log word value */ - *(uint16_t*)&FlashBuf[LOG_BASE + 2] = WORD_NEXT(EEPROM_SIZE - 2); - *(uint16_t*)&FlashBuf[LOG_BASE + 4] = ~0x9abc; - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef); - EXPECT_EQ(EEPROM_ReadDataByte(3), 0x65); - EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0xbc); - EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x9a); -} - -TEST_F(EepromStm32Test, TestWriteByte) { - /* Direct compacted-area baseline: Address < 0x80 */ - EEPROM_WriteDataByte(2, 0xef); - EEPROM_WriteDataByte(3, 0xbe); - /* Direct compacted-area baseline: Address >= 0x80 */ - EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x78); - EEPROM_WriteDataByte(EEPROM_SIZE - 1, 0x56); - /* Check values */ - /* First write in each aligned word should have been direct */ - EXPECT_EQ(FlashBuf[EEPROM_BASE + 2], (uint8_t)~0xef); - EXPECT_EQ(FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2], (uint8_t)~0x78); - - /* Second write per aligned word requires a log entry */ - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], BYTE_VALUE(3, 0xbe)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_NEXT(EEPROM_SIZE - 1)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], (uint16_t)~0x5678); -} - -TEST_F(EepromStm32Test, TestByteRoundTrip) { - /* Direct compacted-area: Address < 0x80 */ - EEPROM_WriteDataWord(0, 0xdead); - EEPROM_WriteDataByte(2, 0xef); - EEPROM_WriteDataByte(3, 0xbe); - /* Direct compacted-area: Address >= 0x80 */ - EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x78); - EEPROM_WriteDataByte(EEPROM_SIZE - 1, 0x56); - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataByte(0), 0xad); - EXPECT_EQ(EEPROM_ReadDataByte(1), 0xde); - EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef); - EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe); - EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x78); - EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56); - /* Write log entries */ - EEPROM_WriteDataByte(2, 0x80); - EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x3c); - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataByte(2), 0x80); - EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe); - EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x3c); - EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56); -} - -TEST_F(EepromStm32Test, TestReadWord) { - /* Direct compacted-area baseline: Address < 0x80 */ - FlashBuf[EEPROM_BASE + 0] = ~0xad; - FlashBuf[EEPROM_BASE + 1] = ~0xde; - /* Direct compacted-area baseline: Address >= 0x80 */ - FlashBuf[EEPROM_BASE + 200] = ~0xcd; - FlashBuf[EEPROM_BASE + 201] = ~0xab; - FlashBuf[EEPROM_BASE + EEPROM_SIZE - 4] = ~0x34; - FlashBuf[EEPROM_BASE + EEPROM_SIZE - 3] = ~0x12; - FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2] = ~0x78; - FlashBuf[EEPROM_BASE + EEPROM_SIZE - 1] = ~0x56; - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataWord(0), 0xdead); - EXPECT_EQ(EEPROM_ReadDataWord(200), 0xabcd); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0x1234); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x5678); - /* Write Log word zero-encoded */ - *(uint16_t*)&FlashBuf[LOG_BASE] = WORD_ZERO(200); - /* Write Log word one-encoded */ - *(uint16_t*)&FlashBuf[LOG_BASE + 2] = WORD_ONE(EEPROM_SIZE - 4); - /* Write Log word value */ - *(uint16_t*)&FlashBuf[LOG_BASE + 4] = WORD_NEXT(EEPROM_SIZE - 2); - *(uint16_t*)&FlashBuf[LOG_BASE + 6] = ~0x9abc; - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataWord(200), 0); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 1); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x9abc); -} - -TEST_F(EepromStm32Test, TestWriteWord) { - /* Direct compacted-area: Address < 0x80 */ - EEPROM_WriteDataWord(0, 0xdead); // Aligned - EEPROM_WriteDataWord(3, 0xbeef); // Unaligned - /* Direct compacted-area: Address >= 0x80 */ - EEPROM_WriteDataWord(200, 0xabcd); // Aligned - EEPROM_WriteDataWord(203, 0x9876); // Unaligned - EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234); - EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678); - /* Write Log word zero-encoded */ - EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0); - /* Write Log word one-encoded */ - EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1); - /* Write Log word value aligned */ - EEPROM_WriteDataWord(200, 0x4321); // Aligned - /* Write Log word value unaligned */ - EEPROM_WriteDataByte(202, 0x3c); // Set neighboring byte - EEPROM_WriteDataWord(203, 0xcdef); // Unaligned - /* Check values */ - /* Direct compacted-area */ - EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE], (uint16_t)~0xdead); - EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + 3], (uint16_t)~0xbeef); - EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + 200], (uint16_t)~0xabcd); - EXPECT_EQ(FlashBuf[EEPROM_BASE + 203], (uint8_t)~0x76); - EXPECT_EQ(FlashBuf[EEPROM_BASE + 204], (uint8_t)~0x98); - EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + EEPROM_SIZE - 4], (uint16_t)~0x1234); - EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2], (uint16_t)~0x5678); - /* Write Log word zero-encoded */ - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], WORD_ZERO(EEPROM_SIZE - 4)); - /* Write Log word one-encoded */ - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_ONE(EEPROM_SIZE - 2)); - /* Write Log word value aligned */ - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], WORD_NEXT(200)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 6], (uint16_t)~0x4321); - /* Write Log word value unaligned */ - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 8], WORD_NEXT(202)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 10], (uint16_t)~0x763c); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 12], WORD_NEXT(202)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 14], (uint16_t)~0xef3c); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 16], WORD_NEXT(204)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 18], (uint16_t)~0x00cd); -} - -TEST_F(EepromStm32Test, TestWordRoundTrip) { - /* Direct compacted-area: Address < 0x80 */ - EEPROM_WriteDataWord(0, 0xdead); // Aligned - EEPROM_WriteDataWord(3, 0xbeef); // Unaligned - /* Direct compacted-area: Address >= 0x80 */ - EEPROM_WriteDataWord(200, 0xabcd); // Aligned - EEPROM_WriteDataWord(203, 0x9876); // Unaligned - EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234); - EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678); - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataWord(0), 0xdead); - EXPECT_EQ(EEPROM_ReadDataWord(3), 0xbeef); - EXPECT_EQ(EEPROM_ReadDataWord(200), 0xabcd); - EXPECT_EQ(EEPROM_ReadDataWord(203), 0x9876); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0x1234); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x5678); - - /* Write Log word zero-encoded */ - EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0); - /* Write Log word one-encoded */ - EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1); - /* Write Log word value aligned */ - EEPROM_WriteDataWord(200, 0x4321); // Aligned - /* Write Log word value unaligned */ - EEPROM_WriteDataByte(202, 0x3c); // Set neighboring byte - EEPROM_WriteDataWord(203, 0xcdef); // Unaligned - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataWord(200), 0x4321); - EXPECT_EQ(EEPROM_ReadDataByte(202), 0x3c); - EXPECT_EQ(EEPROM_ReadDataWord(203), 0xcdef); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0); - EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 1); -} - -TEST_F(EepromStm32Test, TestByteWordBoundary) { - /* Direct compacted-area write */ - EEPROM_WriteDataWord(0x7e, 0xdead); - EEPROM_WriteDataWord(0x80, 0xbeef); - /* Byte log entry */ - EEPROM_WriteDataByte(0x7f, 0x3c); - /* Word log entry */ - EEPROM_WriteDataByte(0x80, 0x18); - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataWord(0x7e), 0x3cad); - EXPECT_EQ(EEPROM_ReadDataWord(0x80), 0xbe18); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], BYTE_VALUE(0x7f, 0x3c)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_NEXT(0x80)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], (uint16_t)~0xbe18); - /* Byte log entries */ - EEPROM_WriteDataWord(0x7e, 0xcafe); - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataWord(0x7e), 0xcafe); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 6], BYTE_VALUE(0x7e, 0xfe)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 8], BYTE_VALUE(0x7f, 0xca)); - /* Byte and Word log entries */ - EEPROM_WriteDataWord(0x7f, 0xba5e); - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataWord(0x7f), 0xba5e); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 10], BYTE_VALUE(0x7f, 0x5e)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 12], WORD_NEXT(0x80)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 14], (uint16_t)~0xbeba); - /* Word log entry */ - EEPROM_WriteDataWord(0x80, 0xf00d); - /* Check values */ - EEPROM_Init(); - EXPECT_EQ(EEPROM_ReadDataWord(0x80), 0xf00d); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 16], WORD_NEXT(0x80)); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 18], (uint16_t)~0xf00d); -} - -TEST_F(EepromStm32Test, TestDWordRoundTrip) { - /* Direct compacted-area: Address < 0x80 */ - eeprom_write_dword((uint32_t*)0, 0xdeadbeef); // Aligned - eeprom_write_dword((uint32_t*)9, 0x12345678); // Unaligned - /* Direct compacted-area: Address >= 0x80 */ - eeprom_write_dword((uint32_t*)200, 0xfacef00d); - eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xba5eba11); // Aligned - eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0xcafed00d); // Unaligned - /* Check direct values */ - EEPROM_Init(); - EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef); - EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x12345678); - EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 0xfacef00d); - EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xba5eba11); // Aligned - EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0xcafed00d); // Unaligned - /* Write Log byte encoded */ - eeprom_write_dword((uint32_t*)0, 0xdecafbad); - eeprom_write_dword((uint32_t*)9, 0x87654321); - /* Write Log word encoded */ - eeprom_write_dword((uint32_t*)200, 1); - /* Write Log word value aligned */ - eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xdeadc0de); // Aligned - eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0x6789abcd); // Unaligned - /* Check log values */ - EEPROM_Init(); - EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdecafbad); - EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x87654321); - EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 1); - EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xdeadc0de); // Aligned - EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0x6789abcd); // Unaligned -} - -TEST_F(EepromStm32Test, TestBlockRoundTrip) { - char src0[] = "0123456789abcdef"; - void* src1 = (void*)&src0[1]; - /* Various alignments of src & dst, Address < 0x80 */ - eeprom_write_block(src0, (void*)0, sizeof(src0)); - eeprom_write_block(src0, (void*)21, sizeof(src0)); - eeprom_write_block(src1, (void*)40, sizeof(src0) - 1); - eeprom_write_block(src1, (void*)61, sizeof(src0) - 1); - /* Various alignments of src & dst, Address >= 0x80 */ - eeprom_write_block(src0, (void*)140, sizeof(src0)); - eeprom_write_block(src0, (void*)161, sizeof(src0)); - eeprom_write_block(src1, (void*)180, sizeof(src0) - 1); - eeprom_write_block(src1, (void*)201, sizeof(src0) - 1); - - /* Check values */ - EEPROM_Init(); - - char dstBuf[256] = {0}; - char* dst0a = (char*)dstBuf; - char* dst0b = (char*)&dstBuf[20]; - char* dst1a = (char*)&dstBuf[41]; - char* dst1b = (char*)&dstBuf[61]; - char* dst0c = (char*)&dstBuf[80]; - char* dst0d = (char*)&dstBuf[100]; - char* dst1c = (char*)&dstBuf[121]; - char* dst1d = (char*)&dstBuf[141]; - eeprom_read_block((void*)dst0a, (void*)0, sizeof(src0)); - eeprom_read_block((void*)dst0b, (void*)21, sizeof(src0)); - eeprom_read_block((void*)dst1a, (void*)40, sizeof(src0) - 1); - eeprom_read_block((void*)dst1b, (void*)61, sizeof(src0) - 1); - eeprom_read_block((void*)dst0c, (void*)140, sizeof(src0)); - eeprom_read_block((void*)dst0d, (void*)161, sizeof(src0)); - eeprom_read_block((void*)dst1c, (void*)180, sizeof(src0) - 1); - eeprom_read_block((void*)dst1d, (void*)201, sizeof(src0) - 1); - EXPECT_EQ(strcmp((char*)src0, dst0a), 0); - EXPECT_EQ(strcmp((char*)src0, dst0b), 0); - EXPECT_EQ(strcmp((char*)src0, dst0c), 0); - EXPECT_EQ(strcmp((char*)src0, dst0d), 0); - EXPECT_EQ(strcmp((char*)src1, dst1a), 0); - EXPECT_EQ(strcmp((char*)src1, dst1b), 0); - EXPECT_EQ(strcmp((char*)src1, dst1c), 0); - EXPECT_EQ(strcmp((char*)src1, dst1d), 0); -} - -TEST_F(EepromStm32Test, TestCompaction) { - /* Direct writes */ - eeprom_write_dword((uint32_t*)0, 0xdeadbeef); - eeprom_write_byte((uint8_t*)4, 0x3c); - eeprom_write_word((uint16_t*)6, 0xd00d); - eeprom_write_dword((uint32_t*)150, 0xcafef00d); - eeprom_write_dword((uint32_t*)200, 0x12345678); - /* Fill write log entries */ - uint32_t i; - uint32_t val = 0xd8453c6b; - for (i = 0; i < (LOG_SIZE / (sizeof(uint32_t) * 2)); i++) { - val ^= 0x593ca5b3; - val += i; - eeprom_write_dword((uint32_t*)200, val); - } - /* Check values pre-compaction */ - EEPROM_Init(); - EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef); - EXPECT_EQ(eeprom_read_byte((uint8_t*)4), 0x3c); - EXPECT_EQ(eeprom_read_word((uint16_t*)6), 0xd00d); - EXPECT_EQ(eeprom_read_dword((uint32_t*)150), 0xcafef00d); - EXPECT_EQ(eeprom_read_dword((uint32_t*)200), val); - EXPECT_NE(*(uint16_t*)&FlashBuf[LOG_BASE], 0xFFFF); - EXPECT_NE(*(uint16_t*)&FlashBuf[LOG_BASE + LOG_SIZE - 2], 0xFFFF); - /* Run compaction */ - eeprom_write_byte((uint8_t*)4, 0x1f); - EEPROM_Init(); - EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef); - EXPECT_EQ(eeprom_read_byte((uint8_t*)4), 0x1f); - EXPECT_EQ(eeprom_read_word((uint16_t*)6), 0xd00d); - EXPECT_EQ(eeprom_read_dword((uint32_t*)150), 0xcafef00d); - EXPECT_EQ(eeprom_read_dword((uint32_t*)200), val); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], 0xFFFF); - EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + LOG_SIZE - 2], 0xFFFF); -} diff --git a/tmk_core/common/test/flash_stm32_mock.c b/tmk_core/common/test/flash_stm32_mock.c deleted file mode 100644 index 1b81d81f9a..0000000000 --- a/tmk_core/common/test/flash_stm32_mock.c +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright 2021 by Don Kjer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include "flash_stm32.h" - -uint8_t FlashBuf[MOCK_FLASH_SIZE] = {0}; - -static bool flash_locked = true; - -FLASH_Status FLASH_ErasePage(uint32_t Page_Address) { - if (flash_locked) return FLASH_ERROR_WRP; - Page_Address -= (uintptr_t)FlashBuf; - Page_Address -= (Page_Address % FEE_PAGE_SIZE); - if (Page_Address >= MOCK_FLASH_SIZE) return FLASH_BAD_ADDRESS; - memset(&FlashBuf[Page_Address], '\xff', FEE_PAGE_SIZE); - return FLASH_COMPLETE; -} - -FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) { - if (flash_locked) return FLASH_ERROR_WRP; - Address -= (uintptr_t)FlashBuf; - if (Address >= MOCK_FLASH_SIZE) return FLASH_BAD_ADDRESS; - uint16_t oldData = *(uint16_t*)&FlashBuf[Address]; - if (oldData == 0xFFFF || Data == 0) { - *(uint16_t*)&FlashBuf[Address] = Data; - return FLASH_COMPLETE; - } else { - return FLASH_ERROR_PG; - } -} - -FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) { return FLASH_COMPLETE; } -void FLASH_Unlock(void) { flash_locked = false; } -void FLASH_Lock(void) { flash_locked = true; } -void FLASH_ClearFlag(uint32_t FLASH_FLAG) {} diff --git a/tmk_core/common/test/rules.mk b/tmk_core/common/test/rules.mk deleted file mode 100644 index e47e5880c5..0000000000 --- a/tmk_core/common/test/rules.mk +++ /dev/null @@ -1,23 +0,0 @@ -eeprom_stm32_DEFS := -DFLASH_STM32_MOCKED -DNO_PRINT -DFEE_FLASH_BASE=FlashBuf -eeprom_stm32_tiny_DEFS := $(eeprom_stm32_DEFS) \ - -DFEE_MCU_FLASH_SIZE=1 \ - -DMOCK_FLASH_SIZE=1024 \ - -DFEE_PAGE_SIZE=512 \ - -DFEE_DENSITY_PAGES=1 -eeprom_stm32_large_DEFS := $(eeprom_stm32_DEFS) \ - -DFEE_MCU_FLASH_SIZE=64 \ - -DMOCK_FLASH_SIZE=65536 \ - -DFEE_PAGE_SIZE=2048 \ - -DFEE_DENSITY_PAGES=16 - -eeprom_stm32_INC := \ - $(TMK_PATH)/common/chibios/ -eeprom_stm32_tiny_INC := $(eeprom_stm32_INC) -eeprom_stm32_large_INC := $(eeprom_stm32_INC) - -eeprom_stm32_SRC := \ - $(TMK_PATH)/common/test/eeprom_stm32_tests.cpp \ - $(TMK_PATH)/common/test/flash_stm32_mock.c \ - $(TMK_PATH)/common/chibios/eeprom_stm32.c -eeprom_stm32_tiny_SRC := $(eeprom_stm32_SRC) -eeprom_stm32_large_SRC := $(eeprom_stm32_SRC) diff --git a/tmk_core/common/test/testlist.mk b/tmk_core/common/test/testlist.mk deleted file mode 100644 index 51a9638bb9..0000000000 --- a/tmk_core/common/test/testlist.mk +++ /dev/null @@ -1 +0,0 @@ -TEST_LIST += eeprom_stm32_tiny eeprom_stm32_large diff --git a/util/stm32eeprom_parser.py b/util/stm32eeprom_parser.py deleted file mode 100755 index b124f713d5..0000000000 --- a/util/stm32eeprom_parser.py +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2021 Don Kjer -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from __future__ import print_function - -import argparse -from struct import pack, unpack -import os, sys - -MAGIC_FEEA = '\xea\xff\xfe\xff' - -MAGIC_FEE9 = '\x16\x01' -EMPTY_WORD = '\xff\xff' -WORD_ENCODING = 0x8000 -VALUE_NEXT = 0x6000 -VALUE_RESERVED = 0x4000 -VALUE_ENCODED = 0x2000 -BYTE_RANGE = 0x80 - -CHUNK_SIZE = 1024 - -STRUCT_FMTS = { - 1: 'B', - 2: 'H', - 4: 'I' -} -PRINTABLE='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ ' - -EECONFIG_V1 = [ - ("MAGIC", 0, 2), - ("DEBUG", 2, 1), - ("DEFAULT_LAYER", 3, 1), - ("KEYMAP", 4, 1), - ("MOUSEKEY_ACCEL", 5, 1), - ("BACKLIGHT", 6, 1), - ("AUDIO", 7, 1), - ("RGBLIGHT", 8, 4), - ("UNICODEMODE", 12, 1), - ("STENOMODE", 13, 1), - ("HANDEDNESS", 14, 1), - ("KEYBOARD", 15, 4), - ("USER", 19, 4), - ("VELOCIKEY", 23, 1), - ("HAPTIC", 24, 4), - ("MATRIX", 28, 4), - ("MATRIX_EXTENDED", 32, 2), - ("KEYMAP_UPPER_BYTE", 34, 1), -] -VIABASE_V1 = 35 - -VERBOSE = False - -def parseArgs(): - parser = argparse.ArgumentParser(description='Decode an STM32 emulated eeprom dump') - parser.add_argument('-s', '--size', type=int, - help='Size of the emulated eeprom (default: input_size / 2)') - parser.add_argument('-o', '--output', help='File to write decoded eeprom to') - parser.add_argument('-y', '--layout-options-size', type=int, - help='VIA layout options size (default: 1)', default=1) - parser.add_argument('-t', '--custom-config-size', type=int, - help='VIA custom config size (default: 0)', default=0) - parser.add_argument('-l', '--layers', type=int, - help='VIA keyboard layers (default: 4)', default=4) - parser.add_argument('-r', '--rows', type=int, help='VIA matrix rows') - parser.add_argument('-c', '--cols', type=int, help='VIA matrix columns') - parser.add_argument('-m', '--macros', type=int, - help='VIA macro count (default: 16)', default=16) - parser.add_argument('-C', '--canonical', action='store_true', - help='Canonical hex+ASCII display.') - parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output') - parser.add_argument('input', help='Raw contents of the STM32 flash area used to emulate eeprom') - return parser.parse_args() - - -def decodeEepromFEEA(in_file, size): - decoded=size*[None] - pos = 0 - while True: - chunk = in_file.read(CHUNK_SIZE) - for i in range(0, len(chunk), 2): - decoded[pos] = unpack('B', chunk[i])[0] - pos += 1 - if pos >= size: - break - - if len(chunk) < CHUNK_SIZE or pos >= size: - break - return decoded - -def decodeEepromFEE9(in_file, size): - decoded=size*[None] - pos = 0 - # Read compacted flash - while True: - read_size = min(size - pos, CHUNK_SIZE) - chunk = in_file.read(read_size) - for i in range(len(chunk)): - decoded[pos] = unpack('B', chunk[i])[0] ^ 0xFF - pos += 1 - if pos >= size: - break - - if len(chunk) < read_size or pos >= size: - break - if VERBOSE: - print("COMPACTED EEPROM:") - dumpBinary(decoded, True) - print("WRITE LOG:") - # Read write log - while True: - entry = in_file.read(2) - if len(entry) < 2: - print("Partial log address at position 0x%04x" % pos, file=sys.stderr) - break - pos += 2 - - if entry == EMPTY_WORD: - break - - be_entry = unpack('>H', entry)[0] - entry = unpack('H', entry)[0] - if not (entry & WORD_ENCODING): - address = entry >> 8 - decoded[address] = entry & 0xFF - if VERBOSE: - print("[0x%04x]: BYTE 0x%02x = 0x%02x" % (be_entry, address, decoded[address])) - else: - if (entry & VALUE_NEXT) == VALUE_NEXT: - # Read next word as value - value = in_file.read(2) - if len(value) < 2: - print("Partial log value at position 0x%04x" % pos, file=sys.stderr) - break - pos += 2 - address = entry & 0x1FFF - address <<= 1 - address += BYTE_RANGE - decoded[address] = unpack('B', value[0])[0] ^ 0xFF - decoded[address+1] = unpack('B', value[1])[0] ^ 0xFF - be_value = unpack('>H', value)[0] - if VERBOSE: - print("[0x%04x 0x%04x]: WORD 0x%04x = 0x%02x%02x" % (be_entry, be_value, address, decoded[address+1], decoded[address])) - else: - # Reserved for future use - if entry & VALUE_RESERVED: - if VERBOSE: - print("[0x%04x]: RESERVED 0x%04x" % (be_entry, address)) - continue - address = entry & 0x1FFF - address <<= 1 - decoded[address] = (entry & VALUE_ENCODED) >> 13 - decoded[address+1] = 0 - if VERBOSE: - print("[0x%04x]: ENCODED 0x%04x = 0x%02x%02x" % (be_entry, address, decoded[address+1], decoded[address])) - - return decoded - -def dumpBinary(data, canonical): - def display(pos, row): - print("%04x" % pos, end='') - for i in range(len(row)): - if i % 8 == 0: - print(" ", end='') - char = row[i] - if char is None: - print(" ", end='') - else: - print(" %02x" % row[i], end='') - if canonical: - print(" |", end='') - for i in range(len(row)): - char = row[i] - if char is None: - char = " " - else: - char = chr(char) - if char not in PRINTABLE: - char = "." - print(char, end='') - print("|", end='') - - print("") - - size = len(data) - empty_rows = 0 - prev_row = '' - first_repeat = True - for pos in range(0, size, 16): - row=data[pos:pos+16] - row[len(row):16] = (16-len(row))*[None] - if row == prev_row: - if first_repeat: - print("*") - first_repeat = False - else: - first_repeat = True - display(pos, row) - prev_row = row - print("%04x" % (pos+16)) - -def dumpEeconfig(data, eeconfig): - print("EECONFIG:") - for (name, pos, length) in eeconfig: - fmt = STRUCT_FMTS[length] - value = unpack(fmt, ''.join([chr(x) for x in data[pos:pos+length]]))[0] - print(("%%04x %%s = 0x%%0%dx" % (length * 2)) % (pos, name, value)) - -def dumpVia(data, base, layers, cols, rows, macros, - layout_options_size, custom_config_size): - magicYear = data[base + 0] - magicMonth = data[base + 1] - magicDay = data[base + 2] - # Sanity check - if not 10 <= magicYear <= 0x99 or \ - not 0 <= magicMonth <= 0x12 or \ - not 0 <= magicDay <= 0x31: - print("ERROR: VIA Signature is not valid; Year:%x, Month:%x, Day:%x" % (magicYear, magicMonth, magicDay)) - return - if cols is None or rows is None: - print("ERROR: VIA dump requires specifying --rows and --cols", file=sys.stderr) - return 2 - print("VIA:") - # Decode magic - print("%04x MAGIC = 20%02x-%02x-%02x" % (base, magicYear, magicMonth, magicDay)) - # Decode layout options - options = 0 - pos = base + 3 - for i in range(base+3, base+3+layout_options_size): - options = options << 8 - options |= data[i] - print(("%%04x LAYOUT_OPTIONS = 0x%%0%dx" % (layout_options_size * 2)) % (pos, options)) - pos += layout_options_size + custom_config_size - # Decode keycodes - keymap_size = layers * rows * cols * 2 - if (pos + keymap_size) >= (len(data) - 1): - print("ERROR: VIA keymap requires %d bytes, but only %d available" % (keymap_size, len(data) - pos)) - return 3 - for layer in range(layers): - print("%s LAYER %d %s" % ('-'*int(cols*2.5), layer, '-'*int(cols*2.5))) - for row in range(rows): - print("%04x | " % pos, end='') - for col in range(cols): - keycode = (data[pos] << 8) | (data[pos+1]) - print(" %04x" % keycode, end='') - pos += 2 - print("") - # Decode macros - for macro_num in range(macros): - macro = "" - macro_pos = pos - while pos < len(data): - char = chr(data[pos]) - pos += 1 - if char == '\x00': - print("%04x MACRO[%d] = '%s'" % (macro_pos, macro_num, macro)) - break - else: - macro += char - return 0 - - -def decodeSTM32Eeprom(input, canonical, size=None, output=None, **kwargs): - input_size = os.path.getsize(input) - if size is None: - size = input_size >> 1 - - # Read the first few bytes to check magic signature - with open(input, 'rb') as in_file: - magic=in_file.read(4) - in_file.seek(0) - - if magic == MAGIC_FEEA: - decoded = decodeEepromFEEA(in_file, size) - eeconfig = EECONFIG_V1 - via_base = VIABASE_V1 - elif magic[:2] == MAGIC_FEE9: - decoded = decodeEepromFEE9(in_file, size) - eeconfig = EECONFIG_V1 - via_base = VIABASE_V1 - else: - print("Unknown magic signature: %s" % " ".join(["0x%02x" % ord(x) for x in magic]), file=sys.stderr) - return 1 - - if output is not None: - with open(output, 'wb') as out_file: - out_file.write(pack('%dB' % len(decoded), *decoded)) - print("DECODED EEPROM:") - dumpBinary(decoded, canonical) - dumpEeconfig(decoded, eeconfig) - if kwargs['rows'] is not None and kwargs['cols'] is not None: - return dumpVia(decoded, via_base, **kwargs) - - return 0 - -def main(): - global VERBOSE - kwargs = vars(parseArgs()) - VERBOSE = kwargs.pop('verbose') - return decodeSTM32Eeprom(**kwargs) - -if __name__ == '__main__': - sys.exit(main())