Skip to content

Introduce dshot ESC protocol upperhalf and imx9 lowerhalf#18785

Open
jlaitine wants to merge 4 commits intoapache:masterfrom
tiiuae:introduce_dshot_upperhalf_and_imx9_lowerhalf
Open

Introduce dshot ESC protocol upperhalf and imx9 lowerhalf#18785
jlaitine wants to merge 4 commits intoapache:masterfrom
tiiuae:introduce_dshot_upperhalf_and_imx9_lowerhalf

Conversation

@jlaitine
Copy link
Copy Markdown
Contributor

@jlaitine jlaitine commented Apr 23, 2026

Summary

DShot is a packet based serial protocol, used for controlling motor controllers (ESCs), typically for drones.

I needed a dshot motor control for an i.MX93 based custom board, and decided to make a full "traditional"
upper/lower half nuttx driver for it, for easy integration to the actual application.

I am not sure whether the generic upper-half is wanted in NuttX, I know that PX4 (for which this would be most relevant) does it a bit differently, and codes stuff directly into px4 codebase drivers. On the other hand, electronic speed controllers are used also in non-px4 nuttx-based devices, so this could be useful.

I am open to improvement requests for the upper-half / interface; the interface presented here, however, works well for me for flying drone integration.

This PR adds:

  • a new generic drivers/timers/dshot.c upper-half driver
  • an imx93 dshot lower half driver using imx9 flexio module
  • initialization+registering of the dshot for imx93-evk:nsh board as /dev/dshot0

The generic upper-half driver supports registering and configuring DShot, as well as common protocol specific fuctionality to build the the 16-bit TX packets and interpret the 20-bit RX packets (in bidirectional mode). The raw packet sending and receiving is left for the lower-half.

For i.MX9, eight channels of DShot per flexio block are supported in:

  • Normal mode in all DShot speeds, with telemetry request (uart response needs to be handled outside of this driver)
  • Bidirectional mode in all DShot speeds, with telemetry request & response
  • Configurable to use either independent TX timers for each channel, or to use a common TX timer for all channels to synchronize the output
  • For bidirectional RX, each channel always uses an own RX timer.

In normal mode, the driver operates without any interrupts.

In bidirectional mode, the driver reconfigures the FlexIO timers (as needed) and shifters from TX to RX in the interrupt handler, and reads out the raw response packet.

Impact

No impact to existing boards, new feature. First board supporting DShot directly in NuttX level is the i.MX93

Testing

The driver has been tested in both lab environment by scoping the lines and communicating with ESCs, as well as running motors of a quadcopter and a 1-motor fixed wing flying devices.

  1. Attaching 2 scope pictures:

First, the "1_ch_bidir_w_debug.png" shows a single channel "bidirectional dshot" capture from a hexacopter + 2 debug lines. "Channel 0" is one of the lines in digital form. "Channel 1" is a debug channel showing RX clock timing for bidirectional response reading. "Channel 2" is a gpio used to measure initialization and interrupt times taken for the all the 6 channels per frame. The "Channel 3" is just the line in analog form to monitor any clitches.

1_ch_bidir_w_debug

Second, the "4_ch_non_bidir.png" shows 4-channel output for a "non-bidirectional dshot", running 4 motors at different speeds.

4_ch_non_bidir
  1. Tested with flying devices:

There is no "pure nuttx" test bench for the driver, insted, the driver was integrated into a PX4 system via wrappers used by existing code. A few places how it was done:
https://github.com/tiiuae/px4-firmware/blob/bc0d500b0d6c8aa7550c4679c36b6f1a8497f5cb/platforms/nuttx/src/px4/nxp/imx9/dshot/dshot.c#L91
https://github.com/tiiuae/px4-firmware/blob/bc0d500b0d6c8aa7550c4679c36b6f1a8497f5cb/platforms/nuttx/src/px4/nxp/imx9/dshot/dshot.c#L148

Note for px4 people if someone is reading this, the PX4 baseline in question is not the latest upstream one, so there are minor differencies in the wrappers.

The integrated driver was tested in flying the devices, and also checking the telemetry data in px4 debug terminal (example below, the escs in question only provide RPM output).

The actual ESC HW used for testing are older BLheli32 type ESCs and T-motor F55A 4-in-1 ESCs (AM32 firmware).

nsh> listener esc_status

TOPIC: esc_status
 esc_status
    timestamp: 6067858470 (0.000719 seconds ago)
    counter: 2074
    esc_count: 4
    esc_connectiontype: 5
    esc_online_flags: 15 (0b1111)
    esc_armed_flags: 15 (0b1111)

  esc[0] (esc_report):
    timestamp: 6067857069 (0.003602 seconds ago)
    esc_errorcount: 0
    esc_rpm: 128
    esc_voltage: 0.00000
    esc_current: 0.00000
    esc_temperature: 0.00000
    failures: 0
    esc_address: 0
    esc_cmdcount: 0
    esc_state: 0
    actuator_function: 101
    esc_power: 0

  esc[1] (esc_report):
    timestamp: 6067857069 (0.028694 seconds ago)
    esc_errorcount: 0
    esc_rpm: 128
    esc_voltage: 0.00000
    esc_current: 0.00000
    esc_temperature: 0.00000
    failures: 0
    esc_address: 0
    esc_cmdcount: 0
    esc_state: 0
    actuator_function: 102
    esc_power: 0

  esc[2] (esc_report):
    timestamp: 6067857069 (0.056597 seconds ago)
    esc_errorcount: 0
    esc_rpm: 128
    esc_voltage: 0.00000
    esc_current: 0.00000
    esc_temperature: 0.00000
    failures: 0
    esc_address: 0
    esc_cmdcount: 0
    esc_state: 0
    actuator_function: 103
    esc_power: 0

  esc[3] (esc_report):
    timestamp: 6067857069 (0.084419 seconds ago)
    esc_errorcount: 0
    esc_rpm: 128
    esc_voltage: 0.00000
    esc_current: 0.00000
    esc_temperature: 0.00000
    failures: 0
    esc_address: 0
    esc_cmdcount: 0
    esc_state: 0
    actuator_function: 104
    esc_power: 0

@github-actions github-actions Bot added Arch: arm64 Issues related to ARM64 (64-bit) architecture Area: Drivers Drivers issues Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. Board: arm64 labels Apr 23, 2026

ifeq ($(CONFIG_IMX9_FLEXIO_DSHOT),y)
CHIP_CSRCS += imx9_flexio_dshot.c
endif
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jlaitine, please align CMake with the Makefile

if(CONFIG_IMX9_FLEXIO_DSHOT)
list(APPEND SRCS imx9_flexio_dshot.c)
endif()

https://github.com/tiiuae/nuttx/blob/864e096b573588f75779425f9e0fb3bd6e54afc0/arch/arm64/src/imx9/CMakeLists.txt#L47

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thanks, done !

@jlaitine jlaitine force-pushed the introduce_dshot_upperhalf_and_imx9_lowerhalf branch from 864e096 to ba9d36d Compare April 23, 2026 09:55
@acassis acassis requested review from linguini1 and raiden00pl April 23, 2026 12:36
Copy link
Copy Markdown
Contributor

@acassis acassis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jlaitine nice improvement to NuttX!

Please add basic Documentation, otherwise it will become an "ANHFON" (Another Nice Hidden Feature Of NuttX) ;-)

Comment thread drivers/timers/dshot.c Outdated
Comment on lines +120 to +127
/* Parse raw pattern from the line into a 16-bit packet, and verify crc:
* 1. extract gcr20 value from the raw value
* 2. extract the 16-bit packet from the gcr20
* 3. check the packet crc
*
* In case of error, return negative error code.
* Otherwise return the 12-bit payload as a positive integer.
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the right Description format with its parameters and return type

@jlaitine jlaitine force-pushed the introduce_dshot_upperhalf_and_imx9_lowerhalf branch from ba9d36d to 607fb39 Compare April 24, 2026 06:00
@jlaitine
Copy link
Copy Markdown
Contributor Author

Upper-half code comments updated to follow proper style, documentation added.

@jlaitine jlaitine requested a review from acassis April 24, 2026 06:08
@jlaitine jlaitine force-pushed the introduce_dshot_upperhalf_and_imx9_lowerhalf branch from 607fb39 to 5bb881d Compare April 24, 2026 08:02
@jlaitine
Copy link
Copy Markdown
Contributor Author

Still fixed a few misplaced comments in the imx9 lower-half driver

Comment thread drivers/timers/Kconfig Outdated
This selection enables building of the "upper-half" Capture driver.
See include/nuttx/timers/capture.h for further Capture driver information.

config DSHOT
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move after line 132

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I made a bad rebase. Done!

Comment thread include/nuttx/timers/dshot.h Outdated
# if CONFIG_DSHOT_NCHANNELS > 16
# error "max 16 channels supported"
# endif
# define _DSHOT_NCHANNELS CONFIG_DSHOT_NCHANNELS
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use CONFIG_DSHOT_NCHANNELS directly

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was just nice that I can include the dshot.h in some common board files, and still being able to compile even if every board didn't define it. It was also shorter to use

Comment thread include/nuttx/timers/dshot.h Outdated
# endif
# define _DSHOT_NCHANNELS CONFIG_DSHOT_NCHANNELS
#else
# define _DSHOT_NCHANNELS 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the first _

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@jlaitine jlaitine force-pushed the introduce_dshot_upperhalf_and_imx9_lowerhalf branch from 5bb881d to c9a8879 Compare April 28, 2026 05:29
…for DSHOT

DShot is a packet based serial protocol, used for controlling motor controllers
(ESCs), typically for drones.

This adds an upper-half driver for dshot protocol, along with common
configuration options and definitions definitions.

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
Create a bidirectional dshot lower-half driver, using the flexio block.

This driver enables use of DShot protocol for Electronic Speed Controllers
(ESCs) typically used in drone motor control.

Eight channels of DShot per flexio block are supported in:

- Normal mode in all DShot speeds, with telemetry request (uart response
  needs to be handled outside of this driver)
- Bidirectional mode in all DShot speeds, with telemetry request & response
- Configurable to use either independent TX timers for each channel, or to
  use a common TX timer for all channels to synchronize the output
- For bidirectional RX, each channel always uses an own timer.

In normal mode, the driver operates without any interrupts.

In bidirectional mode, the driver reconfigures the FlexIO timers (as needed)
and shifters from TX to RX in the interrupt handler, and reads out the
raw response packet.

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This adds initialization of the flexio_dshot driver to the
imx93-evk:nsh target.

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
… half

Add documentation for the DShot electronic speed controllers protocol

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
@jlaitine jlaitine force-pushed the introduce_dshot_upperhalf_and_imx9_lowerhalf branch from c9a8879 to f197cc7 Compare April 28, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm64 Issues related to ARM64 (64-bit) architecture Area: Drivers Drivers issues Board: arm64 Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants