Skip to content

pwm_mapping: skip timer outputs on UART1's pins when UART1 has a function besides MSP - #12131

Open
MrScothh wants to merge 1 commit into
iNavFlight:maintenance-10.xfrom
MrScothh:fix/pwm-uart1-conflict
Open

MrScothh wants to merge 1 commit into
iNavFlight:maintenance-10.xfrom
MrScothh:fix/pwm-uart1-conflict

Conversation

@MrScothh

@MrScothh MrScothh commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Problem

checkPwmTimerConflicts() keeps motor and servo outputs off the pins of a serial port that has a function, but it checks UART2 to UART8 and the soft serial ports, not UART1. Three targets have timer outputs on UART1's pins:

Target UART1 pins Pads
NEXUSX PB6, PB7 AUX, SBUS
VANTAC_RF007 PB6, PB7 AUX, SBUS
SPRACINGF7DUAL PA9, PA10 PWM 3, PWM 4

When UART1 has a function and the mixer needs enough outputs to reach those pads, both claim the pin, and whichever is set up last keeps it. A function opened after the outputs, such as the receiver, GPS or telemetry, takes the pin back: the motor or servo the Configurator shows on that pad drives nothing. One opened before them, such as DJI HD OSD or SmartPort master, loses it and doesn't work. On NEXUSX the pad labelled SBUS is UART1 RX, so a receiver wired where the label says, with 9 outputs in the mixer, leaves S9 dead without any warning.

Change

UART1 is checked like UART2 to UART8, with one difference: MSP alone doesn't count. On a board with a USB VCP, UART1 gets MSP by default unless the target gives it another function (pgResetFn_serialConfig(), and some targets' targetConfiguration()). MSP opens before the outputs, so it has always given these pins up to them: on that default, AUX/SBUS and PWM 3/4 work as outputs today. Counting MSP would remove those outputs from every default configuration, and on SPRACINGF7DUAL PWM 3 and 4 are the only servo pads by default. That's probably why UART1 was left out when the check was written (#4705, 2019), two years after the MSP default (74e786a, 2017).

So the outputs are kept with UART1 on MSP alone or off, and skipped as soon as UART1 gets any other function. The code can't tell the default MSP from MSP chosen on purpose, so a device that talks MSP on UART1 still loses these pins to the outputs, as today. As on UART2 to UART8, a function that uses one pin only (an SBUS receiver is receive-only) takes both pads. That is the one setup that works today and changes on update: an SBUS receiver on the SBUS pad with 8 outputs in the mixer, the last one on AUX. After this the mixer is one output short and the board reports it and won't arm, until the mixer or the port changes.

On NEXUSX this makes the table in docs/boards/NEXUSX.md hold for every function except MSP. @Raffi1202 noticed in #11925 that the firmware didn't do what the page says; that PR changes the page to the current behaviour, and the AUX/SBUS rows would need "except MSP" with this one. Happy to adjust either way.

Testing

  • MAMBAF722_2022B with two test-only timer outputs added on its UART1 pins (PB6/PB7, after S8), a mixer with 8 motors and 2 servos, assignment read back from the usage flags of MSP2_INAV_OUTPUT_MAPPING_EXT2:
UART1 maintenance-10.x this PR
receiver (serial RX) S9, S10 servos on UART1's pins S9, S10 unassigned
MSP only (the default) S9, S10 servos S9, S10 servos, unchanged
  • All 237 targets build. Against maintenance-10.x: flash +48 to +96 B (NEXUSX, VANTAC_RF007, SPRACINGF7DUAL +48 B, MATEKF722SE +64 B), RAM and ITCM unchanged on KAKUTEF7, KAKUTEF7HDV, MATEKF405SE, MATEKF722SE, MATEKH743, TBS_LUCID_H7_WING.
  • Unit tests: 620 of 620 pass. pwm_mapping.c is not in the host build, so there is no unit test of the check itself.

Not tested on a NEXUSX, VANTAC_RF007 or SPRACINGF7DUAL: I don't have one. If someone with a NEXUSX can try a receiver on the SBUS pad with 9 outputs in the mixer, that would confirm it on the board the docs describe.

It depends on nothing else of mine, and merges cleanly with the open PRs that also change pwm_mapping.c (#12087, #12128, #12129).

… a function besides MSP

checkPwmTimerConflicts() kept outputs off the pins of UART2 to UART8 but
not UART1. On NEXUSX and VANTAC_RF007 the pads labelled AUX and SBUS are
both UART1 and two timer outputs, and SPRACINGF7DUAL has the same on PWM
3 and 4: with a receiver on UART1, a motor or servo could be assigned to
the receiver's pin and drive nothing once the receiver took it back.

UART1 gets MSP by default next to the VCP, and MSP opens before the
outputs and has always given them these pins, so MSP alone still does;
any other function on UART1 now keeps them, as on UART2 to UART8.
@qodo-code-review

Copy link
Copy Markdown
Contributor

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Prevent PWM outputs from claiming UART1 pins used by other functions

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Skip timer outputs on UART1 pins when UART1 has a function other than MSP.
• Preserve existing output assignments when UART1 is unused or configured for MSP alone.
Diagram

graph TD
  Config["UART1 configuration"] --> Pins["UART1 pin tags"] --> Conflict{"Other function and matching pin?"} -->|Yes| Skip["Skip timer output"] --> List["Output list"]
  Conflict -->|No| Assign["Assign timer output"] --> List
Loading
High-Level Assessment

The targeted UART1 exception fits the existing per-port conflict checks. Treating MSP like every other UART1 function would remove outputs from default configurations, while changing UART1's default MSP assignment would have broader effects.

Files changed (1) +9 / -0

Bug fix (1) +9 / -0
pwm_mapping.cExclude UART1 timer pads when non-MSP functions use the port +9/-0

Exclude UART1 timer pads when non-MSP functions use the port

• Adds a UART1 check to timer-output conflict detection. It skips pads matching either UART1 pin when the port has a function other than MSP, while retaining those pads for MSP-only or unconfigured UART1.

src/main/drivers/pwm_mapping.c

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can keep summaries lean with Findings visible per group, which tucks the rest behind a View link

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

RAM / Flash usage vs. base commit e87050f — commit 75f3455

Using the nearest available size baseline — the PR's exact base commit has no stored baseline yet.

Target Flash Δ RAM Δ
MATEKF405 -320 B (-0.04%) CCM: ±0 B (±0.00%)
RAM: +8 B (+0.01%)
MATEKF722 +104 B (+0.02%) ITCM_RAM: ±0 B (±0.00%)
RAM: ±0 B (±0.00%)
TCM: ±0 B (±0.00%)
MATEKF765 +208 B (+0.03%) DTCM_RAM: ±0 B (±0.00%)
SRAM1: ±0 B (±0.00%)
MATEKH743 +112 B (+0.01%) D2_RAM: ±0 B (±0.00%)
DTCM_RAM: ±0 B (±0.00%)
ITCM_RAM: ±0 B (±0.00%)
RAM: ±0 B (±0.00%)

See RAM/flash optimization guide for techniques to reduce usage.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

Test firmware build ready — commit 75f3455

Download firmware for PR #12131

251 targets built. Find your board's .hex file by name on that page (e.g. MATEKF405SE.hex). Files are individually downloadable — no GitHub login required.

Development build for testing only. Use Full Chip Erase when flashing.

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