Skip to content

feat(profiling): flag-gated ISR cycle/CPU-load harness for F051#4

Draft
dakejahl wants to merge 1 commit into
mainfrom
f051-profiling
Draft

feat(profiling): flag-gated ISR cycle/CPU-load harness for F051#4
dakejahl wants to merge 1 commit into
mainfrom
f051-profiling

Conversation

@dakejahl

@dakejahl dakejahl commented Jun 15, 2026

Copy link
Copy Markdown

Summary

A measurement-only harness to quantify per-ISR cycle cost and CPU load on the F051, gated behind PROFILE_ISR so production builds stay byte-identical. Used to validate the f051-perf optimizations (#1) and to confirm the active-phase demag work (#2) won't be CPU-limited at high eRPM.

Problem

The F051 is a Cortex-M0, which has no DWT->CYCCNT and no ITM/SWO, so the usual cycle-accurate trace profiling is physically unavailable and SWD alone gives only halting and crude PC sampling. We still need real-hardware numbers for ISR execution time and CPU headroom to know whether the demag work fits the cycle budget.

Solution

Drive both canonical M0 methods from one instrumentation point. A GPIO marker pin is held high while any instrumented ISR runs, so the wire shows aggregate ISR (CPU) load on a logic analyzer. TIM17 — otherwise unused on the F051, its counter is never even enabled — is repurposed at PSC=0 as a 48 MHz free-running counter (1 tick per core cycle), feeding per-ISR last/max/sum cycle counts that are read back over SWD (via scripts/profile_swd.py) or telemetry. The four hot ISRs are wrapped: comparator zero-cross, the 20 kHz control loop, DShot decode, and TIM14. Disabled it compiles to nothing (22200 B, baseline); enabled it is +236 B. Cherry-pick onto a perf or feature branch to measure that branch.

How to use

SWD-only, no logic analyzer needed.

  1. OpenOCD ≥ 0.11: sudo apt install openocd (0.12; required for read_memory and ST-Link V3).
  2. Wire the probe to the powered, running ESC: SWDIO→PA13, SWCLK→PA14, GND→GND, and on ST-Link V3 also VTREF/VCC→ESC 3.3V (a sense reference — it does not power the board). Leave NRST disconnected so attaching doesn't reset.
  3. Build & run: enable PROFILE_ISR in Inc/profiling.h, rm obj/*.elf (the Makefile doesn't track header edits), rebuild, flash, spin the motor, then in two terminals:
    openocd -f Mcu/f051/openocd.cfg          # init attaches without halting; motor keeps running
    scripts/profile_swd.py obj/AM32_ARK_4IN1_F051_2.20.elf
    
  4. Interpret: CPU% (from the cycle sum) is throughput — total < 100% with margin at max eRPM means not throughput-limited; comp_zc scales with eRPM while the 20 kHz row is fixed. max(us) is worst-case single-invocation latency — the comparator ISR must finish inside the commutation interval at max eRPM. Reset prof_cyc_max between operating points (mww <&prof_cyc_max> 0) or reboot.

Optional: set PROFILE_GPIO_PORT/PIN to a free pad for an aggregate CPU-load marker on a logic analyzer.

Cortex-M0 has no DWT->CYCCNT and no ITM/SWO, so ISR cost is measured two
canonical ways, both driven from one instrumentation point and gated
behind PROFILE_ISR (off by default, production builds stay byte-identical):

- GPIO marker (optional pin) held high while an instrumented ISR runs,
  for aggregate CPU load on a logic analyzer / scope.
- TIM17 repurposed at PSC=0 as a 48 MHz free-running counter (1 tick per
  core cycle); per-ISR last/max/sum cycle counts land in prof_* arrays
  read over SWD or telemetry. TIM17 is otherwise unused on the F051.

scripts/profile_swd.py reads those counters live through a running OpenOCD
(non-halting, safe while the motor spins) and prints per-ISR CPU load,
average/worst-case microseconds, and call rate.

Wraps the four hot ISRs: comparator zero-cross (ADC1_COMP), 20 kHz control
loop (TIM6), DShot decode (EXTI4_15), and TIM14. Cherry-pick onto a
perf/feature branch to compare CPU headroom at a given eRPM.
@dakejahl dakejahl marked this pull request as draft June 23, 2026 05:08
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