FreeRTOS on Raspberry Pi Pico: Audit Exception Handlers on the Correct Core

A linked FreeRTOS handler symbol does not prove that the running processor's exception vector points to it. On a Raspberry Pi Pico integration, handler installation can depend on build configuration and on which core executes the registration.

When tasks stop switching after another SDK component is added, inspect exception ownership before rewriting application delays. This article examines the RP2040 port in FreeRTOS V11.3.1 and the exception API in Pico SDK 2.3.1. It does not claim that this particular version pairing has been built or tested here.

RP2040 FreeRTOS exception audit checks compiled installation path, core-specific vector queries and competing initialization.
Original conceptual engineering diagram. Proposed review method, not a measured result.

Start with the port's selected installation path

The tagged RP2040 port conditionally installs exception handlers when `configUSE_DYNAMIC_EXCEPTION_HANDLERS` is enabled. In its multicore path, SysTick setup and dynamic registration occur on the configured primary tick core, while PendSV and SVC registration occur in each core's scheduler-start path. The single-core path installs the three handlers on the starting core.

The source also retains an SVC handler for backward compatibility even though that handler is no longer used for starting the first task. Avoid importing a generic Cortex-M explanation that assumes every FreeRTOS port starts tasks through an identical SVC sequence.

For the actual build, resolve the preprocessor choice first. If dynamic installation is disabled, inspect the build's alternative vector arrangement rather than expecting a registration call that was compiled out. A map file answers which functions exist; vector inspection answers which function the exception will reach.

Inspect the executing core's vector table

The SDK exception API states that its operations affect the executing core. It provides a vector-handler query and describes exclusive registration constraints: a second exclusive installation without restoration, or an attempt to replace a strong link-time handler through that API, is not an ordinary supported override.

This makes core identity part of the evidence. A diagnostic query made only from core zero cannot stand in for the vector table used by core one. Record the core associated with each observation, together with the relevant initialization stage.

In a hypothetical failure, a helper library registers its own SysTick handler while an application assumes the kernel owns that exception. Adding more calls to either initialization routine does not resolve the ownership conflict. Find the competing installation and decide which component is responsible for the exception in this design.

Compare before and after initialization

Use a minimal build as a reference, then add the suspected component. Inspect the relevant vector entries at a controlled point before scheduler startup and, where practical, from the appropriate core after startup. Correlate the observed handler addresses with the exact linked image.

Do not repair a conflict by casually restoring handlers while tasks are running. That changes a scheduler dependency at runtime and can invalidate the execution state being diagnosed. Correct initialization ownership in a development build, then repeat the test from reset.

If a handler address is correct but progress still fails, inspect whether the intended interrupt is occurring and whether its source is configured. Vector ownership and event generation are separate questions. A valid PendSV entry cannot compensate for a system that never requests the expected context switch.

Keep the conclusion specific to the target

This article's port analysis is for RP2040. An RP2350 ARM build or a RISC-V build must be checked against its own port; matching function names are not evidence of matching exception behavior. Even within RP2040, single-core and multicore configurations create different observations to verify.

The useful diagnosis is precise: which component owns each exception, how that ownership is installed, and on which core it applies. Once those facts are established, application-level timing and scheduling tests have a reliable foundation instead of depending on an assumed vector layout.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *