diff --git NuttX/nuttx/arch/arm/src/stm32/Kconfig NuttX/nuttx/arch/arm/src/stm32/Kconfig index b6c0458..8ebf8df 100644 --- NuttX/nuttx/arch/arm/src/stm32/Kconfig +++ NuttX/nuttx/arch/arm/src/stm32/Kconfig @@ -2514,6 +2514,14 @@ 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 "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" default STM32_JTAG_DISABLE diff --git NuttX/nuttx/arch/arm/src/stm32/chip/stm32_flash.h NuttX/nuttx/arch/arm/src/stm32/chip/stm32_flash.h index 70e6d62..82d8f09 100644 --- NuttX/nuttx/arch/arm/src/stm32/chip/stm32_flash.h +++ NuttX/nuttx/arch/arm/src/stm32/chip/stm32_flash.h @@ -322,10 +322,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 */ diff --git NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c index 73f1419..fb1e1ca 100644 --- NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c +++ NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c @@ -47,6 +47,10 @@ #include #include + +#include +#include +#include #include #include "stm32_flash.h" @@ -81,13 +85,29 @@ #endif /************************************************************************************ - * Private Functions + * Private Data ************************************************************************************/ +static sem_t g_sem = SEM_INITIALIZER(1); + /************************************************************************************ - * Public Functions + * Private Functions ************************************************************************************/ -void stm32_flash_unlock(void) + +static void sem_lock(void) +{ + while (sem_wait(&g_sem) < 0) + { + DEBUGASSERT(errno == EINTR); + } +} + +static inline void sem_unlock(void) +{ + sem_post(&g_sem); +} + +static void flash_unlock(void) { while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) { @@ -103,14 +123,48 @@ void stm32_flash_unlock(void) } } -void stm32_flash_lock(void) +static void flash_lock(void) { modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_LOCK); } +#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) +static void data_cache_disable(void) +{ + modifyreg32(STM32_FLASH_ACR, FLASH_ACR_DCEN, 0); +} -#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) +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); +} +#endif /* defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) */ + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +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) size_t up_progmem_pagesize(size_t page) { return STM32_FLASH_PAGESIZE; @@ -231,14 +285,19 @@ ssize_t up_progmem_erasepage(size_t page) return -EFAULT; } - /* Get flash ready and begin erasing single page */ + 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 erasing single page */ - stm32_flash_unlock(); + flash_unlock(); modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PAGE_ERASE); @@ -257,6 +316,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) @@ -318,14 +378,23 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) return -EFAULT; } - /* Get flash ready and begin flashing */ + 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 */ + + flash_unlock(); - stm32_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); @@ -347,17 +416,25 @@ 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); + +#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) + data_cache_enable(); +#endif + + sem_unlock(); return written; }