Fix PWM motor-role double-counting in pwmEnsureEnoughtMotors() - #11787
Fix PWM motor-role double-counting in pwmEnsureEnoughtMotors()#11787sensei-hacker wants to merge 3 commits into
Conversation
Pass 1 counted a shared-timer motor-only group of n outputs as 2n-1 instead of n: pwmClaimTimer() force-syncs every sibling on the same physical timer as soon as the first one is visited, and the loop had no guard against re-counting a sibling that was already promoted by that broadcast when it reached its own turn later in the same pass. The inflated count made pass 2 more conservative than it should be, silently demoting a later AUTO output from motor to servo with no warning. Triggerable both by target.c declaring 2+ TIM_USE_MOTOR channels on one timer (unconditional at boot) and by the ordinary runtime timer_output_mode MOTORS override exposed in Configurator's Mixer tab. Adds a per-physical-timer dedup guard, matching the de-duplication pass 2 already has via its !TIM_IS_MOTOR_ONLY(...) check.
|
ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing |
PR Summary by QodoFix PWM motor-role double-counting in pwmEnsureEnoughtMotors()
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo
1.
|
…oading actions/download-artifact)
Pass 1's dedup guard counted a shared-timer motor-only group as "1 + pads changed by pwmClaimTimer()", but the claim returns 0 when the whole group is already TIM_USE_MOTOR, so such a group contributed 1 instead of its true size n. The undercount made pass 2 promote extra AUTO outputs to motors, claiming whole timers as motor-only and silently removing servo-capable outputs. Count every non-conflicted motor-only pad on the timer after the claim sync instead: post-claim the whole group shares one role, so this is the group's true size in both shapes (mixed 1 motor-only + n-1 AUTO, and all-motor-only n pads).
|
RAM / Flash usage vs. base branch — commit
|
|
Test firmware build ready — commit Download firmware for PR #11787 245 targets built. Find your board's
|
|
Closing: the 9.1 backport is not being pursued — the 9.1 line will be left as-is. Note that maintenance-10.x never had this defect (its pwmBuildTimerOutputList rewrite eliminated the double-counting shape), and it already carries the firmware-authoritative output-assignment MSP API (0x210E/0x210F), so no 9.1-era JS/C algorithm duplication fix is needed there. |
Summary
Pass 1 of
pwmEnsureEnoughtMotors()insrc/main/drivers/pwm_mapping.covercounts motor-only outputs that share a physical timer: a group ofnshared-timer outputs that are already motor-only at the start of pass 1 inflates themotorOnlyOutputscounter by2n - 1instead ofn.pwmClaimTimer()force-syncs every output sharing a physical timer as soon as the first one is visited. Each sibling then independently satisfiesTIM_IS_MOTOR_ONLYwhen the loop reaches its own index later in the same pass, and gets counted again — pass 1 has no guard against this, unlike pass 2's!TIM_IS_MOTOR_ONLY(...)check for the same class of re-visit.The inflated count makes pass 2 more conservative than it should be when deciding whether to promote remaining
AUTOoutputs to motors. This can silently demote an output the user configured as a motor down to servo, with no error, log message, or other indication.Trigger paths
Both hit an ordinary user, not just unusual
target.cauthoring:target.cdeclares 2+ channels sharing one physical timer as plainTIM_USE_MOTOR(notTIM_USE_OUTPUT_AUTO) — hit at boot regardless of user action. A survey of the target tree found 34 targets with this pattern (e.g.KROOZX,SPRACINGF7DUAL,IFLIGHT_BLITZ_F7_AIO).timer_output_mode <timer> MOTORSoverride, exposed in Configurator's Mixer tab, applied to a physical timer serving 2+ outputs.timerHardwareOverride()applies the override before theTIM_IS_MOTOR_ONLYcheck, so an override-forced group hits the same inflation as a compile-time-declared one.Fix
Adds a per-physical-timer
timerCounted[]dedup guard to pass 1, so each physical timer's motor-only group is counted exactly once regardless of how many of its channels get individually re-visited later in the same pass — mirroring the de-duplication pass 2 already has.Branch scope
Confirmed present on
release/9.1. Confirmed not present onmaintenance-10.x— that branch'spwmEnsureEnoughtMotors()was already replaced by a unifiedpwmBuildTimerOutputList()(direct per-pad assignment, no separate inflatable counter) as an apparent unintentional side effect of unrelated refactor work, so nomaintenance-10.xfix is needed.Testing
cmake -DSITL=ON,make SITL.elf) compiles cleanly with no new warnings.simulate_pwm_roles.pyin the INAV harness tooling, not part of this PR) — before the fix, a synthetic 2-channel shared-timer group forced toMOTORSinflated the count to 3 and silently demoted a third output atmotorCount=3; after the fix, the group counts correctly as 2 and the third output promotes as expected.Related Issues
None filed yet — found while debugging PWM/DSHOT output setup on a custom target.