2018-08-29 22:14:49 +02:00
|
|
|
/*
|
|
|
|
* This software is experimental and a work in progress.
|
|
|
|
* Under no circumstances should these files be used in relation to any critical system(s).
|
|
|
|
* Use of these files is at your own risk.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
|
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
*
|
2019-01-07 02:22:19 +01:00
|
|
|
* This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by
|
|
|
|
* Artur F.
|
2018-08-29 22:14:49 +02:00
|
|
|
*
|
|
|
|
* Modifications for QMK and STM32F303 by Yiancar
|
|
|
|
*/
|
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2018-08-29 22:14:49 +02:00
|
|
|
#include "eeprom_stm32.h"
|
2019-01-07 02:22:19 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* 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.
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
// unlock flash
|
|
|
|
FLASH_Unlock();
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// Clear Flags
|
|
|
|
//FLASH_ClearFlag(FLASH_SR_EOP|FLASH_SR_PGERR|FLASH_SR_WRPERR);
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
return FEE_DENSITY_BYTES;
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
2019-01-07 02:22:19 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* Erase the whole reserved Flash Space used for user Data
|
|
|
|
******************************************************************************/
|
|
|
|
void EEPROM_Erase (void) {
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
int page_num = 0;
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// 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);
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
2019-01-07 02:22:19 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* 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) {
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
FLASH_Status FlashStatus = FLASH_COMPLETE;
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
uint32_t page;
|
|
|
|
int i;
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// exit if desired address is above the limit (e.G. under 2048 Bytes for 4 pages)
|
|
|
|
if (Address > FEE_DENSITY_BYTES) {
|
|
|
|
return 0;
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// calculate which page is affected (Pagenum1/Pagenum2...PagenumN)
|
|
|
|
page = (FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address)) & 0x00000FFF;
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
if (page % FEE_PAGE_SIZE) page = page + FEE_PAGE_SIZE;
|
|
|
|
page = (page / FEE_PAGE_SIZE) - 1;
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// 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) {
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
FlashStatus = FLASH_ProgramHalfWord(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address), (uint16_t)(0x00FF & DataByte));
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
2019-01-07 02:22:19 +01:00
|
|
|
else {
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// 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
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// 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;
|
|
|
|
}
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// manipulate desired data byte in temp data array if new byte is differ to the current
|
|
|
|
DataBuf[FEE_ADDR_OFFSET(Address)] = DataByte;
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
//Erase Page
|
|
|
|
FlashStatus = FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + page);
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// Write new data (whole page) to flash if data has beed 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)]));
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2019-01-07 02:22:19 +01:00
|
|
|
return FlashStatus;
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
2019-01-07 02:22:19 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* Read once data byte from a specified address.
|
|
|
|
*******************************************************************************/
|
|
|
|
uint8_t EEPROM_ReadDataByte (uint16_t Address) {
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
uint8_t DataByte = 0xFF;
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
// Get Byte from specified address
|
|
|
|
DataByte = (*(__IO uint8_t*)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address)));
|
2018-08-29 22:14:49 +02:00
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
return DataByte;
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
2019-01-07 02:22:19 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* Wrap library in AVR style functions.
|
|
|
|
*******************************************************************************/
|
2018-08-29 22:14:49 +02:00
|
|
|
uint8_t eeprom_read_byte (const uint8_t *Address)
|
|
|
|
{
|
|
|
|
const uint16_t p = (const uint32_t) Address;
|
2019-01-07 02:22:19 +01:00
|
|
|
return EEPROM_ReadDataByte(p);
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void eeprom_write_byte (uint8_t *Address, uint8_t Value)
|
|
|
|
{
|
|
|
|
uint16_t p = (uint32_t) Address;
|
2019-01-07 02:22:19 +01:00
|
|
|
EEPROM_WriteDataByte(p, Value);
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void eeprom_update_byte (uint8_t *Address, uint8_t Value)
|
|
|
|
{
|
|
|
|
uint16_t p = (uint32_t) Address;
|
2019-01-07 02:22:19 +01:00
|
|
|
EEPROM_WriteDataByte(p, Value);
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t eeprom_read_word (const uint16_t *Address)
|
|
|
|
{
|
|
|
|
const uint16_t p = (const uint32_t) Address;
|
2019-01-07 02:22:19 +01:00
|
|
|
return EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p+1) << 8);
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void eeprom_write_word (uint16_t *Address, uint16_t Value)
|
|
|
|
{
|
|
|
|
uint16_t p = (uint32_t) Address;
|
2019-01-07 02:22:19 +01:00
|
|
|
EEPROM_WriteDataByte(p, (uint8_t) Value);
|
|
|
|
EEPROM_WriteDataByte(p + 1, (uint8_t) (Value >> 8));
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void eeprom_update_word (uint16_t *Address, uint16_t Value)
|
|
|
|
{
|
|
|
|
uint16_t p = (uint32_t) Address;
|
2019-01-07 02:22:19 +01:00
|
|
|
EEPROM_WriteDataByte(p, (uint8_t) Value);
|
|
|
|
EEPROM_WriteDataByte(p + 1, (uint8_t) (Value >> 8));
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t eeprom_read_dword (const uint32_t *Address)
|
|
|
|
{
|
|
|
|
const uint16_t p = (const uint32_t) Address;
|
2019-01-07 02:22:19 +01:00
|
|
|
return EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p+1) << 8)
|
|
|
|
| (EEPROM_ReadDataByte(p+2) << 16) | (EEPROM_ReadDataByte(p+3) << 24);
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void eeprom_write_dword (uint32_t *Address, uint32_t Value)
|
|
|
|
{
|
2019-01-07 02:22:19 +01:00
|
|
|
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));
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void eeprom_update_dword (uint32_t *Address, uint32_t Value)
|
|
|
|
{
|
2019-01-07 02:22:19 +01:00
|
|
|
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_read_block(void *buf, const void *addr, uint32_t len) {
|
|
|
|
const uint8_t *p = (const uint8_t *)addr;
|
|
|
|
uint8_t *dest = (uint8_t *)buf;
|
|
|
|
while (len--) {
|
|
|
|
*dest++ = eeprom_read_byte(p++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
|
|
|
|
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, uint32_t len) {
|
|
|
|
uint8_t *p = (uint8_t *)addr;
|
|
|
|
const uint8_t *src = (const uint8_t *)buf;
|
|
|
|
while (len--) {
|
|
|
|
eeprom_write_byte(p++, *src++);
|
|
|
|
}
|
2018-08-29 22:14:49 +02:00
|
|
|
}
|