Skip to content

Conversation

@EliaCereda
Copy link

@EliaCereda EliaCereda commented Nov 12, 2025

Implements bidirectional DSHOT in the CF 2.1 Brushless motor drivers, enabled through the motorPowerSet.bidiDshot param. ESC eRPM telemetry readings are exposed as motor.m#_erpm log variables.

DSHOT RX is implemented with DMA Input Capture, recording the timestamps of all edge transitions on the DSHOT line for 100us after the command packet (accounting for 30us wait time, ~50us telemetry packet time and some headroom).
All motors share TIM2 and DSHOT TX and RX need different timer periods, so at each cycle the code transmits a command to M1, M3 and M4, waits for their telemetry reply, then transmits to M2 and receive.

Caveats

  • The ESCs don’t start correctly if motorPowerSet.bidiDshot is enabled at boot, so it currently needs to be set to 1 while the drone is already turned on, on the ground.
  • Enabling telemetry introduces an additional fixed delay on M2 of 100us, on top of the delay from the existing unidirectional DMA implementation.

Implementation

The changes are split in a few commits that should be testable individually:

  • Commit 1: add motorPowerSet.bidiDshot param to turn on bidirectional DSHOT for all motors. When set, ESCs should reset and beep the motors, then everything should work normally. If you attach a logic analyser to DSHOT line RC_IN, you should see the DSHOT signal inverted (idle high) and that command packets are followed by a telemetry packet.
  • Commits 2 and 3: read the telemetry packet with DMA Input Capture and decode it to the motors.m1,2,3,4_erpm log variables. All motors are controlled but DMA capture is enabled only for M4
  • Commit 4: add synchronisation to wait until all motors have finished transmitting before starting to receive. Motor M1, M3, M4 both transmit and receive, M2 is disabled.
  • Commit 5: add TIM2 interrupt to detect when the receive phase is done, so that M2 TX can be triggered. All motors both transmit and receive.
  • Commit 6: cleanup dshotDecodeTelemetryERPM

Resources

https://brushlesswhoop.com/dshot-and-bidirectional-dshot/#bidirectional-dshot
https://github.com/betaflight/betaflight/blob/40b8a468f16d683aefed91a6ecf77590943f47f3/src/platform/STM32/pwm_output_dshot.c
https://github.com/betaflight/betaflight/blob/0b94db5fee44ec5af9f899a229aa329c90cbd8a8/src/platform/common/stm32/pwm_output_dshot_shared.c#L164

Closes #1411

Since the timer period (shared by all motors) needs to be changed between DSHOT TX and RX, all motors must finish transmitting before, they can all be switched to INPUT mode.

Enables reading DSHOT telemetry from motors M1, M3, M4
In INPUT mode, TIM2 is configured to trigger an Update interrupt after 100us.

As the number of GCR edges in a telemetry packet is data-dependent, this is an alternative way to detect that the telemetry packet has finished (elaps. time > max telemetry packet time)

Enable receiving DSHOT telemetry for M2. Order is now M1/M3/M4 transmit, M1/M3/M4 receive, M2 transmit, M2 receive
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.

Feature request: BDshot

1 participant