Conversation
FreeRTOSConfig.h only defined configNUM_CORES, an older name from a pre-merge FreeRTOS SMP branch. The vendored FreeRTOS-Kernel SMP port and RP2040 port both check configNUMBER_OF_CORES (see FreeRTOS.h:96, portmacro.h), which silently defaulted to 1 without it being set. This codebase has been running single-core the entire time despite clearly intending dual-core -- main.c already has a multicore_launch_core1 call and an "on both cores" printf, both gated on the equally-stale portSUPPORT_SMP macro (also from the same pre-merge branch, not defined anywhere in this vendored kernel). Defining configNUMBER_OF_CORES correctly reactivates genuine dual-core execution: FreeRTOS-Kernel's own xPortStartScheduler() calls multicore_launch_core1() automatically once configNUMBER_OF_CORES == portMAX_CORE_COUNT, independent of main.c's now-dead portSUPPORT_SMP branch. Two more defines are newly required once real SMP is active and had to be added alongside it: configUSE_PASSIVE_IDLE_HOOK (FreeRTOS.h requires it when configNUMBER_OF_CORES > 1) and configUSE_CORE_AFFINITY (required by pico_flash's PICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMP, which needs a way to know how tasks are pinned before it can safely pause every core for a flash write). Testing scope: verified booting and running correctly on real dual-core hardware (both cores confirmed running via SWD, clean USB enumeration) on the UUT_FreeRTOS/USB_MIDI_Echo target. The other targets sharing this header were confirmed to still build, but have not been flashed/verified running on real dual-core hardware as part of this change -- worth a broader smoke test before relying on this for other targets, since this reactivates a code path (genuine SMP) that appears to have never actually executed in this codebase's history.
|
Reviewed this — root cause and fix location are right ( 1. Fix scope is incomplete — The catch: ( 2. Nit: alignment. 3. Nit: comment slightly inaccurate. The comment says 🤖 Generated with Claude Code |
Addresses AmeNote-Michael's review on PR midi2-dev#20 (midi2-dev#20, comment 5404943130): 1. ProtoZOA_Main/CMakeLists.txt's target_include_directories lists '.' before '../Common', and references '../Common' (not '../Common/include'), so #include "FreeRTOSConfig.h" in that target resolves to ProtoZOA_Main's own copy, not Common's -- confirmed directly. That copy still only defined configNUM_CORES, so the flagship ProtoZOA_Main firmware kept running single-core even after the original fix, despite main.c having the identical dead portSUPPORT_SMP/multicore_launch_core1 pattern described as this bug's symptom. Patched the same way as Common's copy: configNUMBER_OF_CORES, configUSE_PASSIVE_IDLE_HOOK, and configUSE_CORE_AFFINITY added (the latter two confirmed mandatory once configNUMBER_OF_CORES > 1, per FreeRTOS.h's own #error checks. Verified ProtoZOA_Main builds clean with this change (cmake --build . --target ProtoZOA_Main) -- not yet flashed to real hardware. 2. Fixed configUSE_PASSIVE_IDLE_HOOK's column alignment in Common's copy (was 2 columns off from every other #define in the file). 3. Expanded the configNUM_CORES retention comment (both copies) to also note pico-sdk's pico_async_context_freertos component gates SMP on configNUM_CORES specifically -- not currently linked into this repo, so not an active bug, but a future cleanup shouldn't delete the macro on the assumption that main.c's dead #if branch is the only consumer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> EOF )
|
Thanks for the thorough review -- confirmed the include-path claim directly (
|
|
Tested this on real ProtoZOA hardware (UUT board via the picoprobe on the Main Pico), flashing Build: compiles clean, all 8 firmware targets link ( Hardware behavior: flashed Traced the launch path under a debugger (breakpoints at That contrast (works when single-stepped/breakpointed, fails at full speed, always landing at the exact same bootROM address) points to a race condition in the SMP bring-up rather than a config problem — most likely FIFO/IRQ contention during the handoff window, since both cores install a I wasn't able to pin down the exact faulting instruction — further fine-grained single-stepping on the SMP target wedged my OpenOCD/picoprobe session (needed a physical power-cycle to recover), so I stopped rather than keep stressing the debug link. Given this is a genuinely hardware-reproducible issue with dual-core execution (the whole point of this PR), I'd want this run down further — or at minimum stress-tested more on a few different boards — before merging. Happy to share the exact GDB scripts I used if useful for reproducing. |
|
Reproduced this independently on our own ProtoZOA UUT ( Repro: 100% reproducible with a debugger fully detached during reset (separate fresh SWD connection afterward purely to inspect), which avoids the masking effect you noted. Consistently lands at Fix #1 tried -- ineffective. FreeRTOS-Kernel upstream commit Fix #2 tried (own hypothesis) -- also ineffective, but worth flagging separately. Localization -- this is not a bring-up race. Added a sentinel ladder (writes to a global counter array at fixed milestones, verified via disassembly to never clobber Ruled out an observer/probe artifact. Since the failure signature is only ever read by selecting Ruled out USB/TinyUSB correlation. Disabled the TinyUSB device task entirely (commented out Also ruled out: watchdog (confirmed disabled via direct One honest caveat: the "core1 is back in the bootROM Net: this looks like either something inside FreeRTOS-Kernel's RP2040 SMP scheduler internals below what we can localize further with sentinel instrumentation, or a board/silicon-level power-integrity margin issue outside firmware's reach -- not something either of our known fixes (or the ones we tried) resolves. Happy to share the instrumented 🤖 Generated with Claude Code |
Summary
FreeRTOSConfig.honly definedconfigNUM_CORES, which comes from an older pre-merge FreeRTOS SMP branch. The vendored FreeRTOS kernel and RP2040 SMP port both useconfigNUMBER_OF_CORESinstead (FreeRTOS.h,portmacro.h), so the system has been silently defaulting to single-core execution.This means the codebase has likely never actually been running in SMP mode, despite clearly intending to.
main.calready contains amulticore_launch_core1()call and an "on both cores" log message, but both are gated behindportSUPPORT_SMP, another leftover macro from the old SMP branch that isn't defined anywhere in the current kernel.Defining
configNUMBER_OF_CORESenables the actual SMP path. Once it's set toportMAX_CORE_COUNT, the RP2040 FreeRTOS port launches the second core fromxPortStartScheduler()automatically, so the deadportSUPPORT_SMPpath inmain.cis never used.Enabling SMP also requires two additional configuration options:
configUSE_PASSIVE_IDLE_HOOK, which FreeRTOS requires wheneverconfigNUMBER_OF_CORES > 1configUSE_CORE_AFFINITY, which is required bypico_flashwhenPICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMPis enabled so it can safely determine task placement before pausing all cores for flash operationsTesting
Verified on real dual-core RP2040 hardware using the
UUT_FreeRTOS/USB_MIDI_Echotarget. Both cores were confirmed running over SWD, and USB enumeration completed normally.The remaining targets that share this configuration were verified to build successfully, but were not flashed or tested on hardware as part of this change. Since this re-enables an SMP code path that appears to have never actually been exercised in this repository, I'd recommending we get more testing before merging.