D-Shot Protocol
Overview
Digital Shot (D-shot) is a protocol for flight controller to ESC communication that, as its name suggest, is a digital protocol which brings many benefits to its implementation.
Here is a very good source that provides background, benefits, and implementation in regards to the frame structure (the actual signal that is being sent): https://brushlesswhoop.com/dshot-and-bidirectional-dshot/. One thing they don’t make explicit here, in terms of the duty cycle of each bit, a 1 is a about a 75% duty cycle and a 0 is about a 37.5% duty cycle.
For more background on other protocols for flight controller to ESC communication and how they work for those who are new, here is a good link to two videos: https://www.rcgroups.com/forums/showpost.php?p=36552970&postcount=2765
D-Shot Implementation using DMA
Here we will discuss how D-Shot can be implemented using DMA (Direct Memory Access).
At a high level, we must create a PWM signal that changes every bit, like the signal shown below, instead of keeping a constant PWM signal.
This means we must be constantly changing the duty cycle after every pulse. We can do this by having a loop and manually wait for a timer to tell us when to load the next duty cycle but this would be quite inefficient and hold up the microcontroller during the entire transmission. Instead we will use DMA.
Like I said before, DMA is not required for this application and will work without it, but we have this peripheral available to use, meant for exact situations like these, so why not. Please refer to DMA (Direct Memory Access) if you would like to learn more about DMA and a brief overview on how it works and its applications.
We set up the DMA to target the beginning of a list of 17 values and the duty cycle register in the timer. The 17th value of the list is just zero, which keeps the output low after the final bit is transferred. Every time the timer is about to reset and transfer the next pulse, it issues a command to the DMA peripheral to transfer a single value. This updates the duty cycle for the next pulse. The DMA peripheral knows to only send 17 values, after which it will disable itself. When we want to send another message, we just update the first 16 values with the new message, and re-enable the DMA peripheral.
This takes care of creating the transmission signal, the rest is preparing the buffers that will hold the transmission data which shouldn’t be too difficult if we completely understand how to convert the output value of our PWM loop into a digital value that can be loaded into the buffer the DMA will be using.
Determining the Checksum
Calculating the checksum to attach to the end of our 11bit data + 1 bit telemetry (for a total of 12 bits) is quite simple. All we have to do is split the 12 bits into 3 nibbles (1 nibble = 4 bits) and XOR (exclusive OR) them together, and our result is the checksum.
This can easily be implemented using bitwise operators as shown below:
checksum = (value ^ (value >> 4) ^ (value >> 8)) & 0x00F
Using the DShot Driver
When the PWMChannel object is initialized, PWM generation starts and the DMA transfer complete callback function is set up (basically this is the function that is called when a DMA transfer is complete, in our case when the entire DMA frame is transferred. All we are doing in this function is disabling DMA).
When the set function is called 3 things happen. First, the DShot DMA buffer is prepared which includes calculating the DShot frame, and translating those bits into capture compare values into the buffer. Second, the DMA peripheral is started with interrupts enabled. Finally, DMA requests are enabled. These “requests” are what triggers the DMA to make a transfer and in our case, when the PWM timer capture compare value is reached, a DMA request is made.
DShot Speeds
Currently, the DShot driver is only supporting DShot150. But there are higher speeds available.
DShot | Bitrate | T1H | T0H | Bit (µs) | Frame (µs) |
---|---|---|---|---|---|
150 | 150kbit/s | 5.00 | 2.50 | 6.67 | 106.72 |
300 | 300kbit/s | 2.50 | 1.25 | 3.33 | 53.28 |
600 | 600kbit/s | 1.25 | 0.625 | 1.67 | 26.72 |
1200 | 1200kbit/s | 0.625 | 0.313 | 0.83 | 13.28 |