Skip to content
drich edited this page Feb 28, 2023 · 8 revisions

Raspberry Pi boards sadly offer only 2 hardware PWM pins, which is not enough for any standard quadcopters.

There are however several possible workarounds :

  • Use a DMA engine to generate pulses by writing to mapped GPIOs, this allows up to 500Hz PWM (see pi-blaster from sarfata)
  • Use an external IC dedicated to PWM generation and connecting it via I2C / SPI, this increases hardware complexity and latency
  • Use an external IC multiplexer to alternate the Pi's hardware PWM, this increases hardware and cuts off update frequency in half (2 PWM outputs for 4 motors)
  • Hack DPI video output settings to produce high-resolution PWM / OneShot125/42 / DShot signals, this is the preferred method now but has its own caveats too (see kms-test from cleverca22)

Hacked DPI output

Currently, the recommended settings allow to use DShot300 at a ~6KHz update rate.

/boot/config.txt

dpi_output_format=0x1C17
dpi_group=2
dpi_mode=87
dpi_timings=512 0 40 80 40 1 0 0 1 0 0 0 0 10000 0 9309309 6
dtoverlay=dpi4,gpio_pin0=4,gpio_pin1=5,gpio_pin2=6,gpio_pin3=7
dtoverlay=vc4-fkms-v3d

/boot/cmdline.txt, at the end of line :

vc4.fkms_max_refresh_rate=55000

Modified DPI DTS overlay (precompiled here) copied to /boot/overlays

Under the hood

The video DPI output engine consists of an infinite loop triggering up to 24 GPIOs from a framebuffer. Each pixel is serially sent from top-left to bottom-right of image, this actually allows to output any kind of serialized binary data.

By alternating consecutive pixels between black and white its possible to produce this following pattern on each pin :

0 1 0 1 0 1 0 1

that will then be output by the DPI interface to GPIO as the following signal :

    ___     ___     ___     ___
   |   |   |   |   |   |   |   |
___|   |___|   |___|   |___|   |

Playing around with these fake colors allows to generate any kind of PWM signal, including DShot.

Eight black pixels followed by eight whites, binary value :

0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

will be output by the DPI interface to GPIO as the following signal :

                                _______________________________
                               |                               |
_______________________________|                               |

DShot

A DShot data packet is 16 bits long :

  • 11 bits containing desired motor speed
  • 1 bit to ask for telemetry feedback
  • 4 CRC bits

These 16 bits are sent as PWM pulses following each other, for DShot300 each bit is ~3.33µs long. When a bit value is 1 the pulse width is 2.50µs, while bits 0 are 1.25µs. Total length is 3.33 * 16 = ~54µs, on which we add 1µs to give space between each DShot packet for a total of 55µs.

           1             0             0             1
      _______       ____          ____          _______
     |       |     |    |        |    |        |       |
____ |       |____ |    |_______ |    |_______ |       |____ __  _   _ 
     ←  3.33µs   →               ←1.25→        ← 2.5µs →

By dividing each bit into 32 parts, with a resolution of 107ns, it becomes possible to produce DShot300 frames using DPI output with a refresh rate of 1/0.107 = 9.3MHz which is totally in the accepted range by the driver.

Finally, creating a fake framebuffer with a resolution of 512x1 pixels at ~6900FPS (yes!) representing exactly one DShot frame (16 bits x 32) allows to generate DShot signals just by playing around with pixels colors.

  • A bit with value 0 is represented by 12 "high" (white) pixels, followed by 20 "low" (black) pixels
  • A bit with value 1 is represented by 24 "high" (white) pixels, followed by 8 "low" (black) pixels

__ to_be_contined __

Clone this wiki locally