Article

Bidirectional DShot telemetry must fit the control loop and reject bad symbols

At 8 kHz, a flight controller gets 125 microseconds to complete one PID cycle. ESC RPM feedback helps the controller place motor-noise filters and manage idle speed, but decoding that feedback also consumes CPU time. Two open pull requests from October 23-24 expose different failure modes in the same communication path: a Betaflight contributor wants to reduce the per-loop decoding cost, while a PX4 contributor wants to reject malformed telemetry before it can look valid.

Neither proposal is a released performance or safety result. Taken together, they identify two questions every bidirectional DShot implementation must answer: can the controller process the response on time, and can it trust the decoded value?

The wire has a deadline before the CPU starts decoding

DShot sends a fixed 16-bit throttle/command frame from the flight controller to the electronic speed controller (ESC). In bidirectional mode, the ESC returns an electrical-RPM (eRPM) response on the same signal wire. The flight controller must change direction between transmission and reception; the protocol is not a simultaneous two-way UART. Betaflight's DShot implementation guide describes the frame timing and return encoding in detail.

At DShot300, the published timing example allows 53.28 microseconds for the outgoing frame, two roughly 30-microsecond direction-change intervals and 56 microseconds for the response. The total is about 169.28 microseconds. That places the theoretical maximum exchange rate around 5.9 kHz, below an 8 kHz control loop. The guide describes DShot600 as the appropriate higher-rate choice for 8 kHz bidirectional operation, with a theoretical maximum around 8.7 kHz. These are protocol timing calculations, not proof that a particular controller can sustain the corresponding control loop.

The CPU then has to reconstruct the incoming waveform, validate its encoding, recover eRPM and make the data available to the filters and idle-control logic. Memory transfers and timers reduce processor involvement during transmission, but they do not eliminate decoding and scheduling costs. Hardware, DMA allocation, driver implementation and other tasks determine the margin left after the wire-level exchange.

One-motor-per-cycle decoding moves the scheduling trade-off

Betaflight PR #15890, opened October 23, proposes an optional dshot_bidir_rotate mode for its bitbang implementation. Instead of decoding every motor's telemetry on every PID iteration, it would decode one motor per iteration and rotate through them. The default remains OFF. Its proposed AUTO behaviour enables rotation only above 4 kHz; enabling the option does not independently increase the PID rate.

The contributor's bench measurement uses a HAKRCF411D flight controller, an F411 running at 120 MHz, DShot600 bidirectional, four motor outputs and no propellers or battery. On that setup, reported decoding time drops from 37.6 to 11.6 microseconds per PID loop. The contributor says this permits the nominal 8 kHz loop instead of an observed drop to about 6.1 kHz in the tested configuration.

Those numbers describe one controller and one firmware branch, not a transferable 26-microsecond saving on every F4 target. More importantly, moving decoding work does not make the rest of the processor faster. The PR reports that with rotation enabled, an 8 kHz loop and the full filter chain, USB communication became unresponsive on the bench and required DFU recovery. In that test, recovered PID-loop time was consumed elsewhere, leaving insufficient service time for lower-priority activity.

A motor controller that hits its requested loop frequency while starving USB, serial handling or diagnostics is not necessarily better provisioned. It may simply have shifted which task misses its deadline.

How stale does RPM become when four motors take turns?

With four motors and an 8 kHz loop, a one-motor-per-cycle rotation visits each motor every four iterations: the theoretical refresh rate is 2 kHz per motor, or one reading every 0.5 milliseconds. That is less frequent than full decoding at every 125-microsecond iteration, although still fast relative to many filter-parameter updates. The distinction matters when making dynamic filtering and dynamic-idle claims.

Betaflight's RPM-filter documentation explains that motor eRPM drives frequency-targeted notch filters and feeds dynamic idle. It also stresses consistent loop timing, correct motor pole count and valid ESC telemetry. No universal acceptable maximum age follows from a 2 kHz arithmetic refresh figure alone: the result depends on RPM acceleration, filter update cadence, timing jitter and error/dropout handling.

The rotation proposal makes two extra accommodations. It decodes all motor responses while a command acknowledgement is expected, rather than risk missing a one-frame acknowledgement. It also changes rotation phase periodically so extended DShot telemetry (EDT), sent intermittently, does not systematically favour one motor. Both are useful engineering considerations; neither substitute for an end-to-end validation of sparse telemetry under transient throttle changes.

The author explicitly labels the rotating mode bench tested but not flown. Its effect on RPM filtering, dynamic idle and EDT acknowledgement still needs flight checks. A pilot should not infer a safe 8 kHz configuration simply because the bench counter reaches 8,000 cycles per second.

A valid checksum does not prove a valid symbol stream

A separate issue appears farther along the receive path. Bidirectional DShot eRPM data are encoded into a 20-bit waveform using GCR, which maps each four-bit data nibble to a five-bit symbol. The recipient must first decide whether each symbol belongs to the permitted set. Only then does checking the reconstructed data's checksum have its intended meaning. Betaflight's protocol description documents this encoding.

PX4 PR #29415, opened October 24, says its existing decoder mapped illegal five-bit symbols to zero before checksum validation. Under some corrupt input patterns, such substitutions could produce values whose reconstructed checksums appeared acceptable. The proposed repair applies a shared validated decoder across STM32 and i.MX RT implementations; the contributor states that tests cover every possible 20-bit symbol pattern.

The engineering distinction is subtle. A checksum can detect many accidental modifications to an already valid codeword. It cannot make an invalid symbol valid, and a decoder that silently substitutes a legal data value has changed the error-detection problem before the checksum runs. Rejecting the illegal symbol at the first stage prevents that particular ambiguity.

This is an upstream contributor's code finding. The PR does not establish how often malformed signals occur in field use, how many aircraft have received false eRPM samples, or whether any observed incident followed from it. Exhaustive input-space unit tests are useful evidence of decoder behaviour, but they are not a field reliability measurement.

Testing needs two independent pass conditions

A defensible evaluation separates timeliness from data integrity. First measure whether the intended control rate is sustained with the actual workload enabled. Log or instrument worst-case loop timing, not just an average or a rate displayed in the configurator. Exercise the serial interface, USB, logging and telemetry at the same time. Test restarts and parameter changes, because a bench run that leaves the flight controller inaccessible has already exposed a system-level problem.

Then test what the decoder accepts. Valid response symbols with valid checksums should reconstruct the expected eRPM. Invalid GCR symbols should be rejected regardless of what checksum would result after substitution. Short, missing or distorted replies need explicit error paths, with the filter and idle logic receiving a known invalid or stale-data state rather than a plausible-looking zero. The exact acceptance criteria depend on implementation and must be documented, not guessed from a flight video.

For a four-motor rotating implementation, a useful test matrix includes steady RPM, abrupt motor acceleration, repeated missed replies, individual motor loss, and EDT traffic. It should record the age of the most recent accepted sample per motor, the invalid-response count, the effect on filtering and whether control-loop jitter changes when all-motor decoding is temporarily required. Those are proposed validation conditions, not tests performed for this article.

Finally, check the physical configuration. PX4's DShot documentation ties bidirectional support to appropriate timer/DMA-capable outputs and ESC support. Betaflight requires compatible ESC firmware and correctly configured motor pole counts to interpret eRPM. A software patch cannot overcome incompatible output hardware, an unsupported ESC or an incorrectly entered pole count.

The useful metric is trustworthy data delivered on time

The two proposals do not offer competing solutions. Betaflight's rotating decoder tries to create scheduling headroom by reading fewer motors on each iteration. PX4's symbol validation tries to prevent corrupted responses from masquerading as good data. An autopilot needs both properties: timely samples and defensible rejection of bad ones.

For now the review-stage evidence supports a narrow conclusion. On one F411 bench setup, decoding fewer ESC responses cut measured per-cycle decoding time, but the same configuration exposed USB starvation and lacked flight validation. In another codebase, an illegal-symbol handling path was identified and a validating decoder proposed, without reported field incidence. Any claim of a faster or safer production flight stack needs controlled end-to-end measurements beyond those pull requests.