Skip to main content
Visitor II
May 16, 2026
Question

STM32WB15CC + FreeRTOS: BLE connection drops when writing configuration to internal Flash

  • May 16, 2026
  • 1 reply
  • 118 views

 

Hardware: STM32 NUCLEO-WB15CC (STM32WB15CCUX)
RTOS: FreeRTOS
BLE stack: STM32WB WPAN / BLE via CPU2 (M0+)


Hi,

 

When writing a small configuration block (~48 bytes) to the internal Flash from CPU1 (M4 FreeRTOS task), the BLE connection drops immediately. The disconnect event is received on the host side with no prior warning, and the firmware logs a HCI_DISCONNECTION_COMPLETE_EVT shortly after the Flash erase/write sequence begins.

 

The Flash region used is a dedicated 2 KB NVM page at address 0x0801B000 (defined in the linker script as FLASH_NVM):

 

FLASH_NVM (rx) : ORIGIN = 0x0801B000, LENGTH = 2K



--- Data Written ---

 

The payload written is 48 bytes (already 8-byte aligned), structured as:
[magic: uint32_t (4 B)] [Config_t (40 B)] [checksum: uint32_t (4 B)]


The Config_t struct:


typedef struct {
uint16_t volume_shown;
uint16_t client_timeout_ms;
uint16_t cup_detection_threshold;
uint16_t flow_timeout_forward_ms;
uint16_t flow_timeout_backward_ms;
uint16_t foam_ms;
uint16_t foam_decay_minutes;
uint16_t foam_ms_after_decay;
uint16_t steps_forward;
uint16_t steps_backward;
uint16_t step_increment;
uint16_t tick;
uint8_t use_hall_positioning;
uint8_t offline_operation;
uint8_t com_mode;
uint8_t integration_zig;
float adjust;
char serial_number[4];
RGB_Color_t led_color; // 3 bytes (r, g, b)
} Config_t; // sizeof = 40 bytes



--- Flash Write Code (CPU1 / M4, FreeRTOS task) ---

 

Erase (FlashStorage_Erase):

 

FlashStorage_Status_t FlashStorage_Erase(void)
{
FLASH_EraseInitTypeDef erase_config;
uint32_t page_error = 0U;


uint32_t base = storage_base_addr(); // 0x0801B000
uint32_t page = (base - FLASH_BASE) / FLASH_PAGE_SIZE;


HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);


erase_config.TypeErase = FLASH_TYPEERASE_PAGES;
erase_config.Page = page;
erase_config.NbPages = 1U;


HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase_config, &page_error);
HAL_FLASH_Lock();


return (status == HAL_OK) ? FLASH_STORAGE_OK : FLASH_STORAGE_ERROR_ERASE;
}



Write (FlashStorage_Write):
FlashStorage_Status_t FlashStorage_Write(uint32_t offset, const void *data, uint32_t size)
{
uint32_t address = storage_base_addr() + offset; // 0x0801B000 + 0
const uint64_t *src=(const uint64_t *)data;


HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);


for (uint32_t i = 0U; i < (size / 8U); i++) {
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, src[i]);
address += 8U;
}


HAL_FLASH_Lock();
return FLASH_STORAGE_OK;
}



Call site (Config_SaveToFlash):
void Config_SaveToFlash(void)
{
uint8_t buf[128];
uint32_t magic = CONFIG_FLASH_MAGIC;
uint32_t new_checksum = compute_config_checksum(&config, sizeof(Config_t));


if (new_checksum == last_saved_checksum) return;


memset(buf, 0xFF, sizeof(buf));
memcpy(buf, &magic, 4);
memcpy(buf + 4, &config, sizeof(Config_t));
memcpy(buf + 4 + sizeof(Config_t), &new_checksum, 4);


FlashStorage_Erase();
FlashStorage_Write(0, buf, 48);


last_saved_checksum = new_checksum;
}



--- Deferred Save Strategy ---

 

Config_SaveToFlash() is called from a FreeRTOS task via a deferred mechanism: when a configuration command is received over BLE (GATT write on a custom NUS-style RX characteristic), a pending flag is set and the actual write is delayed by 3000 ms. The task polls Config_ProcessPendingSave() periodically:
void Config_RequestSaveToFlash(void) {
save_pending = true;
save_request_tick = xTaskGetTickCount();
}


void Config_ProcessPendingSave(void) {
if (!save_pending) return;
if ((xTaskGetTickCount() - save_request_tick) < pdMS_TO_TICKS(3000)) return;


save_pending = false;
Config_SaveToFlash();
}

 

Even with this 3-second delay, the BLE connection still drops at the moment HAL_FLASHEx_Erase() is called.



--- Questions ---

 

1. On STM32WB15CC, does a Flash erase/write from CPU1 stall CPU2 (M0+) long enough to cause a supervision timeout or HCI timeout? Is the FLASH_NVM page at 0x0801B000 in a region shared with the BLE stack firmware?

 

2. Should SHCI_C2_FLASH_EraseActivity() be called before/after the erase to notify CPU2? Is this function available and applicable on the WB15?

 

3. Is there a recommended pattern for safely writing to internal Flash while maintaining an active BLE connection on STM32WB15, using FreeRTOS?

 

Any guidance is appreciated. Thank you.

1 reply

ST Employee
May 19, 2026

Hello,

Here are some answers 

1/ Yes, any write/erase of the Flash stalls both CPU1 and CPU2. There is only one flash shared by both CPU so there is no safe area that could be written without stalling CPU2. If this happen during CPU2 radio operation, the link will be lost.

2/ Yes, this is mandatory and available on all STM32WBx products.

3/ The algorithm to be implemented is specified in AN5289 Chapter 4.7 Flash memory management.

The best would be to reuse the flash driver that implements this algorithm and is used and available in the project BLE_Ota (or any other BLE_xxx_Ota project).

It is provided in baremetal framework but can be used as is in OS framework. You may need to adapt to the OS the implementation of FD_WaitForSemAvailable() since the default implementation is a polling activity which will block your task instead of making it pending (although this could still be working fine when Time Slicing is used).

Regards.