Skip to content

Commit

Permalink
Enables the master branch to also use the EEPROM of Stm32F4
Browse files Browse the repository at this point in the history
  • Loading branch information
jiaxin96 committed Jun 14, 2021
1 parent ed2ccb4 commit c4ce4eb
Show file tree
Hide file tree
Showing 17 changed files with 1,671 additions and 32 deletions.
217 changes: 217 additions & 0 deletions keyboards/yandrstudio/tdcq64_2s/f401/eep/eeprom_stm32.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
* 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.
*
* This files are free to use from http:https://engsta.com/stm32-flash-memory-eeprom-emulator/ by
* Artur F.
*
* Modifications for QMK and STM32F303 by Yiancar
* update for STM32F4 support and the the flashing algorithm by yulei
* Adjust the file structure to custom EEPROM_DRIVER by jiaxin96 for support stm32f401cc
*/

#include <stdio.h>
#include <string.h>
#include "eeprom_stm32_custom.h"
#include "eeprom_driver.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.
******************************************************************************/

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Functions -----------------------------------------------------------------*/

#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);

/*****************************************************************************
* 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);

return FEE_DENSITY_BYTES;
}
void eeprom_driver_init(void) {
EEPROM_Init();
}

/*****************************************************************************
* Erase the whole reserved Flash Space used for user Data
******************************************************************************/
void EEPROM_Erase(void) {
// erase all flash pages
EEPROM_Clear();

// reset the content of the buffer
memset(&DataBuf[0], FEE_EMPTY_BYTE, sizeof(DataBuf));
}
void eeprom_driver_erase(void) {
EEPROM_Erase();
}
/*****************************************************************************
* 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 addr;
// exit if not a valid address
if (!IS_VALID_ADDRESS(Address)) {
return 0;
}

// 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;
}

// 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
EEPROM_Clear();
EEPROM_Restore();
} else {
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) {
if (!IS_VALID_ADDRESS(Address)) {
return FEE_EMPTY_BYTE;
}

// Get Byte from caches
return DataBuf[Address];
}

/*****************************************************************************
* helper functions
*******************************************************************************/
// backup the current data
void EEPROM_Backup(void)
{
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) {
// 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++) {
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_STM32F401xC)
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.
*******************************************************************************/
uint8_t eeprom_read_byte_f4(const uint8_t *Address) {
const uint16_t p = (const uint32_t)Address;
return EEPROM_ReadDataByte(p);
}

void eeprom_write_byte_f4(uint8_t *Address, uint8_t Value) {
uint16_t p = (uint32_t)Address;
EEPROM_WriteDataByte(p, Value);
}


void eeprom_read_block(void *buf, const void *addr, size_t len) {
const uint8_t *p = (const uint8_t *)addr;
uint8_t * dest = (uint8_t *)buf;
while (len--) {
*dest++ = eeprom_read_byte_f4(p++);
}
}

void eeprom_write_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_f4(p++, *src++);
}
}


104 changes: 104 additions & 0 deletions keyboards/yandrstudio/tdcq64_2s/f401/eep/eeprom_stm32_custom.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* 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.
*
* This files are free to use from http:https://engsta.com/stm32-flash-memory-eeprom-emulator/ by
* Artur F.
*
* Modifications for QMK and STM32F303 by Yiancar
*
* This library assumes 8-bit data locations. To add a new MCU, please provide the flash
* page size and the total flash size in Kb. The number of available pages must be a multiple
* of 2. Only half of the pages account for the total EEPROM size.
* This library also assumes that the pages are not used by the firmware.
* Adjust the file structure to custom EEPROM_DRIVER by jiaxin96 for support stm32f401cc
*/

#pragma once

#include <ch.h>
#include <hal.h>
#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
#elif defined(EEPROM_EMU_STM32F401xC)
# define MCU_STM32F401xC
#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 4 // 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
# elif defined(MCU_STM32F401xC)
# define FEE_PAGE_SIZE (uint32_t)0x20000 // Page size = 128KByte
# define FEE_DENSITY_PAGES 1 // How many pages are used
# define FEE_SECTOR_ID 5 // 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
#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
# elif defined(MCU_STM32F401xC)
# 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

#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_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
#define FEE_MAX_BYTES ((FEE_DENSITY_BYTES+1) > 1024 ? 1024 : (FEE_DENSITY_BYTES+1)) // eeprom size

Loading

0 comments on commit c4ce4eb

Please sign in to comment.