Ok, it turns out I made a mistake when copy/pasting stuff into the minimal example CMakeLists.txt - I had namely forgotten to copy the `pico_minimize_runtime` line, which ended up being the culprit; so here is the full CMakeLists.txt which reproduces the error:
If you build the OP code with this, flash it on an RP2040 Pico and try to run it, there will not be any blinks - and if you try to connect with gdb, you will land here:
... which is exactly the problem described in OP.
So, the conclusion is: `pico_multicore` and `pico_minimize_runtime` are not good friends, and do not play nicely with each other. Why, I have absolutely no idea. I was so happy when I found `pico_minimize_runtime` even though it is undocumented (currently only 4 hits on Google, none of them with any explanation), because it was really working nice for me for a couple of months on my project, doing exactly what the name says with no side effects - whowouldathunkit that it would come back to bite me in the ass this hard?
By the way, I also did some build tests - and I found something surprising - for CMakeLists.txt
Damn, I wish I could have used pico_minimize_runtime with pico_multicore, but there you go ... maybe I'll have to rely on pico_stdlib to reduce my file size.
Anyways, one more research I've done: I've compared the operation of "bad" and "good" firmware in OP by watching the malloc_mutex variable as in gdb cannot watch variable - Could not insert hardware breakpoints, here are the results:
So, apparently the problem is due to the pico_minimize_runtime stripping away good initialization calls to runtime_init_mutex, at least ...
Code:
add_executable(blink_simple blink_simple.c)pico_set_binary_type(blink_simple copy_to_ram)# pull in common dependenciestarget_link_libraries(blink_simple#pico_stdlib#pico_multicore hardware_regs hardware_timer hardware_clocks hardware_i2c hardware_uart hardware_watchdog hardware_resets hardware_dma hardware_spi hardware_flash pico_platform pico_standard_link pico_crt0 pico_runtime_headers pico_bootrom pico_runtime pico_multicore #pico_stdlib #pico_printf)# create map/bin/hex/uf2 file etc.pico_add_extra_outputs(blink_simple)pico_minimize_runtime(blink_simple EXCLUDE ALL)target_link_options(blink_simple PRIVATE "LINKER:--print-memory-usage")# call pico_set_program_url to set path to example on github, so users can find the source for an example via picotoolexample_auto_set_url(blink_simple)Code:
For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from blink_simple.elf...Remote debugging using localhost:3333warning: multi-threaded target stopped without sending a thread-id, using first non-exited threadmutex_enter_blocking (mtx=mtx@entry=0x20002800 <malloc_mutex>) at /src/pico-sdk/src/common/pico_sync/mutex.c:7171 uint32_t save = spin_lock_blocking(mtx->core.spin_lock);(gdb) bt#0 mutex_enter_blocking (mtx=mtx@entry=0x20002800 <malloc_mutex>) at /src/pico-sdk/src/common/pico_sync/mutex.c:71#1 0x20000eec in __wrap_malloc (size=24) at /src/pico-sdk/src/rp2_common/pico_malloc/malloc.c:69#2 0x2000080e in alarm_pool_create_on_timer (timer=0x40054000, hardware_alarm_num=hardware_alarm_num@entry=0, max_timers=max_timers@entry=16) at /src/pico-sdk/src/common/pico_time/time.c:112#3 0x200001b6 in alarm_pool_create (max_timers=16, timer_alarm_num=0) at /src/pico-sdk/src/common/pico_time/include/pico/time.h:426#4 main () at /src/pico-examples/blink_simple/blink_simple.c:75So, the conclusion is: `pico_multicore` and `pico_minimize_runtime` are not good friends, and do not play nicely with each other. Why, I have absolutely no idea. I was so happy when I found `pico_minimize_runtime` even though it is undocumented (currently only 4 hits on Google, none of them with any explanation), because it was really working nice for me for a couple of months on my project, doing exactly what the name says with no side effects - whowouldathunkit that it would come back to bite me in the ass this hard?
By the way, I also did some build tests - and I found something surprising - for CMakeLists.txt
- multicore, no stdlib, no pico_minimize_runtime
Code:
Memory region Used Size Region Size %age Used FLASH: 39152 B 2 MB 1.87% RAM: 39732 B 256 KB 15.16% - multicore, stdlib, no pico_minimize_runtime - smaller, but works still
Code:
Memory region Used Size Region Size %age Used FLASH: 21668 B 2 MB 1.03% RAM: 22260 B 256 KB 8.49% - multicore, no stdlib, pico_minimize_runtime - even smaller; and it does NOT work
Code:
Memory region Used Size Region Size %age Used FLASH: 10784 B 2 MB 0.51% RAM: 10460 B 256 KB 3.99%
Damn, I wish I could have used pico_minimize_runtime with pico_multicore, but there you go ... maybe I'll have to rely on pico_stdlib to reduce my file size.
Anyways, one more research I've done: I've compared the operation of "bad" and "good" firmware in OP by watching the malloc_mutex variable as in gdb cannot watch variable - Could not insert hardware breakpoints, here are the results:
- They both get inited by hold_non_core0_in_bootrom() -> data_cpy(); both of them have malloc_mutex spin_lock = 0x0 here, but good one has owner = -1, bad one has owner = 0
- They are both again touched by hold_non_core0_in_bootrom() -> data_cpy(); and both of them get reset malloc_mutex to {core = {spin_lock = 0x0}, owner = 0 '\000'}
- After this, the bad does not stop/break anymore, but the good one is touched by platform_entry() -> runtime_init() -> runtime_run_initializers() -> runtime_init_mutex() -> mutex_init(<malloc_mutex>), where malloc_mutex becomes {core = {spin_lock = 0xd0000140}, owner = 0 '\000'
- Then, good one is again touched by platform_entry() -> runtime_init() -> runtime_run_initializers() -> runtime_init_mutex() -> mutex_init(<malloc_mutex>), where malloc_mutex becomes {core = {spin_lock = 0xd0000140}, owner = -1 '\377'}
- Then, good one is touched by alarm_pool_create() -> alarm_pool_create_on_timer() -> `__wrap_malloc()` -> mutex_enter_blocking(<malloc_mutex>), where malloc_mutex becomes {core = {spin_lock = 0xd0000140}, owner = 0 '\000'} (note, bad one does not even react here even if it loops here)
- Then, good one is touched by alarm_pool_create() -> alarm_pool_create_on_timer() -> `__wrap_malloc()` -> mutex_exit(<malloc_mutex>), where malloc_mutex becomes {core = {spin_lock = 0xd0000140}, owner = -1 '\377'}
- Then, for good one, previous two steps (mutex_enter_blocking / mutex_exit) are repeated (same stack), with same malloc_mutex results
So, apparently the problem is due to the pico_minimize_runtime stripping away good initialization calls to runtime_init_mutex, at least ...
Statistics: Posted by sdbbs — Sun May 04, 2025 9:47 pm