DShot motors only initialize after re-assigning output functions (cold boot) — CUAV X7, AM32, v1.16 & v1.17

Summary

On a CUAV X7 with AM32 4-in-1 ESC, DShot motors do not initialize on cold boot (battery power-up). The ESC plays only the power-on tone and never reaches the arming/ready tone, motors do not spin. They start working only after I re-assign the output functions — either manually in QGC Actuators (set MAIN1-4 to Disable, then back to Motor 1-4), or via param set of the PWM_MAIN_FUNC* parameters in the MAVLink console.

The exact same ESC + wiring + motors work perfectly on ArduPilot (motors spin on power-up, no workaround needed). So the hardware is confirmed good.

I would like to understand the correct fix rather than rely on the workaround. Is this a known DShot initialization issue, and is there a proper solution (parameter, startup order, or fix)?

Hardware

  • FC: CUAV X7 (FMUv5-based, has IO processor)
  • ESC: Pilotix 90A AM32 4-in-1, firmware 2.20, MCU ARTERY F421, EEPROM v3
  • ESCs configured in AM32 Configurator: protocol DShot (also tried AUTO), Motor poles 14, KV 900, timing 15°, all 4 written identically
  • Signal wires S1-S4 on MAIN 1-4 (PWM_MAIN outputs)
  • Single battery powers FC and ESC together (simultaneous power-up)
  • Motors: 12N14P

Firmware

  • Reproduces identically on PX4 v1.16.0 and v1.17 stable
  • NuttX 11.0.0
  • Airframe: Generic Quadrotor X
  • Output protocol: DShot300 (PWM_MAIN_TIM0 = -4, PWM_MAIN_TIM1 = -4, both saved)
  • DSHOT_CONFIG parameter does not exist on this build (config is via Actuators / PWM_MAIN_TIMx)
  • SYS_USE_IO parameter does not exist on this build

Behavior

Cold boot (does NOT work)

On battery power-up, ESC plays only the initial power-on tone (“turum”), never the signal-recognition / arming tone. Motors do not spin, including via actuator_test.

dshot status after cold boot looks correct:

INFO  [dshot] Outputs initialized: yes
INFO  [dshot] Outputs used: 0xf
INFO  [dshot] Outputs on: yes
dshot: cycle: ... bdshot rpm: 0 events, dshot telem: 0 events
INFO  [mixer_module] Param prefix: PWM_MAIN
Channel 0: func: 103, value: 0, disarmed: 0, min: 109, max: 1999
Channel 1: func: 102, value: 0, disarmed: 0, min: 109, max: 1999
Channel 2: func: 101, value: 0, disarmed: 0, min: 109, max: 1999
Channel 3: func: 104, value: 0, disarmed: 0, min: 109, max: 1999

actuator_test set -m 1 -v 0.25 sets value: 649 on the channel (so the driver is outputting), but the motor does not spin.

After re-assigning output functions (WORKS)

Either of these makes the motors initialize and spin correctly:

Option A — QGC Actuators: set MAIN1-4 to Disable, then back to Motor 1-4.

Option B — MAVLink console:

param set PWM_MAIN_FUNC1 0
param set PWM_MAIN_FUNC2 0
param set PWM_MAIN_FUNC3 0
param set PWM_MAIN_FUNC4 0
sleep 1
param set PWM_MAIN_FUNC1 103
param set PWM_MAIN_FUNC2 102
param set PWM_MAIN_FUNC3 101
param set PWM_MAIN_FUNC4 104

After this, the ESC plays the full init/arming sequence and actuator_test set -m 1 -v 0.25 spins the motor.

This strongly suggests the DShot driver does not send the correct initial stop/zero command sequence to the ESC on cold boot, and the re-assignment forces a proper re-init. (Looks related to the discussion in PX4-Autopilot issue #17381 about the initial stop command.)

What I have already ruled out

  • Hardware — same ESC/wiring/motors spin fine on ArduPilot
  • ESC settings — protocol DShot/AUTO, poles 14, all 4 channels written identically, verified by read-back
  • Signal + ground continuity — checked with multimeter, S1-S4 on correct signal pins, ground common
  • DSHOT_BIDIR_EN — set to 0 and saved
  • Firmware version — identical behavior on v1.16 and v1.17
  • Protocol speed — DShot300 on both FC and ESC (ArduPilot also uses 300)

Questions

  1. Is this a known DShot cold-boot initialization issue on FMUv5 / CUAV X7?
  2. Is there a correct fix (parameter, startup configuration) rather than the re-assignment workaround?
  3. If a startup workaround in etc/extras.txt is the recommended path, what is the safe way to do it (correct timing relative to the dshot driver start, without writing PWM_MAIN_FUNC params on every boot)?
  4. Is there a console command that re-initializes the dshot output the same way the function re-assignment does, that I could investigate?

Any pointers appreciated. Happy to provide more logs (dshot status, dmesg, parameter dump) on request.

Have you tried the main branch?

Yes, the firmware was installed via QGC, stable release.

That’s not the main branch, that’s the stable release. Select development build and flash with main

Today, I installed the development build main firmware version via QGC.
But the ESC behavior remained exactly the same. The ESC doesn’t start after a reboot. It only works after QGC Actuators: set MAIN1-4 to Disable, then back to Motor 1-4.

I wrote to the manufacturer’s support service, here is their response

“First, we recommend checking the following:
Move the ESC signal wires from MAIN 1–4 outputs to AUX 1–4 outputs.
In QGroundControl → Actuators, assign the motors to the AUX outputs.
Test both DShot300 and DShot600.
If everything works correctly from a cold boot on the AUX outputs, then the issue is likely not related to the ESC itself, but rather to the use of DShot on the MAIN/IO outputs.
If you specifically need to use the MAIN outputs, this is likely a PX4-related issue and would be worth reporting on the PX4 GitHub or forum. The behavior is very similar to a known DShot initialization issue where the initial zero/stop command is not properly sent to the ESC during startup.”

It’s an ESC issue, or at the very least a timing issue between ESC bootloader and PX4. What’s probably happening is that the ESC bootloader is seeing the DShot signal while it’s high and getting stuck in the bootloader. When you re-assign outputs you’re causing the signal to go LOW, which the bootloader detects as a reset. Once you re-assign back to dshot the ESC is now in app firmware and the dshot signal works as expected. So it’s likely a race condition – the FC boots and starts sending the dshot signal faster than the ESC can clear the bootloader. Our ARK 4in1 ESC running AM32 2.20 with PX4 main doesn’t have this issue, so I’d look at the AM32 code for that particular ESC. It could also be a problem with the default pin config in the FC target. If you really want to nail it down I’d hook up a scope and logic analyzer and capture the first few seconds after boot to see what’s going on with the signalling.