diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index 499129a6f3..d399ece866 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -29,6 +29,21 @@ #include "py/mphal.h" #include "flash.h" +#if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION +// See WB55 specific documentation in AN5289 Rev 3, and in particular, Figure 10. + +#include "rfcore.h" +#include "stm32wbxx_ll_hsem.h" + +// Protects all flash registers. +#define SEMID_FLASH_REGISTERS (2) +// Used by CPU1 to prevent CPU2 from writing/erasing data in flash memory. +#define SEMID_FLASH_CPU1 (6) +// Used by CPU2 to prevent CPU1 from writing/erasing data in flash memory. +#define SEMID_FLASH_CPU2 (7) + +#endif + typedef struct { uint32_t base_address; uint32_t sector_size; @@ -181,9 +196,27 @@ int flash_erase(uint32_t flash_dest, uint32_t num_word32) { return 0; } + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Acquire lock on the flash peripheral. + while (LL_HSEM_1StepLock(HSEM, SEMID_FLASH_REGISTERS)) { + } + #endif + // Unlock the flash for erase. HAL_FLASH_Unlock(); + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Tell the HCI controller stack we're starting an erase, so it + // avoids radio activity for a while. + rfcore_start_flash_erase(); + // Wait for PES. + while (LL_FLASH_IsActiveFlag_OperationSuspended()) { + } + // Wait for flash lock. + while (LL_HSEM_1StepLock(HSEM, SEMID_FLASH_CPU2)) { + } + #endif + // Clear pending flags (if any) and set up EraseInitStruct. FLASH_EraseInitTypeDef EraseInitStruct; @@ -233,9 +266,23 @@ int flash_erase(uint32_t flash_dest, uint32_t num_word32) { uint32_t SectorError = 0; HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError); + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Release flash lock. + while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_CFGBSY)) { + } + LL_HSEM_ReleaseLock(HSEM, SEMID_FLASH_CPU2, 0); + // Tell HCI controller that erase is over. + rfcore_end_flash_erase(); + #endif + // Lock the flash after erase. HAL_FLASH_Lock(); + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Release lock on the flash peripheral. + LL_HSEM_ReleaseLock(HSEM, SEMID_FLASH_REGISTERS, 0); + #endif + return mp_hal_status_to_neg_errno(status); } @@ -269,9 +316,21 @@ void flash_erase_it(uint32_t flash_dest, uint32_t num_word32) { */ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Acquire lock on the flash peripheral. + while (LL_HSEM_1StepLock(HSEM, SEMID_FLASH_REGISTERS)) { + } + #endif + // Unlock the flash for write. HAL_FLASH_Unlock(); + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Wait for PES. + while (LL_FLASH_IsActiveFlag_OperationSuspended()) { + } + #endif + HAL_StatusTypeDef status = HAL_OK; #if defined(STM32L4) || defined(STM32WB) @@ -279,7 +338,22 @@ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { // program the flash uint64 by uint64 for (int i = 0; i < num_word32 / 2; i++) { uint64_t val = *(uint64_t *)src; + + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Wait for flash lock. + while (LL_HSEM_1StepLock(HSEM, SEMID_FLASH_CPU2)) { + } + #endif + status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flash_dest, val); + + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Release flash lock. + LL_HSEM_ReleaseLock(HSEM, SEMID_FLASH_CPU2, 0); + while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_CFGBSY)) { + } + #endif + if (status != HAL_OK) { num_word32 = 0; // don't write any odd word after this loop break; @@ -290,7 +364,21 @@ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { if ((num_word32 & 0x01) == 1) { uint64_t val = *(uint64_t *)flash_dest; val = (val & 0xffffffff00000000uL) | (*src); + + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Wait for flash lock. + while (LL_HSEM_1StepLock(HSEM, SEMID_FLASH_CPU2)) { + } + #endif + status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flash_dest, val); + + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Release flash lock. + LL_HSEM_ReleaseLock(HSEM, SEMID_FLASH_CPU2, 0); + while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_CFGBSY)) { + } + #endif } #elif defined(STM32H7) @@ -322,6 +410,11 @@ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { // Lock the flash after write. HAL_FLASH_Lock(); + #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION + // Release lock on the flash peripheral. + LL_HSEM_ReleaseLock(HSEM, SEMID_FLASH_REGISTERS, 0); + #endif + return mp_hal_status_to_neg_errno(status); } diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index c901dfb334..3d041e1c14 100755 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -73,6 +73,7 @@ CFLAGS += -DFFCONF_H=\"ports/stm32/mboot/ffconf.h\" CFLAGS += -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1_NO_ASSERT CFLAGS += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT CFLAGS += -DBUILDING_MBOOT=1 +CFLAGS += -DMICROPY_HW_STM32WB_FLASH_SYNCRONISATION=0 CFLAGS += -DBOOTLOADER_DFU_USB_VID=$(BOOTLOADER_DFU_USB_VID) -DBOOTLOADER_DFU_USB_PID=$(BOOTLOADER_DFU_USB_PID) LDFLAGS = -nostdlib -L . -T stm32_generic.ld -Map=$(@:.elf=.map) --cref diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 127696b193..a73a26b162 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -216,6 +216,10 @@ #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (1) +#ifndef MICROPY_HW_STM32WB_FLASH_SYNCRONISATION +#define MICROPY_HW_STM32WB_FLASH_SYNCRONISATION (1) +#endif + #else #error Unsupported MCU series #endif diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c index 550e5323e8..6133720958 100644 --- a/ports/stm32/rfcore.c +++ b/ports/stm32/rfcore.c @@ -57,10 +57,12 @@ #define OCF_CB_RESET (0x03) #define OCF_CB_SET_EVENT_MASK2 (0x63) -#define OGF_VENDOR (0x3f) -#define OCF_WRITE_CONFIG (0x0c) -#define OCF_SET_TX_POWER (0x0f) -#define OCF_BLE_INIT (0x66) +#define OGF_VENDOR (0x3f) +#define OCF_WRITE_CONFIG (0x0c) +#define OCF_SET_TX_POWER (0x0f) +#define OCF_BLE_INIT (0x66) +#define OCF_C2_FLASH_ERASE_ACTIVITY (0x69) +#define OCF_C2_SET_FLASH_ACTIVITY_CONTROL (0x73) #define HCI_OPCODE(ogf, ocf) ((ogf) << 10 | (ocf)) @@ -557,6 +559,10 @@ void rfcore_ble_init(void) { // Configure and reset the BLE controller. tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_BLE_INIT), (const uint8_t *)&ble_init_params, sizeof(ble_init_params), 0); tl_ble_hci_cmd_resp(HCI_OPCODE(0x03, 0x0003), NULL, 0); + + // Enable PES rather than SEM7 to moderate flash access between the cores. + uint8_t buf = 0; // FLASH_ACTIVITY_CONTROL_PES + tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_C2_SET_FLASH_ACTIVITY_CONTROL), &buf, 1, 0); } void rfcore_ble_hci_cmd(size_t len, const uint8_t *src) { @@ -616,6 +622,16 @@ void rfcore_ble_set_txpower(uint8_t level) { tl_ble_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_SET_TX_POWER), buf, 2); } +void rfcore_start_flash_erase(void) { + uint8_t buf = 1; // ERASE_ACTIVITY_ON + tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_C2_FLASH_ERASE_ACTIVITY), &buf, 1, 0); +} + +void rfcore_end_flash_erase(void) { + uint8_t buf = 0; // ERASE_ACTIVITY_OFF + tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_C2_FLASH_ERASE_ACTIVITY), &buf, 1, 0); +} + // IPCC IRQ Handlers void IPCC_C1_TX_IRQHandler(void) { IRQ_ENTER(IPCC_C1_TX_IRQn); diff --git a/ports/stm32/rfcore.h b/ports/stm32/rfcore.h index 6a3c85f67d..fe29ac612c 100644 --- a/ports/stm32/rfcore.h +++ b/ports/stm32/rfcore.h @@ -35,6 +35,9 @@ void rfcore_ble_hci_cmd(size_t len, const uint8_t *src); void rfcore_ble_check_msg(int (*cb)(void *, const uint8_t *, size_t), void *env); void rfcore_ble_set_txpower(uint8_t level); +void rfcore_start_flash_erase(void); +void rfcore_end_flash_erase(void); + MP_DECLARE_CONST_FUN_OBJ_0(rfcore_status_obj); MP_DECLARE_CONST_FUN_OBJ_1(rfcore_fw_version_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(rfcore_sys_hci_obj);