Skip to content

srxl2: a Smart ESC on a board's ESC connector - #12087

Closed
MrScothh wants to merge 3 commits into
iNavFlight:maintenance-10.xfrom
MrScothh:feature/srxl2-esc-connector
Closed

MrScothh wants to merge 3 commits into
iNavFlight:maintenance-10.xfrom
MrScothh:feature/srxl2-esc-connector

Conversation

@MrScothh

@MrScothh MrScothh commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

A few flight controllers made for helicopters have a connector labelled ESC whose signal pin can also be UART1's TX. @UltraFly asked in #11184 for a Smart ESC on the NEXUS-XR's one, which is PA9, USART1 TX on the F722. This adds an option for it on the three such boards INAV has. It is off by default, so nothing changes until someone turns it on.

Board Connector UART1 otherwise
NEXUSX (NEXUS X / XR) ESC, PA9 AUX and SBUS (PB6/PB7)
VANTAC_RF007 ESC, PA9 AUX and SBUS (PB6/PB7)
NEXUS M1/ESC, PB6 the DSM port (PA9/PA10)

The FlyDragon Pro's ESC connector is UART4's TX already, so that target only gains the driver: a Smart ESC there works with UART4 assigned to it in Ports.

How it behaves

  • New setting esc_srxl2_connector, OFF by default, only on these three targets.
  • ON, with the ESC protocol SRXL2 and UART1 free in Ports: the driver moves UART1's TX to the connector, half duplex, and the ESC there is motor 1. UARTs assigned the Smart ESC function in Ports follow as motors 2 and on, in UART order, as before.
  • The connector's pad keeps its motor slot, which SRXL2 never drives. These targets set that timer to motors, so the servos map exactly as with the option off. Nothing else gets the pin: after the mapping the pad loses its servo, LED, beeper and PINIO flags, so a beeper, LED strip or PINIO set on that timer in the Mixer tab stays off instead of taking the pin from the UART, and the Outputs tab shows what the board does.
  • ON while UART1 has a function in Ports: the connector is not used and UART1 keeps its function. UART1 gets MSP by default on these boards, so MSP has to come off it first; the Outputs tab says so.
  • OFF, or any other ESC protocol: nothing changes, the connector is a motor output as before.
  • Other targets are not affected: everything new is under ESC_CONNECTOR_UART, which only these three define. Their binaries grow only by the connector count in the status reply below.

I made it a setting rather than automatic because the firmware cannot tell a Smart ESC on the connector from one on a UART pad. With a Smart ESC on UART3 and UART1 free, an automatic choice would make the empty connector motor 1 and the ESC on UART3 motor 2.

The change

  • target.h of the three boards: ESC_CONNECTOR_UART, ESC_CONNECTOR_PIN and USE_MOTOR_SRXL2, which F7 does not build by default. FLYDRAGONPRO: USE_MOTOR_SRXL2 only.
  • uartSetTxPin() in the F7 UART driver, for these boards, and in the H7 one, where I tested it. It applies at the next open, and the new pin must use the alternate function of the UART's own TX: AF7 for USART1 on PA9 and PB6 alike.
  • motor_srxl2.c: the setting (new PG escConnectorConfig, id 1048), and srxl2MotorUsesEscConnector(), which decides from the configuration alone, so the output mapping, which runs before the driver opens its port, agrees with it.
  • pwm_mapping.c: while the connector carries the ESC, its pad gets no servo, and after the mapping it loses its servo, LED, beeper and PINIO flags. The motor slot stays because SRXL2 never drives it; skipping the pad would move the slot onto S1's timer and take S1-S3 from the servos.
  • MSP2_INAV_ESC_SRXL2_STATUS appends the board's connectors (a count, then the serial port identifier behind each), so the Configurator can offer the option only where it exists. msp_messages.json and the MSP README are updated. Both sides read the message by its length, so the 10.0 RC Configurator ignores the new bytes.
  • motorConfig_t: on these four targets it gains the SRXL2 fields that F4, H7 and AT32 already have. The padding byte in front of them (see flight/mixer.h) lets a configuration saved without them load with their defaults, so the group keeps its version and nobody loses motor settings.
  • motor_srxl2.h: an #error if a target defines a connector without USE_MOTOR_SRXL2, or on a platform other than F7 and H7. A static assert keeps a connector off PA11/PA12. On F7 INAV's USB runs on OTG_FS with VBUS sensing off, so PA9 is not used by the USB (usbd_conf_stm32f7xx.c).
  • Unit test pwm_mapping_esc_connector_unittest.cc. pwm_mapping.c is not built for the host, so like the other pwm_mapping tests it reproduces the override pass and the assignment loop, and a SourceSync case checks that the live source still has both hooks.
  • Docs: docs/Settings.md regenerated, a section "Boards with an ESC connector" in docs/Spektrum Smart ESC.md, and a line in docs/boards/NEXUSX.md.

The Configurator side is iNavFlight/inav-configurator#2814: the option in the Outputs tab, shown only when the board reports a connector, and the UART shown as "SRXL2 via ESC connector" in Ports.

Related

Cost

Against the base, 3931fcd:

Target Flash RAM ITCM
NEXUSX 469707 -> 475079 B, +5372 (96.66%) +792 B +184 B (70.36%)
VANTAC_RF007 467763 -> 473115 B, +5352 (96.26%) +832 B +184 B (70.36%)
NEXUS 457435 -> 462243 B, +4808 (94.04%) +800 B +24 B (58.69%)
FLYDRAGONPRO 478627 -> 483615 B, +4988 (98.39%) +792 B +184 B (70.36%)
MATEKF405SE, TBS_LUCID_H7_WING, BLUEBERRYF435WING +16 B 0 0
MATEKF722SE, KAKUTEF7, KAKUTEF7HDV 0, identical 0 0 (99.07% and 99.27% on the KAKUTEs)

On the four boards nearly all of it is the SRXL2 driver, which F7 targets do not build by default. It is in the binary whether the setting is on or not: FLYDRAGONPRO ends at 98.39%, below MATEKF722SE's 98.43%. With #12084 (ready delay) and #12085 (power-up) in as well, the four boards grow by another 298 to 584 B, and FLYDRAGONPRO ends at 98.49% (484091 B).

Tested

  • Unit tests: the new one and the existing pwm_mapping ones pass. The new one fails as it should with the final mask taken out of the reproduction (5 cases) or out of pwm_mapping.c (SourceSync).
  • SITL, with a local demo patch that is not part of this PR (UART2 standing in for a connector, and a no-op uartSetTxPin(), since SITL has no UART driver): the option on and off, the port count in the status reply (1 with the connector in use, 0 while its UART has MSP), and the Configurator tabs in each state.
  • TBS Lucid H7 Wing with a bench-only connector, on the previous revision of this PR, whose link path is the same: UART6 built with no TX pin of its own, so only the option can give it one (PC6), and an ESP32 on that pin playing a Smart ESC with the announce and link behaviour I measured on an Avian. resource shows PC6 taken by UART6 in half duplex; the ESC links and its telemetry arrives as motor 1; motor 1's command reaches it (1300, 1600 and 1000 us), with a real Avian on UART8 as motor 2. With motor_srxl2: link an ESC powered together with the board #12085 (power-up) in the same image, the ESC powered 0 to 150 ms after the board's reset linked 8 times out of 8; powered after the board was up, absent at boot and connected later, and across a board reboot, it linked every time.
  • Output mapping on the same board and revision, through MSP2_INAV_QUERY_OUTPUT_ASSIGNMENT with 8 servo rules: with the connector's timer set to motors as on these boards, motor 1 stays on the connector and the servos map identically with the option off and on; on auto, no servo lands on the connector. This revision adds the flags cleared after the mapping, which only the unit test covers: the beeper, LED and PINIO cases were not run on hardware.
  • Builds: the ten targets in the table, and SITL with the demo patch.

Not tested, testing wanted

None of the three boards. The mechanism ran on an H7 standing in for one; the three are F722, whose UART driver takes the same four-line setter. An owner of any of them with a Smart ESC could confirm the link on the connector, and that with the option off a normal ESC on the connector still works.

A few helicopter flight controllers have a connector labelled ESC whose pin
can also be UART1's TX: the NEXUS X/XR and Vantac RF007 (PA9) and the NEXUS
(PB6). Such a target now declares ESC_CONNECTOR_UART and ESC_CONNECTOR_PIN,
and a new setting, esc_srxl2_connector (off by default, only on those
targets), puts a Smart ESC there: with the ESC protocol set to SRXL2 and the
connector's UART free, the driver moves that UART's TX to the connector
(uartSetTxPin(), on F7 and H7) and opens it as motor 1. UARTs assigned the
Smart ESC function in Ports follow as motors 2 and on.

The pad behind the connector keeps its motor slot, which SRXL2 never drives,
so on these targets, which set the connector's timer to motors, the servos
map as with the setting off. The pad gets no servo, and after the mapping it
keeps no LED, beeper or PINIO flag either: none of those takes the pin from
the UART, and the Outputs tab maps what the board does.

The setting lives in a new parameter group. The three targets gain the
driver (USE_MOTOR_SRXL2) and with it the SRXL2 fields of motorConfig_t; the
padding byte in front of them lets a configuration saved without them load
with their defaults, so that group keeps its version. The FlyDragon Pro
gains the driver only: its connector labelled ESC is UART4's TX already.

MSP2_INAV_ESC_SRXL2_STATUS now ends with the board's connectors, by the UART
behind each, for the Configurator.
@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

qodo-free-for-open-source-projects Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

PR Summary by Qodo

Enable SRXL2 Smart ESCs on supported ESC connectors

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add an opt-in Smart ESC connector mode for three helicopter flight controllers.
Diagram

graph TD
  B["Board targets"] --> C["Connector setting"] --> E{"Connector eligible?"} --> D["SRXL2 driver"] --> U["UART TX pin"] --> P["ESC connector"]
  E --> M["Output mapping"] --> P
  B --> S["MSP status"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Select the connector automatically
  • ➕ No new user-facing setting.
  • ➖ An empty connector could become motor 1 ahead of a Smart ESC on an assigned UART.
2. Configure connector pin remapping through Ports
  • ➕ Could use the existing serial-port assignment workflow.
  • ➖ Would require a broader pin-selection interface and still need timer-pad ownership safeguards.

Recommendation: Keep the opt-in board-specific setting. It makes motor ordering intentional and limits pin remapping to boards that declare the capability. Reviewers should pay particular attention to UART ownership and output mapping on the three F7 boards, which still need hardware validation.

Files changed (19) +565 / -38

Enhancement (7) +143 / -27
pwm_mapping.cProtect the connector pad during output mapping +20/-0

Protect the connector pad during output mapping

• Prevents servo assignment to an active Smart ESC connector. After mapping, removes its servo, LED, beeper, and PINIO flags while retaining its motor slot.

src/main/drivers/pwm_mapping.c

serial_uart.hDeclare the F7/H7 UART TX pin setter +4/-0

Declare the F7/H7 UART TX pin setter

• Exposes uartSetTxPin for changing a UART's transmit pin before its next open.

src/main/drivers/serial_uart.h

serial_uart_stm32f7xx.cAllow F7 UART transmit-pin selection +9/-0

Allow F7 UART transmit-pin selection

• Adds a setter that changes the selected UART device's TX pin for subsequent port initialization.

src/main/drivers/serial_uart_stm32f7xx.c

serial_uart_stm32h7xx.cAllow H7 UART transmit-pin selection +9/-0

Allow H7 UART transmit-pin selection

• Adds the corresponding TX pin setter for H7 UART devices.

src/main/drivers/serial_uart_stm32h7xx.c

fc_msp.cReport Smart ESC connector capability over MSP +6/-0

Report Smart ESC connector capability over MSP

• Appends a connector count and, where defined, its UART identifier to the SRXL2 status response.

src/main/fc/fc_msp.c

motor_srxl2.cInitialize connector ESCs before assigned UARTs +71/-27

Initialize connector ESCs before assigned UARTs

• Registers the connector configuration and checks the setting, protocol, and UART availability. An eligible connector becomes the first ESC; the driver also rejects arming when assigned ESC ports exceed its supported limit.

src/main/io/motor_srxl2.c

motor_srxl2.hDeclare connector configuration and build constraints +24/-0

Declare connector configuration and build constraints

• Declares the connector configuration and eligibility query. Build errors guard against enabling the connector without SRXL2 or on a platform lacking the TX pin setter.

src/main/io/motor_srxl2.h

Tests (1) +311 / -0
pwm_mapping_esc_connector_unittest.ccTest connector output-mapping safeguards +311/-0

Test connector output-mapping safeguards

• Models motor-slot and servo behavior across output modes, including removal of competing pad flags. A source-synchronization test checks that both hooks remain in the live mapping code.

src/test/unit/pwm_mapping_esc_connector_unittest.cc

Documentation (5) +76 / -9
Settings.mdDocument the connector setting +10/-0

Document the connector setting

• Adds the generated reference entry for esc_srxl2_connector, including its board restrictions, UART requirement, motor ordering, and OFF default.

docs/Settings.md

Spektrum Smart ESC.mdExplain Smart ESC connector wiring and setup +44/-6

Explain Smart ESC connector wiring and setup

• Documents the supported boards, opt-in setup, UART1 conflict, and preserved output mapping. Also clarifies FlyDragon Pro setup and the four-port arming limit.

docs/Spektrum Smart ESC.md

NEXUSX.mdLink NEXUS X owners to connector setup +2/-0

Link NEXUS X owners to connector setup

• Notes that the ESC connector can carry SRXL2 through UART1 TX and links to the wiring instructions.

docs/boards/NEXUSX.md

README.mdDocument connector fields in SRXL2 status +3/-1

Document connector fields in SRXL2 status

• Describes the appended connector count and serial-port identifiers, including how connector use affects the opened-port count.

docs/development/msp/README.md

msp_messages.jsonExtend the SRXL2 status message specification +17/-2

Extend the SRXL2 status message specification

• Bumps the specification patch version and declares the appended connector count and variable-length port list.

docs/development/msp/msp_messages.json

Other (6) +35 / -2
parameter_group_ids.hReserve a connector configuration group ID +2/-1

Reserve a connector configuration group ID

• Assigns ID 1048 to PG_ESC_CONNECTOR_CONFIG and advances the INAV parameter-group endpoint.

src/main/config/parameter_group_ids.h

settings.yamlExpose an opt-in connector setting +11/-0

Expose an opt-in connector setting

• Adds the board-conditional esc_srxl2_connector setting with an OFF default.

src/main/fc/settings.yaml

target.hEnable the SRXL2 driver on FlyDragon Pro +3/-0

Enable the SRXL2 driver on FlyDragon Pro

• Builds SRXL2 support for its existing UART4 TX ESC connector; it does not enable the new connector setting.

src/main/target/FLYDRAGONPRO/target.h

target.hDeclare the NEXUS PB6 ESC connector +7/-1

Declare the NEXUS PB6 ESC connector

• Enables SRXL2 and identifies USART1 and PB6 as the connector UART and pin.

src/main/target/NEXUS/target.h

target.hDeclare the NEXUS X/XR PA9 ESC connector +6/-0

Declare the NEXUS X/XR PA9 ESC connector

• Enables SRXL2 and identifies USART1 and PA9 as the connector UART and pin.

src/main/target/NEXUSX/target.h

target.hDeclare the RF007 PA9 ESC connector +6/-0

Declare the RF007 PA9 ESC connector

• Enables SRXL2 and identifies USART1 and PA9 as the connector UART and pin.

src/main/target/VANTAC_RF007/target.h

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

qodo-free-for-open-source-projects Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. An existing ESC goes idle while arming ✓ Resolved
Description
srxl2MotorInitialize() inserts the connector before the assigned UARTs, and its four-entry limit
then skips the last assigned UART without recording an error. If a four-motor setup already uses
four Smart ESC UARTs, enabling the connector leaves the former fourth UART unopened, while the four
opened ESCs satisfy the motor-count and connection checks for arming.
Code

src/main/io/motor_srxl2.c[R660-664]

+#ifdef ESC_CONNECTOR_UART
+    if (srxl2MotorUsesEscConnector()) {
+        uartSetTxPin((UARTDevice_e)(ESC_CONNECTOR_UART - SERIAL_PORT_USART1), IO_TAG(ESC_CONNECTOR_PIN));
+        srxl2AddEsc(ESC_CONNECTOR_UART);
+    }
Evidence
The connector takes the first esc[] entry before the loop, which stops at four entries even if
another configured port remains. The output check rejects only fewer opened ports than mixer motors,
and the connection check examines only opened entries, so neither detects a displaced fifth ESC.

src/main/io/motor_srxl2.c[655-675]
src/main/io/motor_srxl2.h[48-57]
src/main/drivers/pwm_mapping.c[449-460]
src/main/io/motor_srxl2.c[1018-1035]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Enabling the ESC connector can turn a previously valid four-UART ESC configuration into five configured ESCs. Initialization silently skips the last UART, but the four opened ESCs still satisfy the arming checks.
## Fix Focus Areas
- src/main/io/motor_srxl2.c[660-675]
- src/main/drivers/pwm_mapping.c[449-460]
## Recommended Fix
Detect when a configured ESC port remains after the four-entry limit is reached, including when the connector consumed one entry. Expose that overflow to the motor-output validation and prevent arming rather than accepting the truncated set of ports.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can add REVIEW.md to your repo root and Qodo follows it on every PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/main/io/motor_srxl2.c
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

RAM / Flash usage vs. base branch — commit e3a28e6

No size baseline is available yet for this PR's base commit (no per-commit baseline has been published for it). This comment will show deltas once one exists — rebasing the PR refreshes its base commit.

Target Flash Δ RAM Δ
MATEKF405 723247 B (no baseline) 136780 B (no baseline)
MATEKF722 480771 B (no baseline) 112124 B (no baseline)
MATEKF765 756151 B (no baseline) 153948 B (no baseline)
MATEKH743 799051 B (no baseline) 158436 B (no baseline)

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

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Test firmware build ready — commit ee138ec

Download firmware for PR #12087

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.

@UltraFly

UltraFly commented Oct 1, 2026

Copy link
Copy Markdown

I tested this fix on avian 100A on nexus XR, I confirm it works after setting esc port to srxl2 mode

@MrScothh

MrScothh commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

@UltraFly thanks, the first test on one of the three boards, and with an Avian other than my 70A.

The driver opens at most four ports, and the connector takes the first, so
with four UARTs also assigned the last one was dropped without a word: its ESC
was never fed while the other four answered, and arming went ahead. A port
left over now keeps the link reported as missing, which blocks arming with
the OSD's hardware warning.
@sensei-hacker

sensei-hacker commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

I could see how this could be a little useful - though the board already has a pin for UART1.
I wonder if it could be MORE useful by deleting a bit of the code. Changing this:

Only on this one specific group of boards,
you can move only this one specific UART
to one specific motor pin
in order to use it with one specific brand of ESC

To:
You can set a motor pin as UART instead

Would it be 5939% more useful too 800X more people if the restrictions were deleted?

@sensei-hacker

Copy link
Copy Markdown
Member

Also just an FYI so you can prioritize your time since I know you've worked on a lot of things:

This board family is by far the most limited, least-capable target that can partially support INAV. I guess certain people are attracted to it BECAUSE it only has a couple spots to plug things in, while all other flight controllers have two or three times as many places users can plug things in.

A couple of users made a few requests to do hacky things in INAV to try to get around the extreme limitations of this particular board, to "undo" the choice of buying a board with only plugs available, A and B. A better solution would probably be for them to use literally any other any other board, any of the 209+ boards that can run INAV. There are no other boards in existence with the same limitations, and these won't be able to even partially support INAV 11 a year from now.

@MrScothh
MrScothh marked this pull request as draft October 5, 2026 23:13
@MrScothh
MrScothh marked this pull request as ready for review October 5, 2026 23:14
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit ee138ec

@sensei-hacker

sensei-hacker commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

There is a cool feature in here. I am hesitant to burn flash and RAM on on lines of code like:

1. Only allow this feature on one specific family of boards -- everyone else can screw off
2. Only allow this feature for one esoteric protocol -- everyone else can screw off
3. Only allow this feature on one specific uart -- everyone else can screw off
4. Only allow this feature on one specific PWM output-- everyone else can screw off
5. DoCoolFeature();

I'm thinking it may be more useful to essentially delete lines 1-4? If putting a UART on a PWM pad is useful, can we just do that? Without restricting it to only the three people who want to use one specific uart on one specific board for one specific purpose?

@MrScothh

Copy link
Copy Markdown
Contributor Author

Closing this in favour of #12143. @UltraFly, the NEXUS, NEXUS X and Vantac RF007 are in there too: the Smart ESC on the ESC connector now works with serialpad 0 5 0, and the test build in #12090 still has this PR's old esc_srxl2_connector setting.

@MrScothh MrScothh closed this Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants