From 67190a31efc84155fa03acac0a0d3786496bacd5 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 11 Mar 2018 20:33:36 +0100 Subject: [PATCH 1/5] cpu/stm32_common: unify flashpage support --- cpu/stm32_common/periph/flashpage.c | 187 ++++++++++++++++++++++------ 1 file changed, 150 insertions(+), 37 deletions(-) diff --git a/cpu/stm32_common/periph/flashpage.c b/cpu/stm32_common/periph/flashpage.c index 35ae45ff464c..111fd91d348f 100644 --- a/cpu/stm32_common/periph/flashpage.c +++ b/cpu/stm32_common/periph/flashpage.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2016 Freie Universität Berlin + * 2018 Inria * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -15,11 +16,14 @@ * @brief Low-level flash page driver implementation * * @author Hauke Petersen + * @author Francisco Acosta + * @author Alexandre Abadie * * @} */ #include "cpu.h" +#include "stmclk.h" #include "assert.h" #define ENABLE_DEBUG (0) @@ -27,64 +31,173 @@ #include "periph/flashpage.h" -void flashpage_write(int page, void *data) +#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) +/* Data EEPROM and control register unlock keys */ +#define FLASH_KEY1 ((uint32_t)0x89ABCDEF) +#define FLASH_KEY2 ((uint32_t)0x02030405) +/* Program memory unlock keys */ +#define FLASH_PRGKEY1 ((uint32_t)0x8C9DAEBF) +#define FLASH_PRGKEY2 ((uint32_t)0x13141516) +#define CNTRL_REG (FLASH->PECR) +#define CNTRL_REG_LOCK (FLASH_PECR_PELOCK) +#define KEY_REG (FLASH->PEKEYR) +#define FLASH_CR_PER (FLASH_PECR_ERASE | FLASH_PECR_PROG) +#define FLASH_CR_PG (FLASH_PECR_FPRG | FLASH_PECR_PROG) +#define FLASHPAGE_DIV (4U) /* write 4 bytes in one go */ +#else +#define CNTRL_REG (FLASH->CR) +#define CNTRL_REG_LOCK (FLASH_CR_LOCK) +#define KEY_REG (FLASH->KEYR) +#define FLASHPAGE_DIV (2U) +#endif + +static void _unlock(void) { - assert(page < (int)FLASHPAGE_NUMOF); + DEBUG("[flashpage] unlocking the flash module\n"); + if (CNTRL_REG & CNTRL_REG_LOCK) { + KEY_REG = FLASH_KEY1; + KEY_REG = FLASH_KEY2; + } - uint16_t *page_addr = flashpage_addr(page); - uint16_t *data_addr = (uint16_t *)data; - uint32_t hsi_state = (RCC->CR & RCC_CR_HSION); +#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) + DEBUG("[flashpage] unlocking the flash program memory\n"); + if (!(CNTRL_REG & CNTRL_REG_LOCK)) { + if (CNTRL_REG & FLASH_PECR_PRGLOCK) { + DEBUG("[flashpage] setting the program memory unlock keys\n"); + FLASH->PRGKEYR = FLASH_PRGKEY1; + FLASH->PRGKEYR = FLASH_PRGKEY2; + } + } +#endif +} + +static void _lock(void) +{ + DEBUG("[flashpage] locking the flash module\n"); + CNTRL_REG |= CNTRL_REG_LOCK; +} +static void _erase_page(void *page_addr) +{ +#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) + uint32_t *dst = page_addr; +#else + uint16_t *dst = page_addr; + + uint32_t hsi_state = (RCC->CR & RCC_CR_HSION); /* the internal RC oscillator (HSI) must be enabled */ - RCC->CR |= (RCC_CR_HSION); - while (!(RCC->CR & RCC_CR_HSIRDY)) {} + stmclk_enable_hsi(); +#endif - /* unlock the flash module */ - DEBUG("[flashpage] unlocking the flash module\n"); - if (FLASH->CR & FLASH_CR_LOCK) { - FLASH->KEYR = FLASH_KEY1; - FLASH->KEYR = FLASH_KEY2; - } + /* unlock the flash module */ + _unlock(); - /* ERASE sequence */ /* make sure no flash operation is ongoing */ DEBUG("[flashpage] erase: waiting for any operation to finish\n"); while (FLASH->SR & FLASH_SR_BSY) {} /* set page erase bit and program page address */ - DEBUG("[flashpage] erase: setting the erase bit and page address\n"); - FLASH->CR |= FLASH_CR_PER; - FLASH->AR = (uint32_t)flashpage_addr(page); - DEBUG("address to erase: %p\n", flashpage_addr(page)); + DEBUG("[flashpage] erase: setting the erase bit\n"); + CNTRL_REG |= FLASH_CR_PER; + DEBUG("address to erase: %p\n", page_addr); +#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) + DEBUG("[flashpage] erase: trigger the page erase\n"); + *dst = (uint32_t)0; +#else + DEBUG("[flashpage] erase: setting the page address\n"); + FLASH->AR = (uint32_t)dst; /* trigger the page erase and wait for it to be finished */ DEBUG("[flashpage] erase: trigger the page erase\n"); - FLASH->CR |= FLASH_CR_STRT; + CNTRL_REG |= FLASH_CR_STRT; +#endif DEBUG("[flashpage] erase: wait as long as device is busy\n"); while (FLASH->SR & FLASH_SR_BSY) {} /* reset PER bit */ DEBUG("[flashpage] erase: resetting the page erase bit\n"); - FLASH->CR &= ~(FLASH_CR_PER); + CNTRL_REG &= ~(FLASH_CR_PER); - /* WRITE sequence */ - if (data != NULL) { - DEBUG("[flashpage] write: now writing the data\n"); - /* set PG bit and program page to flash */ - FLASH->CR |= FLASH_CR_PG; - for (unsigned i = 0; i < (FLASHPAGE_SIZE / 2); i++) { - *page_addr++ = data_addr[i]; - while (FLASH->SR & FLASH_SR_BSY) {} - } - /* clear program bit again */ - FLASH->CR &= ~(FLASH_CR_PG); - DEBUG("[flashpage] write: done writing data\n"); + /* lock the flash module again */ + _lock(); + +#if !(defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)) + /* restore the HSI state */ + if (!hsi_state) { + stmclk_disable_hsi(); } +#endif +} + +void flashpage_write_raw(void *target_addr, void *data, size_t len) +{ + /* assert multiples of FLASHPAGE_RAW_BLOCKSIZE are written and no less of + that length. */ + assert(!(len % FLASHPAGE_RAW_BLOCKSIZE)); + + /* ensure writes are aligned */ + assert(!(((unsigned)target_addr % FLASHPAGE_RAW_ALIGNMENT) || + ((unsigned)data % FLASHPAGE_RAW_ALIGNMENT))); + + /* ensure the length doesn't exceed the actual flash size */ + assert(((unsigned)target_addr + len) < + (CPU_FLASH_BASE + (FLASHPAGE_SIZE * FLASHPAGE_NUMOF)) + 1); + +#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) + uint32_t *dst = target_addr; + uint32_t *data_addr = (uint32_t *)data; +#else + uint16_t *dst = (uint16_t *)target_addr; + uint16_t *data_addr = (uint16_t *)data; + + uint32_t hsi_state = (RCC->CR & RCC_CR_HSION); + /* the internal RC oscillator (HSI) must be enabled */ + stmclk_enable_hsi(); +#endif + + DEBUG("[flashpage_raw] unlocking the flash module\n"); + _unlock(); + + DEBUG("[flashpage] write: now writing the data\n"); +#if !(defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)) + /* 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]; + while (FLASH->SR & FLASH_SR_BSY) {} + } + + /* clear program bit again */ + CNTRL_REG &= ~(FLASH_CR_PG); + DEBUG("[flashpage] write: done writing data\n"); - /* finally, lock the flash module again */ - DEBUG("flashpage] now locking the flash module again\n"); - FLASH->CR |= FLASH_CR_LOCK; + DEBUG("flashpage_raw] now locking the flash module again\n"); + _lock(); +#if !(defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)) /* restore the HSI state */ if (!hsi_state) { - RCC->CR &= ~(RCC_CR_HSION); - while (RCC->CR & RCC_CR_HSIRDY) {} + stmclk_disable_hsi(); + } +#endif +} + +void flashpage_write(int page, void *data) +{ + assert(page < (int)FLASHPAGE_NUMOF); + +#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) + /* STM32L0/L1 only supports word sizes */ + uint32_t *page_addr = flashpage_addr(page); +#else + /* Default is to support half-word sizes */ + uint16_t *page_addr = flashpage_addr(page); +#endif + + /* ERASE sequence */ + _erase_page(page_addr); + + /* WRITE sequence */ + if (data != NULL) { + flashpage_write_raw(page_addr, data, FLASHPAGE_SIZE); } } From 4972f952d4b01ab71b52c880759a1b872b71cf1e Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 11 Mar 2018 20:34:07 +0100 Subject: [PATCH 2/5] cpu/stm32l0: add flashpage support --- cpu/stm32l0/Makefile.features | 2 ++ cpu/stm32l0/include/cpu_conf.h | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/cpu/stm32l0/Makefile.features b/cpu/stm32l0/Makefile.features index 494f8c194a24..5ee1506b5ea2 100644 --- a/cpu/stm32l0/Makefile.features +++ b/cpu/stm32l0/Makefile.features @@ -1,3 +1,5 @@ +FEATURES_PROVIDED += periph_flashpage +FEATURES_PROVIDED += periph_flashpage_raw FEATURES_PROVIDED += periph_hwrng BOARDS_WITHOUT_HWRNG += nucleo32-l031 diff --git a/cpu/stm32l0/include/cpu_conf.h b/cpu/stm32l0/include/cpu_conf.h index 057bb229f142..d8cb2b5ed423 100644 --- a/cpu/stm32l0/include/cpu_conf.h +++ b/cpu/stm32l0/include/cpu_conf.h @@ -54,6 +54,31 @@ extern "C" { #endif /** @} */ +/** + * @name Flash page configuration + * @{ + */ +#if defined(CPU_MODEL_STM32L073RZ) || defined(CPU_MODEL_STM32L072CZ) || \ + defined(CPU_MODEL_STM32L053R8) || defined(CPU_MODEL_STM32L031K6) +#define FLASHPAGE_SIZE (128U) +#endif + +#if defined(CPU_MODEL_STM32L073RZ) || defined(CPU_MODEL_STM32L072CZ) +#define FLASHPAGE_NUMOF (1536U) +#elif defined(CPU_MODEL_STM32L053R8) +#define FLASHPAGE_NUMOF (512U) +#elif defined(CPU_MODEL_STM32L031K6) +#define FLASHPAGE_NUMOF (256U) +#endif + +/* The minimum block size which can be written is 4B. However, the erase + * block is always FLASHPAGE_SIZE. + */ +#define FLASHPAGE_RAW_BLOCKSIZE (4U) +/* Writing should be always 4 byte aligned */ +#define FLASHPAGE_RAW_ALIGNMENT (4U) +/** @} */ + #ifdef __cplusplus } #endif From 4e1f2b5d38e3a348110477d20f06ccb005e2913f Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Tue, 13 Mar 2018 11:02:07 +0100 Subject: [PATCH 3/5] cpu/stm32l1: add flashpage support --- cpu/stm32l1/Makefile.features | 3 +++ cpu/stm32l1/include/cpu_conf.h | 22 +++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/cpu/stm32l1/Makefile.features b/cpu/stm32l1/Makefile.features index 8edd0b27724c..5e5e8b9118b4 100644 --- a/cpu/stm32l1/Makefile.features +++ b/cpu/stm32l1/Makefile.features @@ -1 +1,4 @@ +FEATURES_PROVIDED += periph_flashpage +FEATURES_PROVIDED += periph_flashpage_raw + -include $(RIOTCPU)/stm32_common/Makefile.features diff --git a/cpu/stm32l1/include/cpu_conf.h b/cpu/stm32l1/include/cpu_conf.h index 09bcfab3a5dd..cb86a3bf531c 100644 --- a/cpu/stm32l1/include/cpu_conf.h +++ b/cpu/stm32l1/include/cpu_conf.h @@ -72,10 +72,30 @@ extern "C" { #define CPU_FLASH_BASE FLASH_BASE /** @} */ +/** + * @name Flash page configuration + * @{ + */ +#if defined(CPU_MODEL_STM32L152RE) || defined(CPU_MODEL_STM32L151RC) +#define FLASHPAGE_SIZE (256U) +#if defined(CPU_MODEL_STM32L152RE) +#define FLASHPAGE_NUMOF (2048U) /* 512KB */ +#endif +#if defined(CPU_MODEL_STM32L151RC) +#define FLASHPAGE_NUMOF (1024U) /* 256KB */ +#endif +#endif +/* The minimum block size which can be written is 4B. However, the erase + * block is always FLASHPAGE_SIZE. + */ +#define FLASHPAGE_RAW_BLOCKSIZE (4U) +/* Writing should be always 4 bytes aligned */ +#define FLASHPAGE_RAW_ALIGNMENT (4U) +/** @} */ + #ifdef __cplusplus } #endif #endif /* CPU_CONF_H */ /** @} */ -/** @} */ From 4f7dc1ae413d96949c2aa537b5e2e8bec4a71e99 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Tue, 13 Mar 2018 11:02:19 +0100 Subject: [PATCH 4/5] cpu/stm32f0: add flashpage_raw support --- cpu/stm32f0/Makefile.features | 1 + cpu/stm32f0/include/cpu_conf.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/cpu/stm32f0/Makefile.features b/cpu/stm32f0/Makefile.features index fb630f4c2585..8d7a3af1ada8 100644 --- a/cpu/stm32f0/Makefile.features +++ b/cpu/stm32f0/Makefile.features @@ -1,5 +1,6 @@ ifeq (,$(filter nucleo32-f031,$(BOARD))) FEATURES_PROVIDED += periph_flashpage + FEATURES_PROVIDED += periph_flashpage_raw endif -include $(RIOTCPU)/stm32_common/Makefile.features diff --git a/cpu/stm32f0/include/cpu_conf.h b/cpu/stm32f0/include/cpu_conf.h index 786dc027b97a..794480ead853 100644 --- a/cpu/stm32f0/include/cpu_conf.h +++ b/cpu/stm32f0/include/cpu_conf.h @@ -89,6 +89,13 @@ extern "C" { #elif defined(CPU_MODEL_STM32F042K6) #define FLASHPAGE_NUMOF (32U) #endif + +/* The minimum block size which can be written is 2B. However, the erase + * block is always FLASHPAGE_SIZE. + */ +#define FLASHPAGE_RAW_BLOCKSIZE (2U) +/* Writing should be always 4 bytes aligned */ +#define FLASHPAGE_RAW_ALIGNMENT (4U) /** @} */ #ifdef __cplusplus From 06392bbfd3959da96ae8463a7c4e134a39fb64ee Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Tue, 13 Mar 2018 11:02:28 +0100 Subject: [PATCH 5/5] cpu/stm32f1: add flashpage_raw support --- cpu/stm32f1/Makefile.features | 1 + cpu/stm32f1/include/cpu_conf.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/cpu/stm32f1/Makefile.features b/cpu/stm32f1/Makefile.features index 6f8b9d6062d5..5e5e8b9118b4 100644 --- a/cpu/stm32f1/Makefile.features +++ b/cpu/stm32f1/Makefile.features @@ -1,3 +1,4 @@ FEATURES_PROVIDED += periph_flashpage +FEATURES_PROVIDED += periph_flashpage_raw -include $(RIOTCPU)/stm32_common/Makefile.features diff --git a/cpu/stm32f1/include/cpu_conf.h b/cpu/stm32f1/include/cpu_conf.h index 3b73eb1b0ea0..7a1b6f2548f7 100644 --- a/cpu/stm32f1/include/cpu_conf.h +++ b/cpu/stm32f1/include/cpu_conf.h @@ -65,6 +65,13 @@ extern "C" { #elif defined(CPU_MODEL_STM32F103RE) || defined(CPU_MODEL_STM32F103ZE) #define FLASHPAGE_NUMOF (256U) #endif + +/* The minimum block size which can be written is 2B. However, the erase + * block is always FLASHPAGE_SIZE. + */ +#define FLASHPAGE_RAW_BLOCKSIZE (2U) +/* Writing should be always 4 bytes aligned */ +#define FLASHPAGE_RAW_ALIGNMENT (4U) /** @} */ #ifdef __cplusplus