-
-
Notifications
You must be signed in to change notification settings - Fork 40.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
eeprom emulation for stm32f4 #7803
Changes from all commits
25641bd
9a05aa7
092831a
ad3fb66
e966b7e
f546bd3
db9e78a
c2c5d09
a9aa75e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ | |
* Artur F. | ||
* | ||
* Modifications for QMK and STM32F303 by Yiancar | ||
* update for STM32F4 support and the the flashing algorithm by yulei | ||
*/ | ||
|
||
#include <stdio.h> | ||
|
@@ -30,15 +31,24 @@ | |
/* Private variables ---------------------------------------------------------*/ | ||
/* Functions -----------------------------------------------------------------*/ | ||
|
||
uint8_t DataBuf[FEE_PAGE_SIZE]; | ||
#define IS_VALID_ADDRESS(x) ((x) < FEE_MAX_BYTES) | ||
|
||
uint8_t DataBuf[FEE_MAX_BYTES]; | ||
static void EEPROM_Backup(void); | ||
static FLASH_Status EEPROM_Restore(void); | ||
static uint32_t EEPROM_FindValidAddress(void); | ||
static void EEPROM_Clear(void); | ||
|
||
/***************************************************************************** | ||
* Delete Flash Space used for user Data, deletes the whole space between | ||
* RW_PAGE_BASE_ADDRESS and the last uC Flash Page | ||
* Unlock the FLASH programming and initialized the DataBuf | ||
******************************************************************************/ | ||
uint16_t EEPROM_Init(void) { | ||
// unlock flash | ||
FLASH_Unlock(); | ||
|
||
// initialize DataBuf | ||
EEPROM_Backup(); | ||
|
||
// Clear Flags | ||
// FLASH_ClearFlag(FLASH_SR_EOP|FLASH_SR_PGERR|FLASH_SR_WRPERR); | ||
|
||
|
@@ -48,72 +58,124 @@ uint16_t EEPROM_Init(void) { | |
* Erase the whole reserved Flash Space used for user Data | ||
******************************************************************************/ | ||
void EEPROM_Erase(void) { | ||
int page_num = 0; | ||
// erase all flash pages | ||
EEPROM_Clear(); | ||
|
||
// 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); | ||
// reset the content of the buffer | ||
memset(&DataBuf[0], FEE_EMPTY_BYTE, sizeof(DataBuf)); | ||
} | ||
|
||
/***************************************************************************** | ||
* 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. | ||
* Write data with its eeprom address to flash if there has empty words, | ||
* otherwise backup the current valid data, erase all flash pages, | ||
* and finally restore the valid data. | ||
*******************************************************************************/ | ||
uint16_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) { | ||
FLASH_Status FlashStatus = FLASH_COMPLETE; | ||
|
||
uint32_t page; | ||
int i; | ||
|
||
// exit if desired address is above the limit (e.G. under 2048 Bytes for 4 pages) | ||
if (Address > FEE_DENSITY_BYTES) { | ||
uint32_t addr; | ||
// exit if not a valid address | ||
if (!IS_VALID_ADDRESS(Address)) { | ||
return 0; | ||
} | ||
|
||
// calculate which page is affected (Pagenum1/Pagenum2...PagenumN) | ||
page = FEE_ADDR_OFFSET(Address) / FEE_PAGE_SIZE; | ||
// we are sure the address will not be out of bound | ||
#pragma GCC diagnostic ignored "-Warray-bounds" | ||
// same value, do not need program | ||
if (DataBuf[Address] == DataByte) { | ||
return FlashStatus; | ||
} | ||
|
||
// 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)); | ||
// find the address can be written | ||
addr = EEPROM_FindValidAddress(); | ||
DataBuf[Address] = DataByte; | ||
#pragma GCC diagnostic pop | ||
if (addr == FEE_EMPTY_VALUE) { | ||
// EEPROM is full, need to erase and reprogramming | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there's an issue here that when your eeprom is completely full, every single byte write will perform a full erase. I think it would be good to add some "slack" e.g. reserve twice the flash memory compared to emulated eeprom size (so times 8 instead of current times 4) |
||
EEPROM_Clear(); | ||
EEPROM_Restore(); | ||
} else { | ||
// 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 | ||
|
||
// 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; | ||
} | ||
|
||
// 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; | ||
|
||
// Erase Page | ||
FlashStatus = FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE)); | ||
|
||
// 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_ProgramHalfWord(FEE_ADDR_ADDRESS(addr), Address); | ||
FLASH_ProgramHalfWord(FEE_DATA_ADDRESS(addr), DataByte); | ||
} | ||
|
||
return FlashStatus; | ||
} | ||
/***************************************************************************** | ||
* Read once data byte from a specified address. | ||
*******************************************************************************/ | ||
uint8_t EEPROM_ReadDataByte(uint16_t Address) { | ||
uint8_t DataByte = 0xFF; | ||
if (!IS_VALID_ADDRESS(Address)) { | ||
return FEE_EMPTY_BYTE; | ||
} | ||
|
||
// Get Byte from specified address | ||
DataByte = (*(__IO uint8_t *)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address))); | ||
// Get Byte from caches | ||
return DataBuf[Address]; | ||
} | ||
|
||
return DataByte; | ||
/***************************************************************************** | ||
* helper functions | ||
*******************************************************************************/ | ||
// backup the current data | ||
void EEPROM_Backup(void) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggest renaming to |
||
{ | ||
uint32_t begin = FEE_PAGE_BASE_ADDRESS; | ||
uint32_t end = FEE_PAGE_END_ADDRESS; | ||
memset(&DataBuf[0], FEE_EMPTY_BYTE, sizeof(DataBuf)); | ||
while( begin < end) { | ||
uint16_t addr = *(__IO uint16_t*)(FEE_ADDR_ADDRESS(begin)); | ||
if (IS_VALID_ADDRESS(addr)) { | ||
DataBuf[addr] = *(__IO uint16_t*)(FEE_DATA_ADDRESS(begin)); | ||
} else if( addr == FEE_EMPTY_WORD) { | ||
uint16_t data = *(__IO uint16_t*)(FEE_DATA_ADDRESS(begin)); | ||
if (data == FEE_EMPTY_WORD) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this check is needed, you can bail right away |
||
// we reached the end of valid data | ||
break; | ||
} | ||
} | ||
begin += 4; | ||
} | ||
} | ||
// restore data from DataBuf | ||
FLASH_Status EEPROM_Restore(void) { | ||
uint32_t cur = FEE_PAGE_BASE_ADDRESS; | ||
for (uint8_t i = 0; i < FEE_MAX_BYTES; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should not be uint8_t as FEE_MAX_BYTES is 1024, it would loop forever and likely brick the board |
||
if (DataBuf[i] != FEE_EMPTY_BYTE) { | ||
FLASH_ProgramHalfWord(FEE_ADDR_ADDRESS(cur), i); | ||
FLASH_ProgramHalfWord(FEE_DATA_ADDRESS(cur), DataBuf[i]); | ||
cur += 4; | ||
} | ||
} | ||
return FLASH_COMPLETE; | ||
} | ||
// find an empty place for programming | ||
uint32_t EEPROM_FindValidAddress(void) { | ||
uint32_t begin = FEE_PAGE_BASE_ADDRESS; | ||
uint32_t end = FEE_PAGE_END_ADDRESS; | ||
while( begin < end) { | ||
uint32_t data = *(__IO uint32_t*)(begin); | ||
if (data == FEE_EMPTY_VALUE) { | ||
return begin; | ||
} | ||
begin += 4; | ||
} | ||
return FEE_EMPTY_VALUE; | ||
} | ||
|
||
void EEPROM_Clear(void) | ||
{ | ||
#if defined(EEPROM_EMU_STM32F411xE) | ||
FLASH_ErasePage(FEE_SECTOR_ID); | ||
#else | ||
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); | ||
#endif | ||
} | ||
/***************************************************************************** | ||
* Wrap library in AVR style functions. | ||
*******************************************************************************/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,17 +36,23 @@ | |
# define MCU_STM32F103RB | ||
#elif defined(EEPROM_EMU_STM32F072xB) | ||
# define MCU_STM32F072CB | ||
#elif defined(EEPROM_EMU_STM32F411xE) | ||
# define MCU_STM32F411xE | ||
#else | ||
# error "not implemented." | ||
#endif | ||
|
||
#ifndef EEPROM_PAGE_SIZE | ||
# if defined(MCU_STM32F103RB) | ||
# define FEE_PAGE_SIZE (uint16_t)0x400 // Page size = 1KByte | ||
# define FEE_DENSITY_PAGES 2 // How many pages are used | ||
# define FEE_DENSITY_PAGES 4 // atleast needs 4K Bytes to emulated 1024 eeprom on AVR | ||
# 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 | ||
# elif defined(MCU_STM32F411xE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some docs explaining why you had to add a new flash driver rather than re-use the existing one would also be helpful for review. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the explanation was added on the eeprom_stm32f4.c There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rather use the existing code if possible, and target an "improved" version across supported chips, instead of fragmenting implementations. We also have #7274 looking close to completion. If there is a hard requirement for another implementation, it would be nice to target the newer structure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. stm32F4 has different register bits for flash programming compared with stm32f1 and f3. It will introduce many hardware specific #define on the existing code. The new structure introduced by #7274 will not conflict the current EEPROM emulation implementation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am just putting it on record that:
|
||
# define FEE_PAGE_SIZE (uint32_t)0x20000 // Page size = 128KByte | ||
# define FEE_DENSITY_PAGES 1 // How many pages are used | ||
# define FEE_SECTOR_ID 7 // sector id of the flash | ||
# else | ||
# error "No MCU type specified. Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)." | ||
# endif | ||
|
@@ -61,18 +67,26 @@ | |
# define FEE_MCU_FLASH_SIZE 384 // Size in Kb | ||
# elif defined(MCU_STM32F303CC) | ||
# define FEE_MCU_FLASH_SIZE 256 // Size in Kb | ||
# elif defined(MCU_STM32F411xE) | ||
# define FEE_MCU_FLASH_SIZE 512 // 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_PAGE_END_ADDRESS ((uint32_t)(0x08000000 + FEE_MCU_FLASH_SIZE * 1024)) | ||
#define FEE_PAGE_BASE_ADDRESS ((uint32_t)((FEE_PAGE_END_ADDRESS) - FEE_DENSITY_PAGES * FEE_PAGE_SIZE)) | ||
#define FEE_DENSITY_BYTES ((FEE_PAGE_SIZE / 4) * FEE_DENSITY_PAGES - 1) // 4 Bytes for address, value pair | ||
//#define FEE_LAST_PAGE_ADDRESS (FEE_PAGE_BASE_ADDRESS + (FEE_PAGE_SIZE * FEE_DENSITY_PAGES)) | ||
#define FEE_EMPTY_BYTE ((uint8_t)0xFF) | ||
#define FEE_EMPTY_WORD ((uint16_t)0xFFFF) | ||
#define FEE_ADDR_OFFSET(Address) (Address * 2) // 1Byte per Word will be saved to preserve Flash | ||
#define FEE_EMPTY_VALUE ((uint32_t)0xFFFFFFFF) | ||
//#define FEE_ADDR_OFFSET(Address) (Address * 2) // 1 Byte per Word will be saved to preserve Flash | ||
#define FEE_DATA_ADDRESS(Address) ((Address)+2) // flash address of the eeprom data | ||
#define FEE_ADDR_ADDRESS(Address) (Address) // flash address of the eeprom address | ||
Comment on lines
+87
to
+88
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these two IMO don't make sense with the new algorithm and should be removed (previously, it contained a mapping from eeprom address to flash address, but currently such mapping is not required) |
||
#define FEE_MAX_BYTES ((FEE_DENSITY_BYTES+1) > 1024 ? 1024 : (FEE_DENSITY_BYTES+1)) // eeprom size | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is a bug, it should be #define FEE_MAX_BYTES ((FEE_DENSITY_BYTES+1) > 1024 ? (FEE_DENSITY_BYTES+1) : 1024) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Atmega32u4's eeprom size was 1024, so it was limited to keep the compatibility. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, so you do not want to use the full space? Supposedly there is no problem if you use a larger external EEPROM, so there is no reason to limit the max size to just 1024. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If VIA didn't exist, I would say that is just fine. But ... it does, so a higher max by default is absolutely beneficial. To the point that I think it's more important than compatibility. In fact, for the emulated eeprom for the F303, isn't it 4kb? |
||
|
||
// Use this function to initialize the functionality | ||
uint16_t EEPROM_Init(void); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest adding a cast to ensure unsigned
x
here