From 80f56e75f95f8ba248b9271f55d9907f1c6771e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 22 Mar 2017 10:33:59 -0700 Subject: [PATCH 1/5] stm32: Fix erase sector number for microcontrolers with more than 11 sectors Erase a sector from the second bank cause the bit 4 of SNB being set but never unsed, so trying to erase a sector from the first bank was acually eraseing a sector from the second bank. --- arch/arm/src/stm32/chip/stm32_flash.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/stm32/chip/stm32_flash.h b/arch/arm/src/stm32/chip/stm32_flash.h index 218ba05fcf..32eeaf90dd 100644 --- a/arch/arm/src/stm32/chip/stm32_flash.h +++ b/arch/arm/src/stm32/chip/stm32_flash.h @@ -328,10 +328,11 @@ # define FLASH_CR_SER (1 << 1) /* Bit 1: Sector Erase */ # define FLASH_CR_MER (1 << 2) /* Bit 2: Mass Erase sectors 0..11 */ # define FLASH_CR_SNB_SHIFT (3) /* Bits 3-6: Sector number */ -# define FLASH_CR_SNB_MASK (15 << FLASH_CR_SNB_SHIFT) #if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429) +# define FLASH_CR_SNB_MASK (31 << FLASH_CR_SNB_SHIFT) # define FLASH_CR_SNB(n) (((n % 12) << FLASH_CR_SNB_SHIFT) | ((n / 12) << 7)) /* Sector n, n=0..23 */ #else +# define FLASH_CR_SNB_MASK (15 << FLASH_CR_SNB_SHIFT) # define FLASH_CR_SNB(n) ((n) << FLASH_CR_SNB_SHIFT) /* Sector n, n=0..11 */ #endif # define FLASH_CR_PSIZE_SHIFT (8) /* Bits 8-9: Program size */ From 09f70c462de80ad1492838cc2bc08912a7e118b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 22 Mar 2017 10:56:37 -0700 Subject: [PATCH 2/5] stm32: Make up_progmem thread safe Writing to a flash sector while starting the erase of other sector have a undefined behavior so lets add a semaphore and syncronize access to Flash registers. But for the semaphore to work it needs to be initialized so each board needs call stm32_flash_initialize() on initialization, so to avoid runtime problems it is only using semaphore and making it thread safe if initialized, after all boards starts to call stm32_flash_initialize() we can remove the boolean and the check. --- arch/arm/src/stm32/chip/stm32_flash.h | 1 + arch/arm/src/stm32/stm32_flash.c | 70 ++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/arch/arm/src/stm32/chip/stm32_flash.h b/arch/arm/src/stm32/chip/stm32_flash.h index 32eeaf90dd..16c67a933e 100644 --- a/arch/arm/src/stm32/chip/stm32_flash.h +++ b/arch/arm/src/stm32/chip/stm32_flash.h @@ -392,6 +392,7 @@ * Public Functions ************************************************************************************/ +void stm32_flash_initialize(void); void stm32_flash_lock(void); void stm32_flash_unlock(void); diff --git a/arch/arm/src/stm32/stm32_flash.c b/arch/arm/src/stm32/stm32_flash.c index 9ac38a19a1..7f0b53ee60 100644 --- a/arch/arm/src/stm32/stm32_flash.c +++ b/arch/arm/src/stm32/stm32_flash.c @@ -47,7 +47,9 @@ #include #include + #include +#include #include "stm32_flash.h" #include "stm32_rcc.h" @@ -84,10 +86,30 @@ * Private Functions ************************************************************************************/ -/************************************************************************************ - * Public Functions - ************************************************************************************/ -void stm32_flash_unlock(void) +static sem_t g_sem; +/* + * After all SMT32 boards starts calling stm32_flash_initialize() this can + * be removed. + */ +static bool g_initialized = false; + +static void sem_lock(void) +{ + if (g_initialized) + { + sem_wait(&g_sem); + } +} + +static void sem_unlock(void) +{ + if (g_initialized) + { + sem_post(&g_sem); + } +} + +static void flash_unlock(void) { while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) { @@ -103,11 +125,36 @@ void stm32_flash_unlock(void) } } -void stm32_flash_lock(void) +static void flash_lock(void) { modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_LOCK); } +/************************************************************************************ + * Public Functions + ************************************************************************************/ +void stm32_flash_initialize(void) +{ + g_initialized = true; + /* + * Initialize the semaphore that manages exclusive access flash registers + */ + sem_init(&g_sem, 0, 1); +} + +void stm32_flash_unlock(void) +{ + sem_lock(); + flash_unlock(); + sem_unlock(); +} + +void stm32_flash_lock(void) +{ + sem_lock(); + flash_lock(); + sem_unlock(); +} #if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) @@ -231,6 +278,8 @@ ssize_t up_progmem_erasepage(size_t page) return -EFAULT; } + sem_lock(); + #if !defined(CONFIG_STM32_STM32F40XX) if (!(getreg32(STM32_RCC_CR) & RCC_CR_HSION)) { @@ -240,7 +289,7 @@ ssize_t up_progmem_erasepage(size_t page) /* Get flash ready and begin erasing single page */ - stm32_flash_unlock(); + flash_unlock(); modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PAGE_ERASE); @@ -259,6 +308,7 @@ ssize_t up_progmem_erasepage(size_t page) while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) up_waste(); modifyreg32(STM32_FLASH_CR, FLASH_CR_PAGE_ERASE, 0); + sem_unlock(); /* Verify */ if (up_progmem_ispageerased(page) == 0) @@ -320,16 +370,19 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) return -EFAULT; } + sem_lock(); + #if !defined(CONFIG_STM32_STM32F40XX) if (!(getreg32(STM32_RCC_CR) & RCC_CR_HSION)) { + sem_unlock(); return -EPERM; } #endif /* Get flash ready and begin flashing */ - stm32_flash_unlock(); + flash_unlock(); modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PG); @@ -351,17 +404,20 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) if (getreg32(STM32_FLASH_SR) & FLASH_SR_WRITE_PROTECTION_ERROR) { modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); + sem_unlock(); return -EROFS; } if (getreg16(addr) != *hword) { modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); + sem_unlock(); return -EIO; } } modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); + sem_unlock(); return written; } From b9b4f184a7a014ec324f50fabdc4c6539e676b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 22 Mar 2017 11:12:17 -0700 Subject: [PATCH 3/5] stm32: Add workaround for flash data cache corruption on read-while-write This is a know hardware issue on some STM32 see the errata of your model and if you make use of both memory banks you should enable it. --- arch/arm/src/stm32/Kconfig | 6 ++++++ arch/arm/src/stm32/stm32_flash.c | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index de2c8fe23b..72f8a17fbb 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -2633,6 +2633,12 @@ config STM32_FLASH_PREFETCH on F1 parts). Some early revisions of F4 parts do not support FLASH pre-fetch properly and enabling this option may interfere with ADC accuracy. +config STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW + bool "Enable the workaround to fix flash data cache corruption when reading from one flash bank while writing on other flash bank" + default n + ---help--- + See your STM32 errata to check if your STM32 is affected by this problem. + choice prompt "JTAG Configuration" default STM32_JTAG_DISABLE diff --git a/arch/arm/src/stm32/stm32_flash.c b/arch/arm/src/stm32/stm32_flash.c index 7f0b53ee60..4907aa9f0a 100644 --- a/arch/arm/src/stm32/stm32_flash.c +++ b/arch/arm/src/stm32/stm32_flash.c @@ -130,6 +130,20 @@ static void flash_lock(void) modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_LOCK); } +static void data_cache_disable(void) +{ + modifyreg32(STM32_FLASH_ACR, FLASH_ACR_DCEN, 0); +} + +static void data_cache_enable(void) +{ + /* reset data cache */ + modifyreg32(STM32_FLASH_ACR, 0, FLASH_ACR_DCRST); + + /* enable data cache */ + modifyreg32(STM32_FLASH_ACR, 0, FLASH_ACR_DCEN); +} + /************************************************************************************ * Public Functions ************************************************************************************/ @@ -384,6 +398,10 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) flash_unlock(); +#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) + data_cache_disable(); +#endif + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PG); #if defined(CONFIG_STM32_STM32F40XX) @@ -417,6 +435,11 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) } modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); + +#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) + data_cache_enable(); +#endif + sem_unlock(); return written; } From 947acd6c1a1eef21c97f147b58224fd85e8dc880 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 22 Mar 2017 15:53:12 -0600 Subject: [PATCH 4/5] Small changes from review of last PR --- arch/arm/src/stm32/Kconfig | 10 +++--- arch/arm/src/stm32/chip/stm32_flash.h | 1 - arch/arm/src/stm32/stm32_flash.c | 43 ++++++++++---------------- configs/clicker2-stm32/src/stm32_spi.c | 2 +- 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 72f8a17fbb..9e3ce56127 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -2634,10 +2634,12 @@ config STM32_FLASH_PREFETCH properly and enabling this option may interfere with ADC accuracy. config STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW - bool "Enable the workaround to fix flash data cache corruption when reading from one flash bank while writing on other flash bank" - default n - ---help--- - See your STM32 errata to check if your STM32 is affected by this problem. + bool "Workaround for FLASH data cache corruption" + default n + ---help--- + Enable the workaround to fix flash data cache corruption when reading + from one flash bank while writing on other flash bank. See your STM32 + errata to check if your STM32 is affected by this problem. choice prompt "JTAG Configuration" diff --git a/arch/arm/src/stm32/chip/stm32_flash.h b/arch/arm/src/stm32/chip/stm32_flash.h index 16c67a933e..32eeaf90dd 100644 --- a/arch/arm/src/stm32/chip/stm32_flash.h +++ b/arch/arm/src/stm32/chip/stm32_flash.h @@ -392,7 +392,6 @@ * Public Functions ************************************************************************************/ -void stm32_flash_initialize(void); void stm32_flash_lock(void); void stm32_flash_unlock(void); diff --git a/arch/arm/src/stm32/stm32_flash.c b/arch/arm/src/stm32/stm32_flash.c index 4907aa9f0a..8ba48a8262 100644 --- a/arch/arm/src/stm32/stm32_flash.c +++ b/arch/arm/src/stm32/stm32_flash.c @@ -48,8 +48,10 @@ #include #include -#include #include +#include +#include +#include #include "stm32_flash.h" #include "stm32_rcc.h" @@ -82,31 +84,27 @@ #define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPERR #endif +/************************************************************************************ + * Private Data + ************************************************************************************/ + +static sem_t g_sem = SEM_INITIALIZER(1); + /************************************************************************************ * Private Functions ************************************************************************************/ -static sem_t g_sem; -/* - * After all SMT32 boards starts calling stm32_flash_initialize() this can - * be removed. - */ -static bool g_initialized = false; - static void sem_lock(void) { - if (g_initialized) + while (sem_wait(&g_sem) < 0) { - sem_wait(&g_sem); + DEBUGASSERT(errno == EINTR); } } -static void sem_unlock(void) +static inline void sem_unlock(void) { - if (g_initialized) - { - sem_post(&g_sem); - } + sem_post(&g_sem); } static void flash_unlock(void) @@ -137,24 +135,18 @@ static void data_cache_disable(void) static void data_cache_enable(void) { - /* reset data cache */ + /* Reset data cache */ + modifyreg32(STM32_FLASH_ACR, 0, FLASH_ACR_DCRST); - /* enable data cache */ + /* Enable data cache */ + modifyreg32(STM32_FLASH_ACR, 0, FLASH_ACR_DCEN); } /************************************************************************************ * Public Functions ************************************************************************************/ -void stm32_flash_initialize(void) -{ - g_initialized = true; - /* - * Initialize the semaphore that manages exclusive access flash registers - */ - sem_init(&g_sem, 0, 1); -} void stm32_flash_unlock(void) { @@ -171,7 +163,6 @@ void stm32_flash_lock(void) } #if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) - size_t up_progmem_pagesize(size_t page) { return STM32_FLASH_PAGESIZE; diff --git a/configs/clicker2-stm32/src/stm32_spi.c b/configs/clicker2-stm32/src/stm32_spi.c index 7e231d108b..87e6e8d1d1 100644 --- a/configs/clicker2-stm32/src/stm32_spi.c +++ b/configs/clicker2-stm32/src/stm32_spi.c @@ -63,7 +63,7 @@ * Name: stm32_spidev_initialize * * Description: - * Called to configure SPI chip select GPIO pins for the stm32f4discovery board. + * Called to configure SPI chip select GPIO pins for the Mikroe Clicker2 STM32 board. * ************************************************************************************/ From 3fb0a00c356d39f7ea2b4a330868941711eee987 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 22 Mar 2017 17:32:52 -0600 Subject: [PATCH 5/5] Small changes from review of last PR. Plus spacing and typo fix. --- arch/arm/src/stm32/Kconfig | 6 +++--- arch/arm/src/stm32/chip/stm32_flash.h | 24 ++++++++++++------------ configs/Makefile | 2 +- include/semaphore.h | 4 ++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 9e3ce56127..557f8434f0 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -2629,9 +2629,9 @@ config STM32_FLASH_PREFETCH default y if STM32_STM32F427 || STM32_STM32F429 || STM32_STM32F446 default n ---help--- - Enable FLASH prefetch and F2 and F4 parts (FLASH pre-fetch is always enabled - on F1 parts). Some early revisions of F4 parts do not support FLASH pre-fetch - properly and enabling this option may interfere with ADC accuracy. + Enable FLASH prefetch and F2 and F4 parts (FLASH pre-fetch is always enabled + on F1 parts). Some early revisions of F4 parts do not support FLASH pre-fetch + properly and enabling this option may interfere with ADC accuracy. config STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW bool "Workaround for FLASH data cache corruption" diff --git a/arch/arm/src/stm32/chip/stm32_flash.h b/arch/arm/src/stm32/chip/stm32_flash.h index 32eeaf90dd..6bc1085bd1 100644 --- a/arch/arm/src/stm32/chip/stm32_flash.h +++ b/arch/arm/src/stm32/chip/stm32_flash.h @@ -324,10 +324,10 @@ # define FLASH_CR_OBL_LAUNCH (1 << 13) /* Bit 13: Force option byte loading */ # endif #elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) -# define FLASH_CR_PG (1 << 0) /* Bit 0: Programming */ -# define FLASH_CR_SER (1 << 1) /* Bit 1: Sector Erase */ -# define FLASH_CR_MER (1 << 2) /* Bit 2: Mass Erase sectors 0..11 */ -# define FLASH_CR_SNB_SHIFT (3) /* Bits 3-6: Sector number */ +# define FLASH_CR_PG (1 << 0) /* Bit 0: Programming */ +# define FLASH_CR_SER (1 << 1) /* Bit 1: Sector Erase */ +# define FLASH_CR_MER (1 << 2) /* Bit 2: Mass Erase sectors 0..11 */ +# define FLASH_CR_SNB_SHIFT (3) /* Bits 3-6: Sector number */ #if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429) # define FLASH_CR_SNB_MASK (31 << FLASH_CR_SNB_SHIFT) # define FLASH_CR_SNB(n) (((n % 12) << FLASH_CR_SNB_SHIFT) | ((n / 12) << 7)) /* Sector n, n=0..23 */ @@ -335,19 +335,19 @@ # define FLASH_CR_SNB_MASK (15 << FLASH_CR_SNB_SHIFT) # define FLASH_CR_SNB(n) ((n) << FLASH_CR_SNB_SHIFT) /* Sector n, n=0..11 */ #endif -# define FLASH_CR_PSIZE_SHIFT (8) /* Bits 8-9: Program size */ +# define FLASH_CR_PSIZE_SHIFT (8) /* Bits 8-9: Program size */ # define FLASH_CR_PSIZE_MASK (3 << FLASH_CR_PSIZE_SHIFT) # define FLASH_CR_PSIZE_X8 (0 << FLASH_CR_PSIZE_SHIFT) /* 00 program x8 */ # define FLASH_CR_PSIZE_X16 (1 << FLASH_CR_PSIZE_SHIFT) /* 01 program x16 */ # define FLASH_CR_PSIZE_X32 (2 << FLASH_CR_PSIZE_SHIFT) /* 10 program x32 */ # define FLASH_CR_PSIZE_X64 (3 << FLASH_CR_PSIZE_SHIFT) /* 11 program x64 */ -# define FLASH_CR_STRT (1 << 16) /* Bit 16: Start Erase */ -# define FLASH_CR_EOPIE (1 << 24) /* Bit 24: End of operation interrupt enable */ -# define FLASH_CR_ERRIE (1 << 25) /* Bit 25: Error interrupt enable */ -# define FLASH_CR_LOCK (1 << 31) /* Bit 31: Lock */ +# define FLASH_CR_STRT (1 << 16) /* Bit 16: Start Erase */ +# define FLASH_CR_EOPIE (1 << 24) /* Bit 24: End of operation interrupt enable */ +# define FLASH_CR_ERRIE (1 << 25) /* Bit 25: Error interrupt enable */ +# define FLASH_CR_LOCK (1 << 31) /* Bit 31: Lock */ #endif #if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429) -# define FLASH_CR_MER1 (1 << 15) /* Bit 15: Mass Erase sectors 12..23 */ +# define FLASH_CR_MER1 (1 << 15) /* Bit 15: Mass Erase sectors 12..23 */ #endif /* Flash Option Control Register (OPTCR) */ @@ -375,7 +375,7 @@ /* Flash Option Control Register (OPTCR1) */ #if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429) -# define FLASH_OPTCR1_NWRP_SHIFT (16) /* Bits 16-27: Not write protect (high bank) */ +# define FLASH_OPTCR1_NWRP_SHIFT (16) /* Bits 16-27: Not write protect (high bank) */ # define FLASH_OPTCR1_NWRP_MASK (0xfff << FLASH_OPTCR_NWRP_SHIFT) # define FLASH_OPTCR1_BFB2_SHIFT (4) /* Bits 4: Dual-bank Boot option byte */ @@ -384,7 +384,7 @@ #endif #if defined(CONFIG_STM32_STM32F446) -# define FLASH_OPTCR1_NWRP_SHIFT (16) /* Bits 16-23: Not write protect (high bank) */ +# define FLASH_OPTCR1_NWRP_SHIFT (16) /* Bits 16-23: Not write protect (high bank) */ # define FLASH_OPTCR1_NWRP_MASK (0xff << FLASH_OPTCR_NWRP_SHIFT) #endif diff --git a/configs/Makefile b/configs/Makefile index f430e137e8..31de5604e0 100644 --- a/configs/Makefile +++ b/configs/Makefile @@ -89,7 +89,7 @@ OBJS = $(AOBJS) $(COBJS) BIN = libconfigs$(LIBEXT) all: $(BIN) -.PHONY: depend ccontext clean_context clean distclean +.PHONY: depend context clean_context clean distclean $(AOBJS): %$(OBJEXT): %.S $(call ASSEMBLE, $<, $@) diff --git a/include/semaphore.h b/include/semaphore.h index 0056909db6..e14b1aa409 100644 --- a/include/semaphore.h +++ b/include/semaphore.h @@ -105,14 +105,14 @@ typedef struct sem_s sem_t; #ifdef CONFIG_PRIORITY_INHERITANCE # if CONFIG_SEM_PREALLOCHOLDERS > 0 # define SEM_INITIALIZER(c) \ - {(c), 0, NULL} /* semcount, flags, hhead */ + {(c), 0, NULL} /* semcount, flags, hhead */ # else # define SEM_INITIALIZER(c) \ {(c), 0, {SEMHOLDER_INITIALIZER, SEMHOLDER_INITIALIZER}} /* semcount, flags, holder[2] */ # endif #else # define SEM_INITIALIZER(c) \ - {(c)} /* semcount */ + {(c)} /* semcount */ #endif /****************************************************************************