Multicore and FreeRTOS: arduino-pico API, FreeRTOS from a Tools menu
Multicore API. Sketches use the second RP2040 core the way the arduino-pico core (Earle Philhower) does: defining setup1() and loop1() starts core 1, which runs them at the same time as setup() and loop() on core 0. The rp2040 object gives rp2040.fifo (push, push_nb, pop, pop_nb, available), idleOtherCore(), resumeOtherCore(), restartCore1(), cpuid(), f_cpu() and the heap sizes. The FIFO is a pair of pico-sdk queues in RAM, one per direction, not the hardware SIO FIFO: that is left to the SDK's multicore lockout (used by idleOtherCore()) and to FreeRTOS.
FreeRTOS on/off. Tools > Operating System chooses None (default) or FreeRTOS (SMP). FreeRTOS selects a second prebuilt SDK bundle, platform/system/<board>_freertos/, built by sdk-builder/ with PHYDUINO_OS=freertos: the pico-sdk compiled with the FreeRTOS RP2040 port's SDK hooks, plus the kernel (heap_3), configured by sdk-builder/freertos/FreeRTOSConfig.h. Its compile_flags.txt defines PHYDUINO_FREERTOS=1, which the core tests.
Scheduling. SMP on both cores. setup()/loop() is a task pinned to core 0 and setup1()/loop1() a task pinned to core 1, each with an 8 KB stack at priority 1 (osPriorityNormal with CMSIS-RTOS2, ADR 010). Other tasks may run on either core or be pinned. delay() blocks the task; yield() lets tasks of the same priority run.
Kernel source. The Raspberry Pi fork of FreeRTOS-Kernel, as the submodule extern/FreeRTOS-Kernel.
arduino-pico compatibility. Most RP2040 multicore tutorials and course material use setup1()/loop1() and rp2040.fifo; students can use them unchanged. An own API would be simpler to document but would cut them off from that material, and the SDK alone (pico/multicore.h) gives no sketch structure.
A menu and a second bundle, not a library. For SDK mutexes, semaphores, queues and sleep_ms() to block a task instead of spinning, every SDK source must be compiled with the port's adapter header (PICO_CONFIG_RTOS_ADAPTER_HEADER), and the size of SDK lock types changes with it. A library compiled with the sketch cannot do that to the prebuilt libpico.a (ADR 002), so FreeRTOS needs its own build of the SDK. A menu also makes the choice explicit: a sketch that includes FreeRTOS.h without it gets an error saying which menu to set (a stub header in the plain bundle), not a link error.
SMP. One scheduler for both cores is what FreeRTOS on the RP2040 is normally taught with, uses both cores without the sketch deciding where each task runs, and still allows pinning. Pinning loop() and loop1() keeps the multicore API meaning the same in both modes.
Raspberry Pi fork. The fork is what the pico-sdk examples use and already has the RP2350 Arm and RISC-V ports needed for v0.2.0 and v0.2.1.
A second committed bundle (about 10 MB in the repository, also in the release zip), regenerated whenever the SDK, TinyUSB, the kernel or FreeRTOSConfig.h changes. The kernel configuration is fixed at bundle build time: a sketch cannot change it. The fork has no release tags, so the submodule is pinned to a commit. Sketches must not use the SDK's multicore_fifo_*() functions or multicore_lockout_victim_init() on a core the core already set up, since the hardware FIFO belongs to the lockout and to FreeRTOS. The PC-side tests cover only the no-OS build; FreeRTOS behaviour needs hardware tests (checklist 28-34). Peripherals other than USB Serial and the Serial1/Serial2 receive buffers are not locked: each should be used from one core or task at a time.