From a9c7e31d1701e76ae15464bebe66089710f3cd24 Mon Sep 17 00:00:00 2001 From: francisco Date: Wed, 12 Jun 2019 16:22:24 +0200 Subject: [PATCH 01/12] stm32f4/cpu_conf: add stm32f4 flashpage and flashsector config -stm32f4 doesn't have pages but sectors, flashpage is used as a wrapper around sectors --- cpu/stm32f4/include/cpu_conf.h | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/cpu/stm32f4/include/cpu_conf.h b/cpu/stm32f4/include/cpu_conf.h index 10918d47f2ed..96ef32044fcb 100644 --- a/cpu/stm32f4/include/cpu_conf.h +++ b/cpu/stm32f4/include/cpu_conf.h @@ -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 From 1e304808b051a45bab684514ee1e81c4f4612b36 Mon Sep 17 00:00:00 2001 From: francisco Date: Wed, 12 Jun 2019 16:38:24 +0200 Subject: [PATCH 02/12] cpu/stm32f4: add flashpage and flashpage_raw --- cpu/stm32_common/periph/flash_common.c | 2 +- cpu/stm32_common/periph/flashpage.c | 110 +++++++++++++++++++++++-- cpu/stm32f4/Makefile.features | 2 + 3 files changed, 108 insertions(+), 6 deletions(-) diff --git a/cpu/stm32_common/periph/flash_common.c b/cpu/stm32_common/periph/flash_common.c index eeeb3b27fc39..f7a6e4a769da 100644 --- a/cpu/stm32_common/periph/flash_common.c +++ b/cpu/stm32_common/periph/flash_common.c @@ -32,7 +32,7 @@ #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_STM32F4) #define FLASH_KEY1 ((uint32_t)0x45670123) #define FLASH_KEY2 ((uint32_t)0xCDEF89AB) #endif diff --git a/cpu/stm32_common/periph/flashpage.c b/cpu/stm32_common/periph/flashpage.c index e95fc9ec0b15..ba9919fb07ff 100644 --- a/cpu/stm32_common/periph/flashpage.c +++ b/cpu/stm32_common/periph/flashpage.c @@ -42,6 +42,9 @@ #else #if defined(CPU_FAM_STM32L4) #define FLASHPAGE_DIV (8U) +#elif defined(CPU_FAM_STM32F4) +#define FLASHSECTORS_BANK (12) +#define FLASHPAGE_DIV (4U) #else #define FLASHPAGE_DIV (2U) #endif @@ -69,6 +72,92 @@ static void _unlock_flash(void) #endif } +#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) +static inline int flashbank_sector(void *addr) { + 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) { +#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); + /* 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) { + uint8_t sn = flashsector_sector(page_addr); + DEBUG("[flashsector] erase: erasing sector: %d\n", sn); + _erase_sector(sn); + } +} +#endif + +#if !(defined(CPU_FAM_STM32F4)) static void _erase_page(void *page_addr) { #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \ @@ -140,6 +229,7 @@ static void _erase_page(void *page_addr) } #endif } +#endif void flashpage_write_raw(void *target_addr, const void *data, size_t len) { @@ -155,7 +245,8 @@ 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_STM32L0) || defined(CPU_FAM_STM32L1) || \ + defined(CPU_FAM_STM32F4) uint32_t *dst = target_addr; const uint32_t *data_addr = data; #elif defined(CPU_FAM_STM32L4) @@ -179,6 +270,12 @@ 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_STM32F4) + /* 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) @@ -191,7 +288,6 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) /* 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) @@ -199,11 +295,12 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) #endif DEBUG("[flashpage_raw] write: done writing data\n"); + /* lock the flash module again */ _lock(); -#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \ - defined(CPU_FAM_STM32F3) +#if !(defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \ + defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F4)) /* restore the HSI state */ if (!hsi_state) { stmclk_disable_hsi(); @@ -225,9 +322,12 @@ void flashpage_write(int page, const void *data) uint16_t *page_addr = flashpage_addr(page); #endif +#if !(defined(CPU_FAM_STM32F4)) /* ERASE sequence */ _erase_page(page_addr); - +#else + _erase_sector_page(page_addr); +#endif /* WRITE sequence */ if (data != NULL) { flashpage_write_raw(page_addr, data, FLASHPAGE_SIZE); diff --git a/cpu/stm32f4/Makefile.features b/cpu/stm32f4/Makefile.features index f6818fb224c7..9ddb155deff8 100644 --- a/cpu/stm32f4/Makefile.features +++ b/cpu/stm32f4/Makefile.features @@ -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 From b6a060b50c920ba4d2256155635186cc11a32b0f Mon Sep 17 00:00:00 2001 From: francisco Date: Wed, 12 Jun 2019 16:46:37 +0200 Subject: [PATCH 03/12] stm32f2/cpu_conf: add stm32f2 flashpage and flashsector config -stm32f2 doesn't have pages but sectors, flashpage is used as a wrapper around sectors --- cpu/stm32f2/include/cpu_conf.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/cpu/stm32f2/include/cpu_conf.h b/cpu/stm32f2/include/cpu_conf.h index 745d9f8f04bd..d35a7ff59b2f 100644 --- a/cpu/stm32f2/include/cpu_conf.h +++ b/cpu/stm32f2/include/cpu_conf.h @@ -38,6 +38,36 @@ 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 + */ +#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 From 0db59f879e5b9965816a4f1fa409b257577366d1 Mon Sep 17 00:00:00 2001 From: francisco Date: Wed, 12 Jun 2019 16:47:45 +0200 Subject: [PATCH 04/12] cpu/stm32f2: add flashpage and flashpage_raw --- cpu/stm32_common/periph/flash_common.c | 3 ++- cpu/stm32_common/periph/flashpage.c | 13 +++++++------ cpu/stm32f2/Makefile.features | 2 ++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cpu/stm32_common/periph/flash_common.c b/cpu/stm32_common/periph/flash_common.c index f7a6e4a769da..31d7f55c7cf7 100644 --- a/cpu/stm32_common/periph/flash_common.c +++ b/cpu/stm32_common/periph/flash_common.c @@ -32,7 +32,8 @@ #define CNTRL_REG_LOCK (FLASH_PECR_PELOCK) #define KEY_REG (FLASH->PEKEYR) #else -#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F4) +#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F2) || \ + defined(CPU_FAM_STM32F4) #define FLASH_KEY1 ((uint32_t)0x45670123) #define FLASH_KEY2 ((uint32_t)0xCDEF89AB) #endif diff --git a/cpu/stm32_common/periph/flashpage.c b/cpu/stm32_common/periph/flashpage.c index ba9919fb07ff..5d50a3d64709 100644 --- a/cpu/stm32_common/periph/flashpage.c +++ b/cpu/stm32_common/periph/flashpage.c @@ -42,7 +42,7 @@ #else #if defined(CPU_FAM_STM32L4) #define FLASHPAGE_DIV (8U) -#elif defined(CPU_FAM_STM32F4) +#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) #define FLASHSECTORS_BANK (12) #define FLASHPAGE_DIV (4U) #else @@ -157,7 +157,7 @@ static void _erase_sector_page(void *page_addr) } #endif -#if !(defined(CPU_FAM_STM32F4)) +#if !(defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4)) static void _erase_page(void *page_addr) { #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \ @@ -246,7 +246,7 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) (CPU_FLASH_BASE + (FLASHPAGE_SIZE * FLASHPAGE_NUMOF)) + 1); #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \ - defined(CPU_FAM_STM32F4) + defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) uint32_t *dst = target_addr; const uint32_t *data_addr = data; #elif defined(CPU_FAM_STM32L4) @@ -270,7 +270,7 @@ 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_STM32F4) +#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) /* set parallelism to 32bits */ CNTRL_REG &= FLASH_CR_PSIZE_Msk; CNTRL_REG |= (0x2 << FLASH_CR_PSIZE_Pos); @@ -300,7 +300,8 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) _lock(); #if !(defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \ - defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F4)) + defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F2) || \ + defined(CPU_FAM_STM32F4)) /* restore the HSI state */ if (!hsi_state) { stmclk_disable_hsi(); @@ -322,7 +323,7 @@ void flashpage_write(int page, const void *data) uint16_t *page_addr = flashpage_addr(page); #endif -#if !(defined(CPU_FAM_STM32F4)) +#if !(defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4)) /* ERASE sequence */ _erase_page(page_addr); #else diff --git a/cpu/stm32f2/Makefile.features b/cpu/stm32f2/Makefile.features index c51e0186eb8d..1549e4ac5def 100644 --- a/cpu/stm32f2/Makefile.features +++ b/cpu/stm32f2/Makefile.features @@ -1,3 +1,5 @@ FEATURES_PROVIDED += periph_hwrng +FEATURES_PROVIDED += periph_flashpage +FEATURES_PROVIDED += periph_flashpage_raw -include $(RIOTCPU)/stm32_common/Makefile.features From 7d6329b01575e370f76babda73c1c31de0b195b0 Mon Sep 17 00:00:00 2001 From: francisco Date: Tue, 18 Jun 2019 09:23:43 +0200 Subject: [PATCH 05/12] fixup! cpu/stm32f2: add flashpage and flashpage_raw --- cpu/stm32_common/periph/flashpage.c | 44 +++++++++++++++++++---------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/cpu/stm32_common/periph/flashpage.c b/cpu/stm32_common/periph/flashpage.c index 5d50a3d64709..7cb27703eb8a 100644 --- a/cpu/stm32_common/periph/flashpage.c +++ b/cpu/stm32_common/periph/flashpage.c @@ -73,22 +73,34 @@ static void _unlock_flash(void) } #if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) -static inline int flashbank_sector(void *addr) { - uint8_t sn = (uint8_t)(((uint32_t)addr - CPU_FLASH_BASE) / FLASHSECTOR_SIZE_MIN); - if(sn > 3 && sn < 8) { +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){ + else if (sn >= 8) { sn = (sn / 8) + 4; } return sn; } -static inline int flashsector_sector(void *addr) { -#if(FLASH_DUAL_BANK == 1) - if((uint32_t) addr >= (STM32_FLASHSIZE / 2) + CPU_FLASH_BASE) { +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)); + addr = (void *)((uint32_t)addr - (STM32_FLASHSIZE / 2)); return FLASHSECTORS_BANK + flashbank_sector(addr); } else { @@ -117,7 +129,7 @@ static void _erase_sector(uint8_t sn) DEBUG("[flashsector] erase: setting the sector erase code\n"); CNTRL_REG |= ((sn % FLASHSECTORS_BANK) << FLASH_CR_SNB_Pos); -#if( FLASH_DUAL_BANK == 1) +#if (FLASH_DUAL_BANK == 1) CNTRL_REG |= (sn / FLASHSECTORS_BANK) * FLASH_CR_SNB_4; #endif DEBUG("[flashsector] erase: setting the erase bit\n"); @@ -143,7 +155,7 @@ static void _erase_sector_page(void *page_addr) /* 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) { + if (*(uint32_t *)(page_addr + i) != 0xffffffff) { blank = false; break; } @@ -157,7 +169,9 @@ static void _erase_sector_page(void *page_addr) } #endif -#if !(defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4)) +#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) || \ @@ -288,6 +302,7 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) /* 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) @@ -295,7 +310,6 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) #endif DEBUG("[flashpage_raw] write: done writing data\n"); - /* lock the flash module again */ _lock(); @@ -323,11 +337,11 @@ void flashpage_write(int page, const void *data) uint16_t *page_addr = flashpage_addr(page); #endif -#if !(defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4)) /* ERASE sequence */ - _erase_page(page_addr); -#else +#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) _erase_sector_page(page_addr); +#else + _erase_page(page_addr); #endif /* WRITE sequence */ if (data != NULL) { From c4f1dc58682b42507b9abcdb7b07f3ad8c8b1e25 Mon Sep 17 00:00:00 2001 From: francisco Date: Mon, 8 Jul 2019 15:32:11 +0200 Subject: [PATCH 06/12] stm32f2/4: always erase when at sector start --- cpu/stm32_common/periph/flashpage.c | 36 +++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/cpu/stm32_common/periph/flashpage.c b/cpu/stm32_common/periph/flashpage.c index 7cb27703eb8a..a099db856cdb 100644 --- a/cpu/stm32_common/periph/flashpage.c +++ b/cpu/stm32_common/periph/flashpage.c @@ -56,6 +56,7 @@ extern void _lock(void); extern void _unlock(void); extern void _wait_for_pending_operations(void); + static void _unlock_flash(void) { _unlock(); @@ -73,7 +74,23 @@ static void _unlock_flash(void) } #if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) -static inline int flashbank_sector(void *addr) +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 += CPU_FLASH_BASE(FLASHSECTOR_SIZE_MIN * sn); + } + else { + addr += CPU_FLASH_BASE(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 @@ -93,7 +110,7 @@ static inline int flashbank_sector(void *addr) return sn; } -static inline int flashsector_sector(void *addr) +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 */ @@ -101,14 +118,14 @@ static inline int flashsector_sector(void *addr) 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); + return FLASHSECTORS_BANK + _flashbank_sector(addr); } else { DEBUG("[flashsector]: single bank sector \n"); - return flashbank_sector(addr); + return _flashbank_sector(addr); } #else - return flashbank_sector(addr); + return _flashbank_sector(addr); #endif } @@ -152,7 +169,13 @@ static void _erase_sector(uint8_t sn) static void _erase_sector_page(void *page_addr) { DEBUG("[flashsector] erase: address to erase: %p\n", page_addr); - /* avoid erasing whole sector if "page" is blank*/ + 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); + } + /* 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) { @@ -162,7 +185,6 @@ static void _erase_sector_page(void *page_addr) } /* erase the sector if it failed the blank check */ if (!blank) { - uint8_t sn = flashsector_sector(page_addr); DEBUG("[flashsector] erase: erasing sector: %d\n", sn); _erase_sector(sn); } From e210d1e6559a39a003ff3aa44644ffd9b726671a Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Wed, 17 Jul 2019 12:05:11 +0200 Subject: [PATCH 07/12] stm32f7/cpu_conf: add stm32f7 flashpage and flashsector config -stm32f7 doesn't have pages but sectors, flashpage is used as as wrapper around sectors --- cpu/stm32f7/include/cpu_conf.h | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/cpu/stm32f7/include/cpu_conf.h b/cpu/stm32f7/include/cpu_conf.h index 27c456e67900..bc52243b87c2 100644 --- a/cpu/stm32f7/include/cpu_conf.h +++ b/cpu/stm32f7/include/cpu_conf.h @@ -43,8 +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_STM32F746xx) || defined(CPU_LINE_STM32F722xx) +#define FLASHSECTOR_SIZE_MIN (16*1024U) +#elif defined(CPU_LINE_STM32F767xx) || defined(CPU_LINE_STM32F769xx) +#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 + */ +#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 From 3617fdb5dc39b1fc9ab36a6c74da175c79bb3639 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Wed, 17 Jul 2019 12:10:15 +0200 Subject: [PATCH 08/12] fixup! stm32f2/4: always erase when at sector start --- cpu/stm32_common/periph/flashpage.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpu/stm32_common/periph/flashpage.c b/cpu/stm32_common/periph/flashpage.c index a099db856cdb..93b8ec76d5a1 100644 --- a/cpu/stm32_common/periph/flashpage.c +++ b/cpu/stm32_common/periph/flashpage.c @@ -82,10 +82,10 @@ static inline void * _flashsector_addr(uint8_t sn) uint32_t addr = CPU_FLASH_BASE; #endif if (sn <= 4) { - addr += CPU_FLASH_BASE(FLASHSECTOR_SIZE_MIN * sn); + addr += (FLASHSECTOR_SIZE_MIN * sn); } else { - addr += CPU_FLASH_BASE(FLASHSECTOR_SIZE_MIN * (sn - 4)); + addr += (FLASHSECTOR_SIZE_MIN * (sn - 4)); } return (void *) addr; } @@ -174,6 +174,7 @@ static void _erase_sector_page(void *page_addr) 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; From 7bf18345250ae200f53de9f4c53ef23877026f89 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Wed, 17 Jul 2019 12:11:53 +0200 Subject: [PATCH 09/12] fixup! cpu/stm32f4: add flashpage and flashpage_raw --- cpu/stm32_common/periph/flashpage.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpu/stm32_common/periph/flashpage.c b/cpu/stm32_common/periph/flashpage.c index 93b8ec76d5a1..25b74f24b90d 100644 --- a/cpu/stm32_common/periph/flashpage.c +++ b/cpu/stm32_common/periph/flashpage.c @@ -336,9 +336,8 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) /* lock the flash module again */ _lock(); -#if !(defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \ - defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F2) || \ - defined(CPU_FAM_STM32F4)) +#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \ + defined(CPU_FAM_STM32F3) /* restore the HSI state */ if (!hsi_state) { stmclk_disable_hsi(); From 9dda92f3fc87e2de9fc8d0fb128dac2e8cf6a512 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Wed, 17 Jul 2019 12:13:33 +0200 Subject: [PATCH 10/12] cpu/stm32f7: add flashpage and flashpage_raw --- cpu/stm32_common/periph/flash_common.c | 2 +- cpu/stm32_common/periph/flashpage.c | 28 ++++++++++++++++++-------- cpu/stm32f7/Makefile.features | 3 +++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/cpu/stm32_common/periph/flash_common.c b/cpu/stm32_common/periph/flash_common.c index 31d7f55c7cf7..94af61eb7207 100644 --- a/cpu/stm32_common/periph/flash_common.c +++ b/cpu/stm32_common/periph/flash_common.c @@ -33,7 +33,7 @@ #define KEY_REG (FLASH->PEKEYR) #else #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F2) || \ - defined(CPU_FAM_STM32F4) + defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) #define FLASH_KEY1 ((uint32_t)0x45670123) #define FLASH_KEY2 ((uint32_t)0xCDEF89AB) #endif diff --git a/cpu/stm32_common/periph/flashpage.c b/cpu/stm32_common/periph/flashpage.c index 25b74f24b90d..611809879319 100644 --- a/cpu/stm32_common/periph/flashpage.c +++ b/cpu/stm32_common/periph/flashpage.c @@ -42,7 +42,8 @@ #else #if defined(CPU_FAM_STM32L4) #define FLASHPAGE_DIV (8U) -#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) +#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ + defined(CPU_FAM_STM32F7) #define FLASHSECTORS_BANK (12) #define FLASHPAGE_DIV (4U) #else @@ -73,7 +74,8 @@ static void _unlock_flash(void) #endif } -#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) +#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) @@ -282,8 +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) || \ - defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) +#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) @@ -307,7 +310,8 @@ 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) +#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); @@ -315,20 +319,27 @@ void flashpage_write_raw(void *target_addr, const void *data, size_t len) 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"); @@ -360,7 +371,8 @@ void flashpage_write(int page, const void *data) #endif /* ERASE sequence */ -#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) +#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ + defined(CPU_FAM_STM32F7) _erase_sector_page(page_addr); #else _erase_page(page_addr); diff --git a/cpu/stm32f7/Makefile.features b/cpu/stm32f7/Makefile.features index 2d4e44ccb55c..1549e4ac5def 100644 --- a/cpu/stm32f7/Makefile.features +++ b/cpu/stm32f7/Makefile.features @@ -1,2 +1,5 @@ FEATURES_PROVIDED += periph_hwrng +FEATURES_PROVIDED += periph_flashpage +FEATURES_PROVIDED += periph_flashpage_raw + -include $(RIOTCPU)/stm32_common/Makefile.features From caba796d07507003dff5bb9c4fc79fe069077e3c Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Wed, 24 Jul 2019 10:30:00 +0200 Subject: [PATCH 11/12] fixup! stm32f7/cpu_conf: add stm32f7 flashpage and flashsector config --- cpu/stm32f7/include/cpu_conf.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cpu/stm32f7/include/cpu_conf.h b/cpu/stm32f7/include/cpu_conf.h index bc52243b87c2..dfffcb2397bb 100644 --- a/cpu/stm32f7/include/cpu_conf.h +++ b/cpu/stm32f7/include/cpu_conf.h @@ -52,9 +52,10 @@ extern "C" { * @{ */ #define FLASH_DUAL_BANK (0) -#if defined(CPU_LINE_STM32F746xx) || defined(CPU_LINE_STM32F722xx) +#if defined(CPU_LINE_STM32F722xx) #define FLASHSECTOR_SIZE_MIN (16*1024U) -#elif defined(CPU_LINE_STM32F767xx) || defined(CPU_LINE_STM32F769xx) +#elif defined(CPU_LINE_STM32F767xx) || defined(CPU_LINE_STM32F769xx) || \ + defined(CPU_LINE_STM32F746xx) #define FLASHSECTOR_SIZE_MIN (32*1024UL) #endif @@ -69,6 +70,8 @@ extern "C" { /* 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 @@ -79,7 +82,6 @@ extern "C" { #define FLASHPAGE_RAW_ALIGNMENT (4U) /** @} */ - #ifdef __cplusplus } #endif From 4d0763503cad5e0fa60f4d4bacbbfd2d22090b53 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Wed, 24 Jul 2019 10:44:39 +0200 Subject: [PATCH 12/12] fixup! stm32f2/cpu_conf: add stm32f2 flashpage and flashsector config --- cpu/stm32f2/include/cpu_conf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpu/stm32f2/include/cpu_conf.h b/cpu/stm32f2/include/cpu_conf.h index d35a7ff59b2f..6d26878ce554 100644 --- a/cpu/stm32f2/include/cpu_conf.h +++ b/cpu/stm32f2/include/cpu_conf.h @@ -58,6 +58,8 @@ extern "C" { /* 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