123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687 |
- #include <stdio.h>
- #include <stdbool.h>
- #include "util.h"
- #include "debug.h"
- #include "eeprom_stm32.h"
- #include "flash_stm32.h"
- #include "eeprom_stm32_defs.h"
- #if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT) || !defined(FEE_MCU_FLASH_SIZE) || !defined(FEE_PAGE_BASE_ADDRESS)
- # error "not implemented."
- #endif
- #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
- #define FEE_ADDRESS_MAX_SIZE 0x4000
- #define FEE_EMPTY_WORD ((uint16_t)0xFFFF)
- #define FEE_DENSITY_MAX_SIZE (FEE_PAGE_COUNT * FEE_PAGE_SIZE)
- #ifndef FEE_MCU_FLASH_SIZE_IGNORE_CHECK
- # if FEE_DENSITY_MAX_SIZE > (FEE_MCU_FLASH_SIZE * 1024)
- # pragma message STR(FEE_DENSITY_MAX_SIZE) " > " STR(FEE_MCU_FLASH_SIZE * 1024)
- # error emulated eeprom: FEE_DENSITY_MAX_SIZE is greater than available flash size
- # endif
- #endif
- #ifdef FEE_DENSITY_BYTES
- # if (FEE_DENSITY_BYTES > FEE_DENSITY_MAX_SIZE)
- # pragma message STR(FEE_DENSITY_BYTES) " > " STR(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 STR(FEE_DENSITY_BYTES) " == " STR(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 STR(FEE_DENSITY_BYTES) " > " STR(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
- # define FEE_DENSITY_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE / 2)
- #endif
- #ifdef FEE_WRITE_LOG_BYTES
- # if ((FEE_DENSITY_BYTES + FEE_WRITE_LOG_BYTES) > FEE_DENSITY_MAX_SIZE)
- # pragma message STR(FEE_DENSITY_BYTES) " + " STR(FEE_WRITE_LOG_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE)
- # error emulated eeprom: FEE_WRITE_LOG_BYTES exceeds remaining FEE_DENSITY_MAX_SIZE
- # endif
- # if ((FEE_WRITE_LOG_BYTES) % 2) == 1
- # error emulated eeprom: FEE_WRITE_LOG_BYTES must be even
- # endif
- #else
- # define FEE_WRITE_LOG_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES)
- #endif
- #define FEE_COMPACTED_BASE_ADDRESS FEE_PAGE_BASE_ADDRESS
- #define FEE_COMPACTED_LAST_ADDRESS (FEE_COMPACTED_BASE_ADDRESS + FEE_DENSITY_BYTES)
- #define FEE_WRITE_LOG_BASE_ADDRESS FEE_COMPACTED_LAST_ADDRESS
- #define FEE_WRITE_LOG_LAST_ADDRESS (FEE_WRITE_LOG_BASE_ADDRESS + FEE_WRITE_LOG_BYTES)
- #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
- static uint16_t WordBuf[FEE_DENSITY_BYTES / 2];
- static uint8_t *DataBuf = (uint8_t *)WordBuf;
- static uint16_t *empty_slot;
- #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
- # define debug_eeprom false
- # define eeprom_println(s)
- # define eeprom_printf(fmt, ...)
- #endif
- 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) {
-
- empty_rows = 0;
- }
-
- ++empty_rows;
- for (uint16_t j = 0; j < 16; j++) {
- if (DataBuf[i + j]) {
- empty_rows = 0;
- break;
- }
- }
- if (empty_rows > 1) {
-
- if (empty_rows == 2) {
-
- println("*");
- }
- i += 15;
- continue;
- }
- xprintf("%04x", i);
- }
- if (i % 8 == 0) print(" ");
- xprintf(" %02x", DataBuf[i]);
- if ((i + 1) % 16 == 0) {
- println("");
- }
- }
- #endif
- }
- uint16_t EEPROM_Init(void) {
-
- uint16_t *src = (uint16_t *)FEE_COMPACTED_BASE_ADDRESS;
- uint16_t *dest = (uint16_t *)DataBuf;
- for (; src < (uint16_t *)FEE_COMPACTED_LAST_ADDRESS; ++src, ++dest) {
- *dest = ~*src;
- }
- if (debug_eeprom) {
- println("EEPROM_Init Compacted Pages:");
- print_eeprom();
- println("EEPROM_Init 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;
- }
-
- 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;
-
- if ((address & FEE_VALUE_NEXT) == FEE_VALUE_NEXT) {
-
- 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);
-
- continue;
- }
- address &= 0x1FFF;
- address <<= 1;
-
- address += FEE_BYTE_RANGE;
- } else {
-
- if (address & FEE_VALUE_RESERVED) {
- eeprom_printf("Reserved encoded value at log_addr: 0x%04x;\n", (uint32_t)log_addr);
- continue;
- }
-
- 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();
- }
- return FEE_DENSITY_BYTES;
- }
- static void eeprom_clear(void) {
- FLASH_Unlock();
- for (uint16_t page_num = 0; page_num < FEE_PAGE_COUNT; ++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);
- }
- void EEPROM_Erase(void) {
- eeprom_println("EEPROM_Erase");
-
- eeprom_clear();
-
- EEPROM_Init();
- }
- static uint8_t eeprom_compact(void) {
-
- eeprom_clear();
- FLASH_Unlock();
- FLASH_Status final_status = FLASH_COMPLETE;
-
- uint16_t *src = (uint16_t *)DataBuf;
- uintptr_t dest = FEE_COMPACTED_BASE_ADDRESS;
- uint16_t value;
- for (; dest < FEE_COMPACTED_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;
- }
- }
- FLASH_Lock();
- if (debug_eeprom) {
- println("eeprom_compacted:");
- print_eeprom();
- }
- return final_status;
- }
- static uint8_t eeprom_write_direct_entry(uint16_t Address) {
-
- uintptr_t directAddress = FEE_COMPACTED_BASE_ADDRESS + (Address & 0xFFFE);
- if (*(uint16_t *)directAddress == FEE_EMPTY_WORD) {
-
- uint16_t value = ~*(uint16_t *)(&DataBuf[Address & 0xFFFE]);
-
- 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);
-
- uint16_t encoding = FEE_WORD_ENCODING;
- uint8_t entry_size;
- if (value <= 1) {
- encoding |= value << 13;
- entry_size = 2;
- } else {
- encoding |= FEE_VALUE_NEXT;
- entry_size = 4;
-
- Address -= FEE_BYTE_RANGE;
- }
-
- if (empty_slot > (uint16_t *)(FEE_WRITE_LOG_LAST_ADDRESS - entry_size)) {
-
- return eeprom_compact();
- }
-
- Address >>= 1;
- Address |= encoding;
-
- FLASH_Unlock();
-
- eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, Address);
- final_status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, Address);
-
- 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 (empty_slot >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) {
-
- return eeprom_compact();
- }
-
- FLASH_Unlock();
-
- uint16_t value = (Address << 8) | DataBuf[Address];
-
- 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 (Address >= FEE_DENSITY_BYTES) {
- eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [BAD ADDRESS]\n", Address, DataByte);
- return FLASH_BAD_ADDRESS;
- }
-
- if (DataBuf[Address] == DataByte) {
- eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [SKIP SAME]\n", Address, DataByte);
- return 0;
- }
-
- DataBuf[Address] = DataByte;
- eeprom_printf("EEPROM_WriteDataByte DataBuf[0x%04x] = 0x%02x\n", Address, DataBuf[Address]);
-
-
- FLASH_Status status = eeprom_write_direct_entry(Address);
- if (!status) {
-
- if (Address < FEE_BYTE_RANGE) {
- status = eeprom_write_log_byte_entry(Address);
- } else {
- status = eeprom_write_log_word_entry(Address & 0xFFFE);
- }
- }
- 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 (Address >= FEE_DENSITY_BYTES) {
- eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [BAD ADDRESS]\n", Address, DataWord);
- return FLASH_BAD_ADDRESS;
- }
-
- 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;
- }
-
- 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;
- }
-
- *(uint16_t *)(&DataBuf[Address]) = DataWord;
- eeprom_printf("EEPROM_WriteDataWord DataBuf[0x%04x] = 0x%04x\n", Address, *(uint16_t *)(&DataBuf[Address]));
-
-
- final_status = eeprom_write_direct_entry(Address);
- if (!final_status) {
-
-
- if (Address < FEE_BYTE_RANGE) {
- final_status = FLASH_COMPLETE;
-
- if ((uint8_t)oldValue != (uint8_t)DataWord) {
- final_status = eeprom_write_log_byte_entry(Address);
- }
- FLASH_Status status = FLASH_COMPLETE;
-
- 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;
- }
- 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);
- return DataByte;
- }
- uint16_t EEPROM_ReadDataWord(uint16_t Address) {
- uint16_t DataWord = 0xFFFF;
- if (Address < FEE_DENSITY_BYTES - 1) {
-
- 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;
- }
- void eeprom_driver_init(void) { EEPROM_Init(); }
- void eeprom_driver_erase(void) { EEPROM_Erase(); }
- void eeprom_read_block(void *buf, const void *addr, size_t len) {
- const uint8_t *src = (const uint8_t *)addr;
- uint8_t * dest = (uint8_t *)buf;
-
- if (len && (uintptr_t)src % 2) {
-
- *dest++ = EEPROM_ReadDataByte((const uintptr_t)src++);
- --len;
- }
- uint16_t value;
- bool aligned = ((uintptr_t)dest % 2 == 0);
- while (len > 1) {
- value = EEPROM_ReadDataWord((const uintptr_t)((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_ReadDataByte((const uintptr_t)src);
- }
- }
- 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;
-
- if (len && (uintptr_t)dest % 2) {
-
- EEPROM_WriteDataByte((uintptr_t)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_WriteDataWord((uintptr_t)((uint16_t *)dest), value);
- dest += 2;
- src += 2;
- len -= 2;
- }
- if (len) {
- EEPROM_WriteDataByte((uintptr_t)dest, *src);
- }
- }
|