pico_multicore breaks BTstack TLV persistence #2725

Open
opened 2025-11-21 10:59:43 -06:00 by diegoparrilla · 10 comments
diegoparrilla commented 2025-11-21 10:59:43 -06:00 (Migrated from github.com)

I think I’ve found a reproducible combination that breaks TLV persistence in BTstack on RP2040 when using pico-sdk 2.2.0.
This can make developers struggle to locate the root cause, so I’m documenting it here.

The key point: just linking pico_multicore is enough to break TLV persistence, even if no multicore functions are called.

How to reproduce

In CMakeLists.txt:

# Link libraries required for the project
target_link_libraries(${PROJECT_NAME} PRIVATE
    ${LINK_LIBRARIES}
    pico_multicore
    <other libraries...>
)

To ensure the TLV does not overlap with other flash sections (only BT_TLV matters here):

MEMORY
{
    FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 1152k
    RAM(rwx) : ORIGIN =  0x20000000, LENGTH = 256k
    SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
    SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k
    CONFIG_FLASH(rwx): ORIGIN = 0x101DE000, LENGTH = 120K
    GLOBAL_LOOKUP_FLASH(rwx): ORIGIN = 0x101FC000, LENGTH = 4K
    GLOBAL_CONFIG_FLASH(rwx): ORIGIN = 0x101FD000, LENGTH = 4K
    BT_TLV(rwx): ORIGIN = 0x101FE000, LENGTH = 8K
}

I’m using the Bluepad32 library, but the issue is reproducible using the BTstack included in pico-sdk.

Observed behavior

With this setup, any BTstack API call that must persist data in the TLV fails silently.
Nothing is stored.

A clear symptom: link keys are not persisted after pairing a Bluetooth keyboard/mouse, so the device cannot reconnect after a power cycle.

Key findings

  • If I remove pico_multicore, TLV persistence works as expected.
  • If I add pico_multicore but also launch code on Core 1 using multicore_launch_core1(), TLV persistence also works.

So the failure only occurs in the specific situation where:

pico_multicore is linked
AND core1 is NOT launched

This suggests initialization side effects in pico_multicore that interfere with flash operations BTstack depends on.

My project (still WIP): https://github.com/sidecartridge/rp2-atarist-rpikb

Hope this helps identify the root cause, or at least warns other developers about this combination.

I think I’ve found a reproducible combination that breaks TLV persistence in BTstack on RP2040 when using **pico-sdk 2.2.0**. This can make developers struggle to locate the root cause, so I’m documenting it here. The key point: **just linking `pico_multicore` is enough to break TLV persistence**, even if no multicore functions are called. ### **How to reproduce** In `CMakeLists.txt`: ```cmake # Link libraries required for the project target_link_libraries(${PROJECT_NAME} PRIVATE ${LINK_LIBRARIES} pico_multicore <other libraries...> ) ``` To ensure the TLV does not overlap with other flash sections (only `BT_TLV` matters here): ```ld MEMORY { FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 1152k RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k CONFIG_FLASH(rwx): ORIGIN = 0x101DE000, LENGTH = 120K GLOBAL_LOOKUP_FLASH(rwx): ORIGIN = 0x101FC000, LENGTH = 4K GLOBAL_CONFIG_FLASH(rwx): ORIGIN = 0x101FD000, LENGTH = 4K BT_TLV(rwx): ORIGIN = 0x101FE000, LENGTH = 8K } ``` I’m using the **Bluepad32** library, but the issue is reproducible using the BTstack included in pico-sdk. ### **Observed behavior** With this setup, any BTstack API call that must persist data in the TLV fails silently. Nothing is stored. A clear symptom: **link keys are not persisted** after pairing a Bluetooth keyboard/mouse, so the device cannot reconnect after a power cycle. ### **Key findings** * If I **remove `pico_multicore`**, TLV persistence works as expected. * If I **add `pico_multicore` but also launch code on Core 1** using `multicore_launch_core1()`, TLV persistence also works. So the failure only occurs in the specific situation where: ``` pico_multicore is linked AND core1 is NOT launched ``` This suggests initialization side effects in `pico_multicore` that interfere with flash operations BTstack depends on. My project (still WIP): [https://github.com/sidecartridge/rp2-atarist-rpikb](https://github.com/sidecartridge/rp2-atarist-rpikb) Hope this helps identify the root cause, or at least warns other developers about this combination.
peterharperuk commented 2025-11-21 11:33:57 -06:00 (Migrated from github.com)

What's VLT? pico_btstack uses flash_safe_execute. There's some advice in the SDK about using pico_multicore. You might need to set PICO_FLASH_ASSUME_CORE0_SAFE=1

See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_flash/include/pico/flash.h#L12

What's VLT? pico_btstack uses flash_safe_execute. There's some advice in the SDK about using pico_multicore. You might need to set PICO_FLASH_ASSUME_CORE0_SAFE=1 See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_flash/include/pico/flash.h#L12
diegoparrilla commented 2025-11-21 11:55:13 -06:00 (Migrated from github.com)

Sorry, TLV (fixed): https://bluekitchen-gmbh.com/storing-link-keys-in-flash-memory/

I use the PICO_FLASH_ASSUME_COREx_SAFE in my code for Core 1, and I previously tested the following combinations (I chased the issue for a while):

  1. No PICO_FLASH_ASSUME_CORE0_SAFE or PICO_FLASH_ASSUME_CORE1_SAFE macros set
  2. PICO_FLASH_ASSUME_CORE1_SAFE set to 1, PICO_FLASH_ASSUME_CORE0_SAFE not set
  3. PICO_FLASH_ASSUME_CORE1_SAFE set to 1, PICO_FLASH_ASSUME_CORE0_SAFE set to 1

The problem comes from just linking the library. PICO_FLASH_ASSUME_COREx_SAFE does not affect the outcome in this case.

Sorry, TLV (fixed): https://bluekitchen-gmbh.com/storing-link-keys-in-flash-memory/ I use the PICO_FLASH_ASSUME_COREx_SAFE in my code for Core 1, and I previously tested the following combinations (I chased the issue for a while): 1. No PICO_FLASH_ASSUME_CORE0_SAFE or PICO_FLASH_ASSUME_CORE1_SAFE macros set 2. PICO_FLASH_ASSUME_CORE1_SAFE set to 1, PICO_FLASH_ASSUME_CORE0_SAFE not set 3. PICO_FLASH_ASSUME_CORE1_SAFE set to 1, PICO_FLASH_ASSUME_CORE0_SAFE set to 1 The problem comes from just linking the library. PICO_FLASH_ASSUME_COREx_SAFE does not affect the outcome in this case.
peterharperuk commented 2025-11-21 12:25:32 -06:00 (Migrated from github.com)

Thanks. Did you try setting PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT to zero?

Thanks. Did you try setting PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT to zero?
diegoparrilla commented 2025-11-21 12:36:46 -06:00 (Migrated from github.com)

Yes. No luck.

Yes. No luck.
Loc15 commented 2025-11-28 22:25:03 -06:00 (Migrated from github.com)

I can confirm this issue. On debug build I get assertion "false" failed: file ".../pico-sdk/src/rp2_common/pico_flash/flash.c", line 190, function: default_enter_safe_zone_timeout_ms using multicore (It works fine without it). On release build, it fails to store device using TLV persistence using multicore too.

I can confirm this issue. On debug build I get `assertion "false" failed: file ".../pico-sdk/src/rp2_common/pico_flash/flash.c", line 190, function: default_enter_safe_zone_timeout_ms` using multicore (It works fine without it). On release build, it fails to store device using TLV persistence using multicore too.
giftzwerg73 commented 2025-12-21 16:34:07 -06:00 (Migrated from github.com)

I came across this issue too.
Linking pico_multicore but not calling multicore_launch_core1() before starting BTstack code resulted in authentication errors when trying to connect over bluetooth to the pico w.
Starting core1 with some dummy code before running BTstack code and connecting over bluetooth works fine.
Thanks diegoparrilla for pointing me in the right direction.

I came across this issue too. Linking pico_multicore but not calling multicore_launch_core1() before starting BTstack code resulted in authentication errors when trying to connect over bluetooth to the pico w. Starting core1 with some dummy code before running BTstack code and connecting over bluetooth works fine. Thanks diegoparrilla for pointing me in the right direction.
peterharperuk commented 2026-06-12 03:51:52 -05:00 (Migrated from github.com)

This is quite extensively discussed here https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_flash/include/pico/flash.h#L17

Maybe we need to add a note pico_btstack to take notice of this when using freertos?

You can set PICO_FLASH_ASSUME_CORE1_SAFE=1 if nothing is running on core 1. Otherwise, it's more complicated...

This is quite extensively discussed here https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_flash/include/pico/flash.h#L17 Maybe we need to add a note pico_btstack to take notice of this when using freertos? You can set PICO_FLASH_ASSUME_CORE1_SAFE=1 if nothing is running on core 1. Otherwise, it's more complicated...
kilograham commented 2026-06-16 20:10:36 -05:00 (Migrated from github.com)

Sorry, TLV (fixed): https://bluekitchen-gmbh.com/storing-link-keys-in-flash-memory/

I use the PICO_FLASH_ASSUME_COREx_SAFE in my code for Core 1, and I previously tested the following combinations (I chased the issue for a while):

1. No PICO_FLASH_ASSUME_CORE0_SAFE or PICO_FLASH_ASSUME_CORE1_SAFE macros set

2. PICO_FLASH_ASSUME_CORE1_SAFE set to 1, PICO_FLASH_ASSUME_CORE0_SAFE not set

3. PICO_FLASH_ASSUME_CORE1_SAFE set to 1, PICO_FLASH_ASSUME_CORE0_SAFE set to 1

The problem comes from just linking the library. PICO_FLASH_ASSUME_COREx_SAFE does not affect the outcome in this case.

I don't understand how you could hit the assert mentioned above if the correct PICO_FLASH_ASSUME_COREx_SAFE is 1, as it should never go down that code path. I just want to double check that regardless of everything else

> Sorry, TLV (fixed): https://bluekitchen-gmbh.com/storing-link-keys-in-flash-memory/ > > I use the PICO_FLASH_ASSUME_COREx_SAFE in my code for Core 1, and I previously tested the following combinations (I chased the issue for a while): > > 1. No PICO_FLASH_ASSUME_CORE0_SAFE or PICO_FLASH_ASSUME_CORE1_SAFE macros set > > 2. PICO_FLASH_ASSUME_CORE1_SAFE set to 1, PICO_FLASH_ASSUME_CORE0_SAFE not set > > 3. PICO_FLASH_ASSUME_CORE1_SAFE set to 1, PICO_FLASH_ASSUME_CORE0_SAFE set to 1 > > > The problem comes from just linking the library. PICO_FLASH_ASSUME_COREx_SAFE does not affect the outcome in this case. I don't understand how you could hit the assert mentioned above if the _correct_ PICO_FLASH_ASSUME_COREx_SAFE is 1, as it should never go down that code path. I just want to double check that regardless of everything else
elrir01 commented 2026-08-04 18:28:23 -05:00 (Migrated from github.com)

I had the same experience as @Loc15, same assertion failed. I'm using FreeRTOS and btstack on SDK 2.2.0 but for me the workarounds don't work. On debug build it gives assertion "false" failed: file ".../Apps/pico/old-sdk/pico-sdk/src/rp2_common/pico_flash/flash.c", line 179, function: default_enter_safe_zone_timeout_ms and on release it just silently fails. With the new SDK, the 2.3.0 version, and the same code, it works fine but I cannot authenticate correctly with my phone or other device and the keys are the same through the flashing of old and new firmware because the TLV memory section is not touched. As I mentioned in #3106.

I had the same experience as @Loc15, same assertion failed. I'm using FreeRTOS and btstack on SDK 2.2.0 but for me the workarounds don't work. On debug build it gives `assertion "false" failed: file ".../Apps/pico/old-sdk/pico-sdk/src/rp2_common/pico_flash/flash.c", line 179, function: default_enter_safe_zone_timeout_ms` and on release it just silently fails. With the new SDK, the 2.3.0 version, and the same code, it works fine but I cannot authenticate correctly with my phone or other device and the keys are the same through the flashing of old and new firmware because the TLV memory section is not touched. As I mentioned in #3106.
peterharperuk commented 2026-08-18 07:48:01 -05:00 (Migrated from github.com)

I'm going to assume this is fixed by https://github.com/raspberrypi/pico-sdk/pull/3019
i.e. you will not see an assert in 2.3.0. There are other unrelated issues covered in https://github.com/raspberrypi/pico-sdk/issues/3106
I will add some logging if flash_safe_execute fails so it's a bit more obvious, and add a test for this.

I'm going to assume this is fixed by https://github.com/raspberrypi/pico-sdk/pull/3019 i.e. you will not see an assert in 2.3.0. There are other unrelated issues covered in https://github.com/raspberrypi/pico-sdk/issues/3106 I will add some logging if flash_safe_execute fails so it's a bit more obvious, and add a test for this.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk#2725
No description provided.