Skip to content

Comments

pid/filter: FAST_CODE annotations and RC command caching#11357

Open
sensei-hacker wants to merge 2 commits intoiNavFlight:maintenance-9.xfrom
sensei-hacker:perf/pid-fast-code-and-cache
Open

pid/filter: FAST_CODE annotations and RC command caching#11357
sensei-hacker wants to merge 2 commits intoiNavFlight:maintenance-9.xfrom
sensei-hacker:perf/pid-fast-code-and-cache

Conversation

@sensei-hacker
Copy link
Member

@sensei-hacker sensei-hacker commented Feb 22, 2026

Summary

Two performance improvements to the PID hot path, applied in order:

  1. pid/filter: add FAST_CODE to pidController callees — adds FAST_CODE to functions called from pidController() so they land in ITCM (fast RAM) on STM32 targets, eliminating flash-to-ITCM trampoline jumps at 1 kHz
  2. fc/pid: avoid recomputing values that change at lower rates — caches RC command values and pidSumLimit so they are only recalculated when new RX data arrives (~50 Hz) rather than every PID loop iteration (~1000 Hz). Also gates failsafeUpdateRcCommandValues() behind the same new-data check

Files Changed

  • src/main/common/filter.c — FAST_CODE
  • src/main/common/maths.c — FAST_CODE
  • src/main/fc/fc_core.c — FAST_CODE, RC command caching
  • src/main/flight/pid.c — FAST_CODE, RC command caching
  • src/main/flight/smith_predictor.c — FAST_CODE

Testing

  • Compiles cleanly for SITL ✅
  • STM32 target builds without linker errors
  • No regressions in PID behavior or RC response

sensei-hacker and others added 2 commits February 22, 2026 15:19
pidController is FAST_CODE. Its callees that lacked FAST_CODE created
SRAM veneers (trampolines from ITCM to flash) on every call. Annotate
each callee that was audited as genuinely hot:

  pid.c:
    pTermProcess, dTermProcess, applyItermLimiting,
    pidApplySetpointRateLimiting, checkItermLimitingActive,
    checkItermFreezingActive, pidRcCommandToAngle, pidRcCommandToRate

  smith_predictor.c: applySmithPredictor

  filter.c: pt1ComputeRC (static; called from FAST_CODE pt1FilterApply4)

  maths.c: constrain, constrainf, scaleRangef
    (called from the pid.c functions above; candidates for static inline
    in a future refactor, but FAST_CODE resolves the veneer for now)

  fc_core.c: getAxisRcCommand

Functions removed from FAST_CODE where no FAST_CODE caller existed
(sin_approx, cos_approx, fast_fsqrtf, failsafeShouldApplyControlInput)
were never added in this tree; no net change for those.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two independent optimisations for the main PID loop:

rcCommand caching (fc_core.c)
  getAxisRcCommand() and failsafeUpdateRcCommandValues() are now gated
  on isRXDataNew so they only run when the RX task delivers a fresh
  frame (~50 Hz) instead of every PID cycle (1 kHz / multirotor rate).
  rcCommand[] is updated from a small cache on every cycle so the rest
  of the code is unaffected.

pidSumLimit precomputation (pid.c)
  getPidSumLimit() returns 400 or 500 based on vehicle type and axis —
  values that are constant for the lifetime of a flight. Add a
  pidSumLimit field to pidState_t, initialise it once in pidInit(), and
  replace the two hot-path calls in pidApplyFixedWingRateController and
  pidApplyMulticopterRateController with a struct field read.
  getPidSumLimit() is retained for pid_autotune.c (not hot).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant