Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cpu/stm32_common/periph/flash_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
#define CNTRL_REG_LOCK (FLASH_PECR_PELOCK)
#define KEY_REG (FLASH->PEKEYR)
#else
#if defined(CPU_FAM_STM32L4)
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F2) || \
defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7)
#define FLASH_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)
#endif
Expand Down
157 changes: 153 additions & 4 deletions cpu/stm32_common/periph/flashpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
#else
#if defined(CPU_FAM_STM32L4)
#define FLASHPAGE_DIV (8U)
#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7)
#define FLASHSECTORS_BANK (12)
#define FLASHPAGE_DIV (4U)
#else
#define FLASHPAGE_DIV (2U)
#endif
Expand All @@ -53,6 +57,7 @@ extern void _lock(void);
extern void _unlock(void);
extern void _wait_for_pending_operations(void);


static void _unlock_flash(void)
{
_unlock();
Expand All @@ -69,6 +74,129 @@ static void _unlock_flash(void)
#endif
}

#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7)
static inline void * _flashsector_addr(uint8_t sn)
{
#if (FLASH_DUAL_BANK == 1)
uint32_t addr = CPU_FLASH_BASE + (STM32_FLASHSIZE / 2);
#else
uint32_t addr = CPU_FLASH_BASE;
#endif
if (sn <= 4) {
addr += (FLASHSECTOR_SIZE_MIN * sn);
}
else {
addr += (FLASHSECTOR_SIZE_MIN * (sn - 4));
}
return (void *) addr;
}

static inline int _flashbank_sector(void *addr)
{
/* When flash is in single bank there is a max of 12 sectors. The first 4
sectors are equally sized, the 5th amount to the sum of the first 4
sectors and the 6th to 12th amount to the sum of the first 5 sectos.
e.g.: if FLASHSECTOR_SIZE_MIN is 16k there are 4 sectors of 16kB,
1 of 64kB and 7 of 128kB. */
/* We use this pattern to find in what sector and address falls */
uint8_t sn =
(uint8_t)(((uint32_t)addr - CPU_FLASH_BASE) / FLASHSECTOR_SIZE_MIN);

if (sn > 3 && sn < 8) {
sn = 4;
}
else if (sn >= 8) {
sn = (sn / 8) + 4;
}
return sn;
}

static inline int _flashsector_sector(void *addr)
{
/* When in dual bank there can be up to 24 sectors, where sectors 12-23
follow the same layout as sectors 0-11 */
#if (FLASH_DUAL_BANK == 1)
if ((uint32_t)addr >= (STM32_FLASHSIZE / 2) + CPU_FLASH_BASE) {
DEBUG("[flashsector]: dual bank sector \n");
addr = (void *)((uint32_t)addr - (STM32_FLASHSIZE / 2));
return FLASHSECTORS_BANK + _flashbank_sector(addr);
}
else {
DEBUG("[flashsector]: single bank sector \n");
return _flashbank_sector(addr);
}
#else
return _flashbank_sector(addr);
#endif
}

static void _erase_sector(uint8_t sn)
{
/* make sure no flash operation is ongoing */
_wait_for_pending_operations();

/* unlock the flash module */
_unlock_flash();

/* set parallelism to 32bits */
CNTRL_REG &= FLASH_CR_PSIZE_Msk;
CNTRL_REG |= (0x2 << FLASH_CR_PSIZE_Pos);

/* make sure no flash operation is ongoing */
_wait_for_pending_operations();

DEBUG("[flashsector] erase: setting the sector erase code\n");
CNTRL_REG |= ((sn % FLASHSECTORS_BANK) << FLASH_CR_SNB_Pos);
#if (FLASH_DUAL_BANK == 1)
CNTRL_REG |= (sn / FLASHSECTORS_BANK) * FLASH_CR_SNB_4;
#endif
DEBUG("[flashsector] erase: setting the erase bit\n");
CNTRL_REG |= FLASH_CR_SER;

DEBUG("[flashsector] erase: trigger the page erase\n");
CNTRL_REG |= FLASH_CR_STRT;

/* wait as long as device is busy */
_wait_for_pending_operations();

/* reset PER bit */
DEBUG("[flashsector] erase: resetting the sector erase bit\n");
CNTRL_REG &= ~FLASH_CR_SER;

/* lock the flash module again */
_lock();
}

static void _erase_sector_page(void *page_addr)
{
DEBUG("[flashsector] erase: address to erase: %p\n", page_addr);
uint8_t sn = _flashsector_sector(page_addr);
/* always erase sector when writing to first page */
if(_flashsector_addr(sn) == page_addr) {
DEBUG("[flashsector] erase: erasing sector: %d\n", sn);
_erase_sector(sn);
return;
}
/* avoid erasing whole sector if "page" is blank */
bool blank = true;
for (unsigned i = 0; i < FLASHPAGE_SIZE; i += sizeof(uint32_t)) {
if (*(uint32_t *)(page_addr + i) != 0xffffffff) {
blank = false;
break;
}
}
/* erase the sector if it failed the blank check */
if (!blank) {
DEBUG("[flashsector] erase: erasing sector: %d\n", sn);
_erase_sector(sn);
}
}
#endif

#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \
defined(CPU_FAM_STM32L4)
static void _erase_page(void *page_addr)
{
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \
Expand Down Expand Up @@ -140,6 +268,7 @@ static void _erase_page(void *page_addr)
}
#endif
}
#endif

void flashpage_write_raw(void *target_addr, const void *data, size_t len)
{
Expand All @@ -155,7 +284,9 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len)
assert(((unsigned)target_addr + len) <
(CPU_FLASH_BASE + (FLASHPAGE_SIZE * FLASHPAGE_NUMOF)) + 1);

#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \
defined(CPU_FAM_STM32L1)
uint32_t *dst = target_addr;
const uint32_t *data_addr = data;
#elif defined(CPU_FAM_STM32L4)
Expand All @@ -179,22 +310,36 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len)
/* make sure no flash operation is ongoing */
_wait_for_pending_operations();

#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4)|| \
defined(CPU_FAM_STM32F7)
/* set parallelism to 32bits */
CNTRL_REG &= FLASH_CR_PSIZE_Msk;
CNTRL_REG |= (0x2 << FLASH_CR_PSIZE_Pos);
#endif

DEBUG("[flashpage_raw] write: now writing the data\n");
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4)
defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F3) || \
defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) || \
defined(CPU_FAM_STM32L4)
/* set PG bit and program page to flash */
CNTRL_REG |= FLASH_CR_PG;
#endif
for (size_t i = 0; i < (len / FLASHPAGE_DIV); i++) {
DEBUG("[flashpage_raw] writing %c to %p\n", (char)data_addr[i], dst);
*dst++ = data_addr[i];
#if defined(CPU_FAM_STM32F7)
__DSB();
#endif
/* wait as long as device is busy */
_wait_for_pending_operations();
}

/* clear program bit again */
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4)
defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F3) || \
defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) || \
defined(CPU_FAM_STM32L4)
CNTRL_REG &= ~(FLASH_CR_PG);
#endif
DEBUG("[flashpage_raw] write: done writing data\n");
Expand Down Expand Up @@ -226,8 +371,12 @@ void flashpage_write(int page, const void *data)
#endif

/* ERASE sequence */
#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7)
_erase_sector_page(page_addr);
#else
_erase_page(page_addr);

#endif
/* WRITE sequence */
if (data != NULL) {
flashpage_write_raw(page_addr, data, FLASHPAGE_SIZE);
Expand Down
2 changes: 2 additions & 0 deletions cpu/stm32f2/Makefile.features
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_raw

-include $(RIOTCPU)/stm32_common/Makefile.features
32 changes: 32 additions & 0 deletions cpu/stm32f2/include/cpu_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,38 @@ extern "C" {
#define CPU_FLASH_BASE FLASH_BASE
/** @} */

/**
* @brief Flash sector configuration
*
* @{
*/
#define FLASH_DUAL_BANK (0)
#define FLASHSECTOR_SIZE_MIN (16*1024U)
/** @} */

/**
* @brief Flash page configuration
*
* NOTE: STM32F2 flash is organized in sectors, FLASHPAGE_* is
* defined as a wrapper over sectors.
*
* @{
*/
/* To keep the same flashpage functionality an arbitrary 1K < FLASHSECTOR_SIZE_MIN
* (size of smaller sector) is defined
*/
/* An erase byte in flash is set to 0xff */
#define FLASH_ERASE_STATE (0xff)
#define FLASHPAGE_SIZE (1024U)
#define FLASHPAGE_NUMOF (STM32_FLASHSIZE / FLASHPAGE_SIZE)
/* The minimum block size which can be written is 4B. However, the erase
* depends on the specific sector.
*/
#define FLASHPAGE_RAW_BLOCKSIZE (4U)
/* Writing should be always 4 bytes aligned */
#define FLASHPAGE_RAW_ALIGNMENT (4U)
/** @} */

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 2 additions & 0 deletions cpu/stm32f4/Makefile.features
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_raw

# the granularity of provided feature definition for STMs is currently by CPU
# sub-family (e.g., stm32f[1234]). Unfortunately, only some of e.g., the
Expand Down
35 changes: 35 additions & 0 deletions cpu/stm32f4/include/cpu_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,41 @@ extern "C" {
#define CPU_FLASH_BASE FLASH_BASE
/** @} */

/**
* @brief Flash sector configuration
*
* @{
*/
#if (defined(CPU_LINE_STM32F429xx) || defined(CPU_LINE_STM32F437xx)) && \
(STM32_FLASHSIZE == (2048*1024))
#define FLASH_DUAL_BANK (1)
#else
#define FLASH_DUAL_BANK (0)
#endif
#define FLASHSECTOR_SIZE_MIN (16*1024U)
/** @} */

/**
* @brief Flash page configuration
*
* NOTE: STM32F4 flash is organized in sectors, FLASHPAGE_* is
* defined as a wrapper over sectors.
*
* @{
*/
/* To keep the same flashpage functionality an arbitrary 1K < FLASHSECTOR_SIZE_MIN
* (size of smaller sector) is defined
*/
#define FLASHPAGE_SIZE (1024)
#define FLASHPAGE_NUMOF (STM32_FLASHSIZE / FLASHPAGE_SIZE)
/* The minimum block size which can be written is 4B. However, the erase
* depends on the specific sector.
*/
#define FLASHPAGE_RAW_BLOCKSIZE (4U)
/* Writing should be always 4 bytes aligned */
#define FLASHPAGE_RAW_ALIGNMENT (4U)
/** @} */

#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 3 additions & 0 deletions cpu/stm32f7/Makefile.features
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_raw

-include $(RIOTCPU)/stm32_common/Makefile.features
37 changes: 37 additions & 0 deletions cpu/stm32f7/include/cpu_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,43 @@ extern "C" {
#elif defined(CPU_LINE_STM32F722xx)
#define CPU_IRQ_NUMOF (104U)
#endif
#define CPU_FLASH_BASE FLASH_BASE
/** @} */

/**
* @brief Flash sector configuration
*
* @{
*/
#define FLASH_DUAL_BANK (0)
#if defined(CPU_LINE_STM32F722xx)
#define FLASHSECTOR_SIZE_MIN (16*1024U)
#elif defined(CPU_LINE_STM32F767xx) || defined(CPU_LINE_STM32F769xx) || \
defined(CPU_LINE_STM32F746xx)
#define FLASHSECTOR_SIZE_MIN (32*1024UL)
#endif

/**
* @brief Flash page configuration
*
* NOTE: STM32F7 flash is organized in sectors, FLASHPAGE_* is
* defined as a wrapper over sectors.
*
* @{
*/
/* To keep the same flashpage functionality an arbitrary 1K < FLASHSECTOR_SIZE_MIN
* (size of smaller sector) is defined
*/
/* An erase byte in flash is set to 0xff */
#define FLASH_ERASE_STATE (0xff)
#define FLASHPAGE_SIZE (1024U)
#define FLASHPAGE_NUMOF (STM32_FLASHSIZE / FLASHPAGE_SIZE)
/* The minimum block size which can be written is 4B. However, the erase
* depends on the specific sector.
*/
#define FLASHPAGE_RAW_BLOCKSIZE (4U)
/* Writing should be always 4 bytes aligned */
#define FLASHPAGE_RAW_ALIGNMENT (4U)
/** @} */

#ifdef __cplusplus
Expand Down