Paparazzi UAS  v6.0_unstable-41-g5cfda00-dirty
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
esc_dshot.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2018 Alexandre Bustico <alexandre.bustico@enac.fr>
3  * Gautier Hattenberger <gautier.hattenberger@enac.fr>
4  *
5  * This file is part of paparazzi
6  *
7  * paparazzi is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * paparazzi is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with paparazzi; see the file COPYING. If not, see
19  * <http://www.gnu.org/licenses/>.
20  */
21 
31 #include <stdnoreturn.h>
32 #include <math.h>
33 #include <string.h>
34 
35 /*
36 # _ __ _ _ _ _
37 # | | / _| (_) (_) | | (_)
38 # __| | ___ | |_ _ _ __ _ | |_ _ ___ _ __
39 # / _` | / _ \ | _| | | | '_ \ | | | __| | | / _ \ | '_ \
40 # | (_| | | __/ | | | | | | | | | | \ |_ | | | (_) | | | | |
41 # \__,_| \___| |_| |_| |_| |_| |_| \__| |_| \___/ |_| |_|
42 */
43 
47 #ifndef DSHOT_SPEED
48 #define DSHOT_SPEED 300
49 #endif
50 
54 #ifndef DSHOT_TELEMETRY_BAUD
55 #define DSHOT_TELEMETRY_BAUD 115200
56 #endif
57 
60 #ifndef DSHOT_TELEMETRY_TIMEOUT_MS
61 #define DSHOT_TELEMETRY_TIMEOUT_MS 3
62 #endif
63 
65 #define PWM_FREQ (STM32_SYSCLK/2000)
66 
73 #define TICKS_PER_PERIOD 1000
74 
75 // Some extra defines and macros
76 #define DSHOT_FREQ (DSHOT_SPEED*1000) // in Hz
77 #define TICK_FREQ (PWM_FREQ * TICKS_PER_PERIOD)
78 #define DSHOT_PWM_PERIOD (TICK_FREQ/DSHOT_FREQ)
79 #define DSHOT_BIT0_DUTY (DSHOT_PWM_PERIOD * 373 / 1000)
80 #define DSHOT_BIT1_DUTY (DSHOT_BIT0_DUTY*2)
81 #define DCR_DBL ((DSHOT_CHANNELS-1) << 8) // DSHOT_CHANNELS transfert(s), first register to get is CCR1
82 #define DCR_DBA(pwmd) (((uint32_t *) (&pwmd->tim->CCR) - ((uint32_t *) pwmd->tim)))
83 
84 #define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
85 #define Min(x,y) (x < y ? x : y)
86 
87 #define DSHOT_MAX_VALUE ((1<<11)-1) // 11 bits used to send command, so maximum value is 2047
88 
89 /*
90 # _ __ _ _ _ _ _ __
91 # | '_ \ | | | | | | | | | '_ \
92 # | |_) | _ __ ___ | |_ ___ | |_ | |_| | | |_) | ___
93 # | .__/ | '__| / _ \ | __| / _ \ | __| \__, | | .__/ / _ \
94 # | | | | | (_) | \ |_ | (_) | \ |_ __/ | | | | __/
95 # |_| |_| \___/ \__| \___/ \__| |___/ |_| \___|
96 */
97 static DshotPacket makeDshotPacket(const uint16_t throttle, const bool tlmRequest);
98 static inline void setDshotPacketThrottle(DshotPacket * const dp, const uint16_t throttle);
99 static inline void setDshotPacketTlm(DshotPacket * const dp, const bool tlmRequest);
100 static void buildDshotDmaBuffer(DshotPackets * const dsp, DshotDmaBuffer * const dma, const size_t timerWidth);
101 static inline uint8_t updateCrc8(uint8_t crc, uint8_t crc_seed);
102 static uint8_t calculateCrc8(const uint8_t *Buf, const uint8_t BufLen);
103 static noreturn void dshotTlmRec(void *arg);
104 static size_t getTimerWidth(const PWMDriver *pwmp);
105 
106 /*
107 # _ __ _
108 # | '_ \ (_)
109 # __ _ | |_) | _
110 # / _` | | .__/ | |
111 # | (_| | | | | |
112 # \__,_| |_| |_|
113 */
114 
123 {
124  memset((void *) config->dma_buf, 0, sizeof(*(config->dma_buf)));
125  const size_t timerWidthInBytes = getTimerWidth(config->pwmp);
126 
127  static const SerialConfig tlmcfg = {
128  .speed = DSHOT_TELEMETRY_BAUD,
129  .cr1 = 0, // pas de parité
130  .cr2 = USART_CR2_STOP1_BITS, // 1 bit de stop
131  .cr3 = 0 // pas de controle de flux hardware (CTS, RTS)
132  };
133 
134  driver->config = config;
135  // use pburst, mburst only if buffer size satisfy aligmnent requirement
136  driver->dma_conf = (DMAConfig) {
137  .stream = config->dma_stream,
138  .channel = config->dma_channel,
139  .dma_priority = 3,
140  .irq_priority = 2,
141  .direction = DMA_DIR_M2P,
142  .psize = timerWidthInBytes,
143  .msize = timerWidthInBytes,
144 #if __DCACHE_PRESENT
145  .dcache_memory_in_use = config->dcache_memory_in_use,
146 #endif
147  .inc_peripheral_addr = false,
148  .inc_memory_addr = true,
149  .circular = false,
150  .error_cb = NULL,
151  .end_cb = NULL,
152  .pburst = 0,
153  .mburst = 0,
154  .fifo = 4
155  };
156 
157  driver->pwm_conf = (PWMConfig) {
158  .frequency = TICK_FREQ,
159  .period = TICKS_PER_PERIOD,
160  .callback = NULL,
161  .channels = {
162  {.mode = PWM_OUTPUT_ACTIVE_HIGH,
163  .callback = NULL},
164  {.mode = DSHOT_CHANNELS > 1 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED,
165  .callback = NULL},
166  {.mode = DSHOT_CHANNELS > 2 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED,
167  .callback = NULL},
168  {.mode = DSHOT_CHANNELS > 3 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED,
169  .callback = NULL},
170  },
171  .cr2 = STM32_TIM_CR2_CCDS,
172  .dier = STM32_TIM_DIER_UDE
173  };
174 
175  driver->crc_errors = 0;
176  dmaObjectInit(&driver->dmap);
177  chMBObjectInit(&driver->mb, driver->_mbBuf, ARRAY_LEN(driver->_mbBuf));
178 
179  const bool dmaOk = dmaStart(&driver->dmap, &driver->dma_conf);
180  chDbgAssert(dmaOk == true, "dshot dma start error");
181 
182  if (driver->config->tlm_sd) {
183  sdStart(driver->config->tlm_sd, &tlmcfg);
184  chThdCreateStatic(driver->waDshotTlmRec, sizeof(driver->waDshotTlmRec), NORMALPRIO,
185  dshotTlmRec, driver);
186  }
187 
188  pwmStart(driver->config->pwmp, &driver->pwm_conf);
189  driver->config->pwmp->tim->DCR = DCR_DBL | DCR_DBA(driver->config->pwmp); // enable bloc register DMA transaction
190  pwmChangePeriod(driver->config->pwmp, DSHOT_PWM_PERIOD);
191 
192  for (size_t j = 0; j < DSHOT_CHANNELS; j++) {
193  pwmEnableChannel(driver->config->pwmp, j, 0);
194  driver->dshotMotors.dp[j] = makeDshotPacket(0, 0);
195  }
196  driver->dshotMotors.onGoingQry = false;
197  driver->dshotMotors.currentTlmQry = 0U;
198 }
199 
210 void dshotSetThrottle(DSHOTDriver *driver, const uint8_t index,
211  const uint16_t throttle)
212 {
213  if (throttle > 0 && throttle <= DSHOT_CMD_MAX) {
214  chDbgAssert(false, "dshotSetThrottle throttle error");
215  return; // special commands (except MOTOR_STOP) can't be applied from this function
216  } else {
217  // send normal throttle
218  if (index == DSHOT_ALL_MOTORS) {
219  for (uint8_t _index = 0; _index < DSHOT_CHANNELS; _index++) {
220  setDshotPacketThrottle(&driver->dshotMotors.dp[_index], Min(throttle, DSHOT_MAX_VALUE));
221  }
222  } else if ((index - DSHOT_CHANNEL_FIRST_INDEX) < DSHOT_CHANNELS) {
224  Min(throttle, DSHOT_MAX_VALUE));
225  } else {
226  chDbgAssert(false, "dshotSetThrottle index error");
227  }
228  }
229 }
230 
239 void dshotSendSpecialCommand(DSHOTDriver *driver, const uint8_t index,
240  const dshot_special_commands_t specmd)
241 {
242  if (specmd > DSHOT_CMD_MAX) {
243  return; // Don't apply special commands from this function
244  }
245  if (index < DSHOT_CHANNELS) {
246  setDshotPacketThrottle(&driver->dshotMotors.dp[index], specmd);
247  setDshotPacketTlm(&driver->dshotMotors.dp[index], driver->config->tlm_sd != NULL);
248  } else if (index == DSHOT_ALL_MOTORS) {
249  for (uint8_t _index = 0; _index < DSHOT_CHANNELS; _index++) {
250  setDshotPacketThrottle(&driver->dshotMotors.dp[_index], specmd);
251  setDshotPacketTlm(&driver->dshotMotors.dp[_index], driver->config->tlm_sd != NULL);
252  }
253  }
254 
255  uint8_t repeat;
256  switch (specmd) {
265  repeat = 10;
266  break;
267  default:
268  repeat = 1;
269  }
270 
271  while (repeat--) {
272  dshotSendFrame(driver);
273  chThdSleepMilliseconds(1);
274  }
275 }
276 
286 void dshotSendThrottles(DSHOTDriver *driver, const uint16_t throttles[DSHOT_CHANNELS])
287 {
288  for (uint8_t index = 0; index < DSHOT_CHANNELS; index++) {
289  setDshotPacketThrottle(&driver->dshotMotors.dp[index], throttles[index]);
290  }
291 
292  dshotSendFrame(driver);
293 }
294 
303 {
304  if (driver->dmap.state == DMA_READY) {
305  if ((driver->config->tlm_sd != NULL) &&
306  (driver->dshotMotors.onGoingQry == false)) {
307  driver->dshotMotors.onGoingQry = true;
308  const uint32_t index = (driver->dshotMotors.currentTlmQry + 1) % DSHOT_CHANNELS;
309  driver->dshotMotors.currentTlmQry = index;
310  setDshotPacketTlm(&driver->dshotMotors.dp[index], true);
311  chMBPostTimeout(&driver->mb, driver->dshotMotors.currentTlmQry, TIME_IMMEDIATE);
312  }
313 
314  buildDshotDmaBuffer(&driver->dshotMotors, driver->config->dma_buf, getTimerWidth(driver->config->pwmp));
315  dmaStartTransfert(&driver->dmap,
316  &driver->config->pwmp->tim->DMAR,
318 
319  }
320 }
321 
330 {
331  return driver->crc_errors;
332 }
333 
342 const DshotTelemetry *dshotGetTelemetry(const DSHOTDriver *driver, const uint32_t index)
343 {
344  return &driver->dshotMotors.dt[index];
345 }
346 
347 
348 /*
349 # _ __ _ _
350 # | '_ \ (_) | |
351 # | |_) | _ __ _ __ __ __ _ | |_ ___
352 # | .__/ | '__| | | \ \ / / / _` | | __| / _ \
353 # | | | | | | \ V / | (_| | \ |_ | __/
354 # |_| |_| |_| \_/ \__,_| \__| \___|
355 */
356 
357 static DshotPacket makeDshotPacket(const uint16_t _throttle, const bool tlmRequest)
358 {
359  DshotPacket dp = {.throttle = _throttle,
360  .telemetryRequest = (tlmRequest ? 1 : 0),
361  .crc = 0
362  };
363 
364  // compute checksum
365  uint16_t csum = (_throttle << 1) | dp.telemetryRequest;
366  for (int i = 0; i < 3; i++) {
367  dp.crc ^= csum; // xor data by nibbles
368  csum >>= 4;
369  }
370 
371  return dp;
372 }
373 
374 static inline void setDshotPacketThrottle(DshotPacket *const dp, const uint16_t throttle)
375 {
376  dp->throttle = throttle;
377  dp->telemetryRequest = 0;
378 }
379 
380 static inline void setDshotPacketTlm(DshotPacket *const dp, const bool tlmRequest)
381 {
382  dp->telemetryRequest = tlmRequest ? 1 : 0;
383 }
384 
385 static void buildDshotDmaBuffer(DshotPackets *const dsp, DshotDmaBuffer *const dma, const size_t timerWidth)
386 {
387  for (size_t chanIdx = 0; chanIdx < DSHOT_CHANNELS; chanIdx++) {
388  // compute checksum
389  DshotPacket *const dp = &dsp->dp[chanIdx];
390  dp->crc = 0;
391  uint16_t csum = (dp->throttle << 1) | dp->telemetryRequest;
392  for (int i = 0; i < 3; i++) {
393  dp->crc ^= csum; // xor data by nibbles
394  csum >>= 4;
395  }
396  // generate pwm frame
397  for (size_t bitIdx = 0; bitIdx < DSHOT_BIT_WIDTHS; bitIdx++) {
398  const uint16_t value = dp->rawFrame &
399  (1 << ((DSHOT_BIT_WIDTHS - 1) - bitIdx)) ?
401  if (timerWidth == 2) {
402  dma->widths16[bitIdx+DSHOT_PRE_FRAME_SILENT_SYNC_BITS][chanIdx] = value;
403  } else {
404 #if DSHOT_AT_LEAST_ONE_32B_TIMER
405  dma->widths32[bitIdx+DSHOT_PRE_FRAME_SILENT_SYNC_BITS][chanIdx] = value;
406 #else
407  chSysHalt("use of 32 bit timer implies to define DSHOT_AT_LEAST_ONE_32B_TIMER to TRUE");
408 #endif
409  }
410  }
411  // the bits for silence sync (pre and post) in case of continous sending are zeroed once at init
412  }
413 }
414 
415 static inline uint8_t updateCrc8(uint8_t crc, uint8_t crc_seed)
416 {
417  uint8_t crc_u = crc;
418  crc_u ^= crc_seed;
419 
420  for (int i = 0; i < 8; i++) {
421  crc_u = (crc_u & 0x80) ? 0x7 ^ (crc_u << 1) : (crc_u << 1);
422  }
423 
424  return (crc_u);
425 }
426 
427 static uint8_t calculateCrc8(const uint8_t *Buf, const uint8_t BufLen)
428 {
429  uint8_t crc = 0;
430  for (int i = 0; i < BufLen; i++) {
431  crc = updateCrc8(Buf[i], crc);
432  }
433 
434  return crc;
435 }
436 
437 __attribute__((const))
438 static size_t getTimerWidth(const PWMDriver *pwmp)
439 {
440  (void) pwmp;
441 
442  return (0
444  || (pwmp == &PWMD2)
445 #endif
446 #if STM32_PWM_USE_TIM5
447  || (pwmp == &PWMD5)
448 #endif
449  ) ? 4 : 2;
450 }
451 
452 
453 /*
454 # _ _ _
455 # | | | | | |
456 # | |_ | |__ _ __ ___ __ _ __| | ___
457 # | __| | '_ \ | '__| / _ \ / _` | / _` | / __|
458 # \ |_ | | | | | | | __/ | (_| | | (_| | \__ \
459 # \__| |_| |_| |_| \___| \__,_| \__,_| |___/
460 */
461 
462 static noreturn void dshotTlmRec(void *arg)
463 {
464  DSHOTDriver *driver = (DSHOTDriver *) arg;
465 
466  uint32_t escIdx = 0;
467 
468  chRegSetThreadName("dshotTlmRec");
469  while (true) {
470  chMBFetchTimeout(&driver->mb, (msg_t *) &escIdx, TIME_INFINITE);
471  const uint32_t idx = escIdx;
472  const bool success =
473  (sdReadTimeout(driver->config->tlm_sd, driver->dshotMotors.dt[idx].rawData, sizeof(DshotTelemetry),
474  TIME_MS2I(DSHOT_TELEMETRY_TIMEOUT_MS)) == sizeof(DshotTelemetry));
475  if (!success ||
476  (calculateCrc8(driver->dshotMotors.dt[idx].rawData,
477  sizeof(driver->dshotMotors.dt[idx].rawData)) != driver->dshotMotors.dt[idx].crc8)) {
478  // empty buffer to resync
479  while (sdGetTimeout(driver->config->tlm_sd, TIME_IMMEDIATE) >= 0) {};
480  memset(driver->dshotMotors.dt[idx].rawData, 0U, sizeof(DshotTelemetry));
481  // count errors
482  driver->crc_errors++;
483  }
484  driver->dshotMotors.onGoingQry = false;
485  }
486 }
487 
Ready.
Definition: hal_stm32_dma.h:65
#define DCR_DBL
Definition: esc_dshot.c:81
#define DSHOT_TELEMETRY_TIMEOUT_MS
Telemetry timeout in ms.
Definition: esc_dshot.c:61
DSHOT driver based on ChibiOS.
#define DSHOT_PWM_PERIOD
Definition: esc_dshot.c:78
static uint32_t idx
telemetry packed as sent by some KISS ESC
Definition: esc_dshot.h:125
#define Min(x, y)
Definition: esc_dshot.c:85
#define DSHOT_BIT_WIDTHS
DMA buffer size and number of channels.
Definition: esc_dshot.h:49
static void setDshotPacketTlm(DshotPacket *const dp, const bool tlmRequest)
Definition: esc_dshot.c:380
bool dmaStart(DMADriver *dmap, const DMAConfig *cfg)
Configures and activates the DMA peripheral.
Definition: hal_stm32_dma.c:92
DshotTelemetry dt[DSHOT_CHANNELS]
Definition: esc_dshot.h:219
PWMConfig pwm_conf
PWM config associated with pwm timer.
Definition: esc_dshot.h:242
static size_t getTimerWidth(const PWMDriver *pwmp)
Definition: esc_dshot.c:438
uint32_t stream
stream associated with transaction
DSHOT Driver configuration structure.
Definition: esc_dshot.h:155
PWMDriver * pwmp
PWM driver that feed up to 4 dshot lines.
Definition: esc_dshot.h:169
static const struct usb_config_descriptor config
Definition: usb_ser_hw.c:200
static void setDshotPacketThrottle(DshotPacket *const dp, const uint16_t throttle)
Definition: esc_dshot.c:374
void dshotStart(DSHOTDriver *driver, const DSHOTConfig *config)
Configures and activates the DSHOT peripheral.
Definition: esc_dshot.c:122
void dshotSetThrottle(DSHOTDriver *driver, const uint8_t index, const uint16_t throttle)
prepare throttle order for specified ESC
Definition: esc_dshot.c:210
#define DCR_DBA(pwmd)
Definition: esc_dshot.c:82
void dshotSendFrame(DSHOTDriver *driver)
send throttle order
Definition: esc_dshot.c:302
#define TICK_FREQ
Definition: esc_dshot.c:77
void dshotSendSpecialCommand(DSHOTDriver *driver, const uint8_t index, const dshot_special_commands_t specmd)
send special order to one of the ESC (BHELIX, KISS, ...)
Definition: esc_dshot.c:239
DSHOT driver structure.
Definition: esc_dshot.h:228
#define DSHOT_BIT1_DUTY
Definition: esc_dshot.c:80
const DSHOTConfig * config
DMA config associated with pwm timer.
Definition: esc_dshot.h:232
#define DSHOT_ALL_MOTORS
special value for index : send order to all channels
Definition: esc_dshot.h:63
uint8_t crc8
Definition: esc_dshot.h:136
static DshotPacket makeDshotPacket(const uint16_t throttle, const bool tlmRequest)
Definition: esc_dshot.c:357
#define DSHOT_MAX_VALUE
Definition: esc_dshot.c:87
DMA stream configuration structure.
static void buildDshotDmaBuffer(DshotPackets *const dsp, DshotDmaBuffer *const dma, const size_t timerWidth)
Definition: esc_dshot.c:385
#define DSHOT_TELEMETRY_BAUD
Baudrate of the serial link used for telemetry data Can depend on the ESC, but only 115k have been us...
Definition: esc_dshot.c:55
SerialDriver * tlm_sd
if non null : dshot telemetry serial driver
Definition: esc_dshot.h:174
volatile uint8_t currentTlmQry
Definition: esc_dshot.h:220
DshotPackets dshotMotors
Definition: esc_dshot.h:269
#define STM32_PWM_USE_TIM2
Definition: mcuconf.h:249
const DshotTelemetry * dshotGetTelemetry(const DSHOTDriver *driver, const uint32_t index)
return last received telemetry data
Definition: esc_dshot.c:342
uint8_t dma_channel
: dma channel associated with pwm timer used to generate dshot output
Definition: esc_dshot.h:164
#define DSHOT_CHANNELS
Definition: esc_dshot.h:56
#define DSHOT_BIT0_DUTY
Definition: esc_dshot.c:79
#define ARRAY_LEN(a)
Definition: esc_dshot.c:84
MEMORY to PERIPHERAL.
Definition: hal_stm32_dma.h:89
mailbox_t mb
mailbox for dshot telemetry thread
Definition: esc_dshot.h:257
uint32_t crc_errors
number of crc errors
Definition: esc_dshot.h:262
static uint8_t updateCrc8(uint8_t crc, uint8_t crc_seed)
Definition: esc_dshot.c:415
bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
uint32_t dma_stream
: dma stream associated with pwm timer used to generate dshot output
Definition: esc_dshot.h:159
#define DSHOT_PRE_FRAME_SILENT_SYNC_BITS
Definition: esc_dshot.h:50
void dmaObjectInit(DMADriver *dmap)
Definition: hal_stm32_dma.c:56
dshot_special_commands_t
DSHOT special commands (0-47) for KISS and BLHELI ESC.
Definition: esc_dshot.h:91
static noreturn void dshotTlmRec(void *arg)
Definition: esc_dshot.c:462
DMADriver dmap
DMA driver associated with pwm timer.
Definition: esc_dshot.h:247
volatile dmastate_t state
Driver state.
DshotDmaBuffer * dma_buf
dshot dma buffer, sgould be defined in a non Dcached region
Definition: esc_dshot.h:179
DMAConfig dma_conf
DMA config associated with pwm timer.
Definition: esc_dshot.h:237
uint16_t rawFrame
Definition: esc_dshot.h:214
uint32_t dshotGetCrcErrorsCount(DSHOTDriver *driver)
return number of telemetry crc error since dshotStart
Definition: esc_dshot.c:329
DshotPacket dp[DSHOT_CHANNELS]
Definition: esc_dshot.h:218
static uint8_t calculateCrc8(const uint8_t *Buf, const uint8_t BufLen)
Definition: esc_dshot.c:427
volatile bool onGoingQry
Definition: esc_dshot.h:221
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
void dshotSendThrottles(DSHOTDriver *driver, const uint16_t throttles[DSHOT_CHANNELS])
send throttle packed order to all of the ESCs
Definition: esc_dshot.c:286
msg_t _mbBuf[1]
mailbox buffer for dshot telemetry thread
Definition: esc_dshot.h:252
uint16_t widths16[DSHOT_DMA_BUFFER_SIZE][DSHOT_CHANNELS]
Definition: esc_dshot.h:143
#define TICKS_PER_PERIOD
Ticks per period that let use any timer: does not care if linked to PCLK1 or PCLK2 tick_per_period wi...
Definition: esc_dshot.c:73
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
#define DSHOT_DMA_BUFFER_SIZE
Definition: esc_dshot.h:52
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
#define DSHOT_CHANNEL_FIRST_INDEX
Definition: esc_dshot.h:44