Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
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#include "mcu_periph/sys_time.h"
36
37/*
38# _ __ _ _ _ _
39# | | / _| (_) (_) | | (_)
40# __| | ___ | |_ _ _ __ _ | |_ _ ___ _ __
41# / _` | / _ \ | _| | | | '_ \ | | | __| | | / _ \ | '_ \
42# | (_| | | __/ | | | | | | | | | | \ |_ | | | (_) | | | | |
43# \__,_| \___| |_| |_| |_| |_| |_| \__| |_| \___/ |_| |_|
44*/
45
46
50#ifndef DSHOT_TELEMETRY_BAUD
51#define DSHOT_TELEMETRY_BAUD 115200U
52#endif
53
54#ifndef DSHOT_BIDIR_EXTENTED_TELEMETRY
55#define DSHOT_BIDIR_EXTENTED_TELEMETRY FALSE
56#endif
57
60#ifndef DSHOT_TELEMETRY_TIMEOUT_MS
61#define DSHOT_TELEMETRY_TIMEOUT_MS 3
62#endif
63
64
65#ifdef STM32H7XX
66// each H7 timer have the same max clock speed
67#define PWM_FREQ (STM32_TIMCLK1 / 1000U) // the timer will beat @240Mhz on STM32H7
68#else
69// some F4 and F7 timers are limited to / 2
70// others are limited to STM32_SYSCLK
71// so we take the max frequency that all timers can run
72#define PWM_FREQ (STM32_SYSCLK / 2000U) // the timer will beat @84Mhz on STM32F4
73#endif
74
75
82#define TICKS_PER_PERIOD 1000
83
84// ESCs are quite sensitive to the DSHOT duty cycle.
85// 333 should work most of the time, but some ESC need 373
86#ifndef DSHOT_BIT0_DUTY_RATIO
87#define DSHOT_BIT0_DUTY_RATIO 373U
88#endif
89
90#if DSHOT_SPEED != 0 // statically defined
91# define DSHOT_FREQ (DSHOT_SPEED*1000)
92# define DSHOT_BIT0_DUTY (DSHOT_PWM_PERIOD * DSHOT_BIT0_DUTY_RATIO / 1000U)
93# define DSHOT_BIT1_DUTY (DSHOT_BIT0_DUTY*2)
94#else // dynamically defined
95# define DSHOT_FREQ (driver->config->speed_khz * 1000U)
96# define DSHOT_BIT0_DUTY (driver->bit0Duty)
97# define DSHOT_BIT1_DUTY (driver->bit1Duty)
98#endif
99#define TICK_FREQ (PWM_FREQ * TICKS_PER_PERIOD)
100#define DSHOT_PWM_PERIOD (TICK_FREQ/DSHOT_FREQ)
101
102
103#define DCR_DBL ((DSHOT_CHANNELS-1) << 8) // DSHOT_CHANNELS transfert(s)
104// first register to get is CCR1
105#define DCR_DBA(pwmd) (((uint32_t *) (&pwmd->tim->CCR) - ((uint32_t *) pwmd->tim)))
106
107#define DSHOT_MAX_VALUE ((1U<<11U)-1U) // 11 bits used to send command, so maximum value is 2047
108
109#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
110#define Min(x,y) (x < y ? x : y)
111
112
113/*
114# _ __ _ _ _ _ _ __
115# | '_ \ | | | | | | | | | '_ \
116# | |_) | _ __ ___ | |_ ___ | |_ | |_| | | |_) | ___
117# | .__/ | '__| / _ \ | __| / _ \ | __| \__, | | .__/ / _ \
118# | | | | | (_) | \ |_ | (_) | \ |_ __/ | | | | __/
119# |_| |_| \___/ \__| \___/ \__| |___/ |_| \___|
120*/
121static DshotPacket makeDshotPacket(const uint16_t throttle, const bool tlmRequest);
122static void setCrc4(DshotPacket *dp);
123static inline void setDshotPacketThrottle(DshotPacket * const dp, const uint16_t throttle);
124static inline void setDshotPacketTlm(DshotPacket * const dp, const bool tlmRequest);
125static void buildDshotDmaBuffer(DSHOTDriver *driver);
126//static void buildDshotDmaBuffer(DshotPackets * const dsp, DshotDmaBuffer * const dma, const size_t timerWidth);
127static inline uint8_t updateCrc8(uint8_t crc, uint8_t crc_seed);
128static uint8_t calculateCrc8(const uint8_t *Buf, const uint8_t BufLen);
129static noreturn void dshotTlmRec (void *arg);
130static size_t getTimerWidth(const PWMDriver *pwmp);
131#if DSHOT_BIDIR
132static void processBidirErpm(DSHOTDriver *driver);
133static void dshotRestart(DSHOTDriver *driver);
134#if DSHOT_BIDIR_EXTENTED_TELEMETRY
136#endif
137#endif
138
139/*
140# _ __ _
141# | '_ \ (_)
142# __ _ | |_) | _
143# / _` | | .__/ | |
144# | (_| | | | | |
145# \__,_| |_| |_|
146*/
147
156{
157 chDbgAssert(config->dma_buf != NULL, ".dma_buf must reference valid DshotDmaBuffer object");
158
159#if DSHOT_BIDIR
160 dshotRpmCaptureStart(&driver->rpm_capture, &config->dma_capt_cfg, config->pwmp->tim);
161#endif
162
163 memset((void *) config->dma_buf, 0, sizeof(*(config->dma_buf)));
164 const size_t timerWidthInBytes = getTimerWidth(config->pwmp);
165
166 static const SerialConfig tlmcfg = {
167 .speed = DSHOT_TELEMETRY_BAUD,
168 .cr1 = 0, // pas de parité
169 .cr2 = USART_CR2_STOP1_BITS, // 1 bit de stop
170 .cr3 = 0 // pas de controle de flux hardware (CTS, RTS)
171 };
172 // when dshot is bidir, the polarity is inverted
174
175 driver->config = config;
176 // use pburst, mburst only if buffer size satisfy aligmnent requirement
177 driver->dma_conf = (DMAConfig) {
178 .stream = config->dma_stream,
179#if STM32_DMA_SUPPORTS_DMAMUX
180 .dmamux = config->dmamux,
181#else
182 .channel = config->dma_channel,
183#endif
184 .dma_priority = 3,
185 .irq_priority = CORTEX_MAX_KERNEL_PRIORITY + 1,
186 .direction = DMA_DIR_M2P,
187 .psize = timerWidthInBytes,
188 .msize = timerWidthInBytes,
189#if __DCACHE_PRESENT
190 .dcache_memory_in_use = config->dcache_memory_in_use,
191#endif
192 .inc_peripheral_addr = false,
193 .inc_memory_addr = true,
194 .op_mode = DMA_ONESHOT,
195 .error_cb = NULL,
196 .end_cb = NULL,
197 .pburst = 0,
198 .mburst = 0,
199 .fifo = 4
200 };
201
202 driver->pwm_conf = (PWMConfig) {
203 .frequency = TICK_FREQ,
204 .period = TICKS_PER_PERIOD,
205 .callback = NULL,
206 .channels = {
207 {.mode = pwmPolarity,
208 .callback = NULL},
210 .callback = NULL},
212 .callback = NULL},
214 .callback = NULL},
215 },
216 .cr2 = STM32_TIM_CR2_CCDS,
217 .dier = STM32_TIM_DIER_UDE
218 };
219
220 driver->crc_errors = 0;
221 driver->tlm_frame_nb = 0;
222#if DSHOT_SPEED == 0
223 driver->bit0Duty = (DSHOT_PWM_PERIOD * DSHOT_BIT0_DUTY_RATIO / 1000U);
224 driver->bit1Duty = (driver->bit0Duty*2U) ;
225#endif
226
227
228
229 dmaObjectInit(&driver->dmap);
230 chMBObjectInit(&driver->mb, driver->_mbBuf, ARRAY_LEN(driver->_mbBuf));
231
232 const bool dmaOk = dmaStart(&driver->dmap, &driver->dma_conf);
233 chDbgAssert(dmaOk == true, "dshot dma start error");
234
235 if (driver->config->tlm_sd) {
236 sdStart(driver->config->tlm_sd, &tlmcfg);
237 chThdCreateStatic(driver->waDshotTlmRec, sizeof(driver->waDshotTlmRec), NORMALPRIO,
238 dshotTlmRec, driver);
239 }
240
241 pwmStart(driver->config->pwmp, &driver->pwm_conf);
242 driver->config->pwmp->tim->DCR = DCR_DBL | DCR_DBA(driver->config->pwmp); // enable bloc register DMA transaction
244
245 for (size_t j=0; j<DSHOT_CHANNELS; j++) {
246 pwmEnableChannel(driver->config->pwmp, j, 0);
247 driver->dshotMotors.dp[j] = makeDshotPacket(0,0);
249 }
250 driver->dshotMotors.onGoingQry = false;
251 driver->dshotMotors.currentTlmQry = 0U;
252}
253
262{
263 pwmStop(driver->config->pwmp);
264 dmaStopTransfert(&driver->dmap);
265 dmaStop(&driver->dmap);
266}
267
268#if DSHOT_BIDIR
276static void dshotRestart(DSHOTDriver *driver)
277{
278 const bool dmaOk = dmaStart(&driver->dmap, &driver->dma_conf);
279 chDbgAssert(dmaOk == true, "dshot dma start error");
280
281 pwmStart(driver->config->pwmp, &driver->pwm_conf);
282 driver->config->pwmp->tim->DCR = DCR_DBL | DCR_DBA(driver->config->pwmp); // enable bloc register DMA transaction
284
285 for (size_t j=0; j<DSHOT_CHANNELS; j++) {
286 pwmEnableChannel(driver->config->pwmp, j, 0);
287 driver->dshotMotors.dp[j] = makeDshotPacket(0,0);
288 }
289}
290#endif
291
302void dshotSetThrottle(DSHOTDriver *driver, const uint8_t index,
303 const uint16_t throttle)
304{
305 if (throttle > 0 && throttle <= DSHOT_CMD_MAX) {
306 chDbgAssert(false, "dshotSetThrottle throttle error");
307 return; // special commands (except MOTOR_STOP) can't be applied from this function
308 } else {
309 // send normal throttle
310 if (index == DSHOT_ALL_MOTORS) {
311 for (uint8_t _index = 0; _index < DSHOT_CHANNELS; _index++) {
313 }
314 } else if ((index - DSHOT_CHANNEL_FIRST_INDEX) < DSHOT_CHANNELS) {
316 Min(throttle, DSHOT_MAX_VALUE));
317 } else {
318 chDbgAssert(false, "dshotSetThrottle index error");
319 }
320 }
321}
322
333{
334 if (specmd > DSHOT_CMD_MAX) {
335 return; // Don't apply special commands from this function
336 }
337
338 // some dangerous special commands need to be repeated 6 times
339 // to avoid catastrophic failure
341 switch (specmd) {
352 repeat = 10;
353 break;
354 default:
355 repeat = 1;
356 }
357
358 while (repeat--) {
360 if (index < DSHOT_CHANNELS) {
362 setDshotPacketTlm(&driver->dshotMotors.dp[index], driver->config->tlm_sd != NULL);
363 } else if (index == DSHOT_ALL_MOTORS) {
364 for (uint8_t _index = 0; _index < DSHOT_CHANNELS; _index++) {
366 setDshotPacketTlm(&driver->dshotMotors.dp[_index], driver->config->tlm_sd != NULL);
367 }
368 } else {
369 chDbgAssert(false, "dshotSetThrottle index error");
370 }
371 dshotSendFrame(driver);
372 if (repeat)
374 }
375}
376
387{
388 for (uint8_t index = 0; index < DSHOT_CHANNELS; index++) {
389 setDshotPacketThrottle(&driver->dshotMotors.dp[index], throttles[index]);
390 }
391
392 dshotSendFrame(driver);
393}
394
395
396
397
406{
407 if (driver->dmap.state == DMA_READY) {
408#if DSHOT_BIDIR
410#endif
411 if ((driver->config->tlm_sd != NULL) &&
412 (driver->dshotMotors.onGoingQry == false)) {
413 driver->dshotMotors.onGoingQry = true;
414 const msg_t index = (driver->dshotMotors.currentTlmQry + 1U) % DSHOT_CHANNELS;
415 driver->dshotMotors.currentTlmQry = (uint8_t) index;
416 setDshotPacketTlm(&driver->dshotMotors.dp[index], true);
417 chMBPostTimeout(&driver->mb, index, TIME_IMMEDIATE);
418 }
419
420 //buildDshotDmaBuffer(&driver->dshotMotors, driver->config->dma_buf, getTimerWidth(driver->config->pwmp));
421 buildDshotDmaBuffer(driver);
422 dmaTransfert(&driver->dmap,
423 &driver->config->pwmp->tim->DMAR,
425
426#if DSHOT_BIDIR
427 dshotStop(driver);
428 dshotRpmCatchErps(&driver->rpm_capture);
429 processBidirErpm(driver);
430 dshotRestart(driver);
432#endif
433 }
434}
435
444{
445 return driver->crc_errors;
446}
447
456{
457 return driver->tlm_frame_nb;
458}
459
460
470{
472 chDbgAssert(index < DSHOT_CHANNELS, "dshot index error");
473 chMtxLock(&driver->dshotMotors.tlmMtx[index]);
474 const DshotTelemetry tlm = driver->dshotMotors.dt[index];
475 chMtxUnlock(&driver->dshotMotors.tlmMtx[index]);
476 return tlm;
477}
478
479/*
480
481 [2] 0010 mmmm mmmm - Temperature frame in degree Celsius, just like Blheli_32 and KISS [0, 1, ..., 255]
482 [4] 0100 mmmm mmmm - Voltage frame with a step size of 0,25V [0, 0.25 ..., 63,75]
483 [6] 0110 mmmm mmmm - Current frame with a step size of 1A [0, 1, ..., 255]
484 [8] 1000 mmmm mmmm - Debug frame 1 not associated with any specific value, can be used to debug ESC firmware
485 [10] 1010 mmmm mmmm - Debug frame 2 not associated with any specific value, can be used to debug ESC firmware
486 [12] 1100 mmmm mmmm - Stress level frame [0, 1, ..., 255] (since v2.0.0)
487 [14] 1110 mmmm mmmm - Status frame: Bit[7] = alert event, Bit[6] = warning event, Bit[5] = error event, Bit[3-1] - Max. stress level [0-15] (since v2.0.0)
488
489 */
490#if DSHOT_BIDIR && DSHOT_BIDIR_EXTENTED_TELEMETRY
492{
493 switch(DshotErpsEdtType(erps)) {
494 case EDT_TEMP:
495 tlm->frame.temp = DshotErpsEdtTempCentigrade(erps); break;
496
497 case EDT_VOLT:
498 tlm->frame.voltage = DshotErpsEdtCentiVolts(erps); break;
499
500 case EDT_CURRENT:
501 tlm->frame.current = DshotErpsEdtCurrentAmp(erps) * 100U; break;
502
503 case EDT_STRESS:
504 tlm->stress = DshotErpsEdtStress(erps); break;
505
506 case EDT_STATUS:
507 tlm->status = DshotErpsEdtStatus(erps);break;
508
509 default: {};
510 }
511 tlm->ts = chVTGetSystemTimeX();
512}
513#endif
514
515#if DSHOT_BIDIR
526uint32_t dshotGetEperiod(DSHOTDriver *driver, const uint32_t index)
527{
528 chDbgAssert(index < DSHOT_CHANNELS, "index check failed");
529 DshotErpsSetFromFrame(&driver->erps, driver->rpms_frame[index]);
530 if (DshotErpsCheckCrc4(&driver->erps)) {
531#if DSHOT_BIDIR_EXTENTED_TELEMETRY
532 if (DshotErpsIsEdt(&driver->erps)) {
533 if (driver->config->tlm_sd == NULL) {
534 DshotTelemetry *tlm = &driver->dshotMotors.dt[index];
535 updateTelemetryFromBidirEdt(&driver->erps, tlm);
536 }
537 return DSHOT_BIDIR_TLM_EDT;
538 }
539#endif
540 return DshotErpsGetEperiod(&driver->erps);
541 } else {
542 return DSHOT_BIDIR_ERR_CRC;
543 }
544}
556{
558 chDbgAssert(index < DSHOT_CHANNELS, "index check failed");
559 DshotErpsSetFromFrame(&driver->erps, driver->rpms_frame[index]);
560 if (DshotErpsCheckCrc4(&driver->erps)) {
561#if DSHOT_BIDIR_EXTENTED_TELEMETRY
562 if (DshotErpsIsEdt(&driver->erps)) {
563 if (driver->config->tlm_sd == NULL) {
564 DshotTelemetry *tlm = &driver->dshotMotors.dt[index];
565 updateTelemetryFromBidirEdt(&driver->erps, tlm);
566 }
567 return DSHOT_BIDIR_TLM_EDT;
568 }
569#endif
570 return DshotErpsGetRpm(&driver->erps);
571 } else {
572 return DSHOT_BIDIR_ERR_CRC;
573 }
574}
575#endif
576
577
578
579/*
580# _ __ _ _
581# | '_ \ (_) | |
582# | |_) | _ __ _ __ __ __ _ | |_ ___
583# | .__/ | '__| | | \ \ / / / _` | | __| / _ \
584# | | | | | | \ V / | (_| | \ |_ | __/
585# |_| |_| |_| \_/ \__,_| \__| \___|
586*/
587
588static void setCrc4(DshotPacket *dp)
589{
590 // compute checksum
591 dp->crc = 0;
592 uint16_t csum = (dp->throttle << 1) | dp->telemetryRequest;
593 for (int i = 0; i < 3; i++) {
594 dp->crc ^= csum; // xor data by nibbles
595 csum >>= 4;
596 }
597#if DSHOT_BIDIR
598 dp->crc = ~(dp->crc); // crc is inverted when dshot bidir protocol is choosed
599#endif
600}
601
603{
604 DshotPacket dp = {.throttle = _throttle,
605 .telemetryRequest = (tlmRequest ? 1 : 0),
606 .crc = 0
607 };
608
609 setCrc4(&dp);
610 return dp;
611}
612
613static inline void setDshotPacketThrottle(DshotPacket *const dp, const uint16_t throttle)
614{
615 dp->throttle = throttle;
616 dp->telemetryRequest = 0;
617}
618
619static inline void setDshotPacketTlm(DshotPacket *const dp, const bool tlmRequest)
620{
621 dp->telemetryRequest = tlmRequest ? 1 : 0;
622}
623
625{
626 DshotPackets *const dsp = &driver->dshotMotors;
627 DshotDmaBuffer *const dma = driver->config->dma_buf;
628 const size_t timerWidth = getTimerWidth(driver->config->pwmp);
629
630 for (size_t chanIdx = 0; chanIdx < DSHOT_CHANNELS; chanIdx++) {
631 // compute checksum
632 DshotPacket * const dp = &dsp->dp[chanIdx];
633 setCrc4(dp);
634 // generate pwm frame
635 for (size_t bitIdx = 0; bitIdx < DSHOT_BIT_WIDTHS; bitIdx++) {
636 const uint16_t value = dp->rawFrame &
637 (1 << ((DSHOT_BIT_WIDTHS - 1) - bitIdx)) ?
639 if (timerWidth == 2) {
641 } else {
642#if DSHOT_AT_LEAST_ONE_32B_TIMER
643 dma->widths32[bitIdx+DSHOT_PRE_FRAME_SILENT_SYNC_BITS][chanIdx] = value;
644#else
645 chSysHalt("use of 32 bit timer implies to define DSHOT_AT_LEAST_ONE_32B_TIMER to TRUE");
646#endif
647 }
648 }
649 // the bits for silence sync (pre and post) in case of continous sending are zeroed once at init
650 }
651}
652
653
654static inline uint8_t updateCrc8(uint8_t crc, uint8_t crc_seed)
655{
656 uint8_t crc_u = crc;
657 crc_u ^= crc_seed;
658
659 for (int i = 0; i < 8; i++) {
660 crc_u = (crc_u & 0x80) ? 0x7 ^ (crc_u << 1) : (crc_u << 1);
661 }
662
663 return (crc_u);
664}
665
667{
668 uint8_t crc = 0;
669 for (int i = 0; i < BufLen; i++) {
670 crc = updateCrc8(Buf[i], crc);
671 }
672
673 return crc;
674}
675
676
677#if DSHOT_BIDIR
678static void processBidirErpm(DSHOTDriver *driver)
679{
680 for (size_t idx = 0; idx < DSHOT_CHANNELS; idx++) {
681 driver->rpms_frame[idx] = dshotRpmGetFrame(&driver->rpm_capture, idx);
682 }
683}
684#endif
685
686
687__attribute__((const))
689{
690 (void) pwmp;
691
692 return (0
694 || (pwmp == &PWMD2)
695#endif
696#if STM32_PWM_USE_TIM5
697 || (pwmp == &PWMD5)
698#endif
699 ) ? 4 : 2;
700}
701
702
703/*
704# _ _ _
705# | | | | | |
706# | |_ | |__ _ __ ___ __ _ __| | ___
707# | __| | '_ \ | '__| / _ \ / _` | / _` | / __|
708# \ |_ | | | | | | | __/ | (_| | | (_| | \__ \
709# \__| |_| |_| |_| \___| \__,_| \__,_| |___/
710*/
711
712
713static noreturn void dshotTlmRec(void *arg)
714{
715 DSHOTDriver *driver = (DSHOTDriver *) arg;
717
718 msg_t escIdx = 0;
719
720 chRegSetThreadName("dshotTlmRec");
721 while (true) {
723 const uint32_t idx = escIdx;
724 const bool success =
725 (sdReadTimeout(driver->config->tlm_sd, tlm.frame.rawData, sizeof(DshotTelemetryFrame),
727 if (!success ||
728 (calculateCrc8(tlm.frame.rawData, sizeof(tlm.frame.rawData)) != tlm.frame.crc8)) {
729 // empty buffer to resync
730 while (sdGetTimeout(driver->config->tlm_sd, TIME_IMMEDIATE) >= 0) {};
731 memset(tlm.frame.rawData, 0U, sizeof(DshotTelemetry));
732 // count errors
733 if (success)
734 driver->crc_errors++;
735 } else {
736 // big-endian to little-endian conversion
737 tlm.frame.voltage = __builtin_bswap16(tlm.frame.voltage);
738 tlm.frame.current = __builtin_bswap16(tlm.frame.current);
739 tlm.frame.consumption = __builtin_bswap16(tlm.frame.consumption);
740 tlm.frame.rpm = __builtin_bswap16(tlm.frame.rpm);
741 tlm.ts = chVTGetSystemTimeX();
742 driver->tlm_frame_nb++;
743 }
744
745 chMtxLock(&driver->dshotMotors.tlmMtx[idx]);
746 driver->dshotMotors.dt[idx] = tlm;
748 driver->dshotMotors.onGoingQry = false;
749 }
750}
751
uint32_t DshotErpsGetRpm(const DshotErps *derpsp)
calculate and return rpm
Definition dshot_erps.c:87
uint32_t DshotErpsGetEperiod(const DshotErps *derpsp)
return eperiod from mantisse and exponent
Definition dshot_erps.c:72
const DshotErps * DshotErpsSetFromFrame(DshotErps *derpsp, uint32_t frame)
initialise from GCR encoded frame
Definition dshot_erps.c:44
bool DshotErpsCheckCrc4(const DshotErps *derpsp)
check packed validity
Definition dshot_erps.c:99
static uint16_t DshotErpsEdtStatus(const DshotErps *derpsp)
return status value
Definition dshot_erps.h:144
@ EDT_CURRENT
Definition dshot_erps.h:16
@ EDT_STATUS
Definition dshot_erps.h:18
@ EDT_STRESS
Definition dshot_erps.h:17
@ EDT_VOLT
Definition dshot_erps.h:16
@ EDT_TEMP
Definition dshot_erps.h:16
static uint8_t DshotErpsEdtTempCentigrade(const DshotErps *derpsp)
return temperature for a temperature telemetry frame
Definition dshot_erps.h:106
static uint16_t DshotErpsEdtStress(const DshotErps *derpsp)
return stress value
Definition dshot_erps.h:134
static EdtType DshotErpsEdtType(const DshotErps *derpsp)
return type of a telemetry frame
Definition dshot_erps.h:97
static uint16_t DshotErpsEdtCentiVolts(const DshotErps *derpsp)
return voltage for a voltage telemetry frame
Definition dshot_erps.h:115
static uint16_t DshotErpsEdtCurrentAmp(const DshotErps *derpsp)
return current intensity for a current telemetry frame
Definition dshot_erps.h:124
static bool DshotErpsIsEdt(const DshotErps *derpsp)
return true if current frame is a telemetry frame
Definition dshot_erps.h:84
ERPS complete frame, raw and decoded.
Definition dshot_erps.h:58
void dshotRpmCaptureStart(DshotRpmCapture *drcp, const DshotRpmCaptureConfig *cfg, stm32_tim_t *timer)
Configures and activates the DSHOT ERPS CAPTURE driver.
void dshotRpmCatchErps(DshotRpmCapture *drcp)
capture the DSHOT ERPS frame(s) : one frame for each DSHOT_CHANNELS
static uint32_t dshotRpmGetFrame(const DshotRpmCapture *drcp, uint8_t index)
return last collected erps frame
static void buildDshotDmaBuffer(DSHOTDriver *driver)
Definition esc_dshot.c:624
void dshotStart(DSHOTDriver *driver, const DSHOTConfig *config)
Configures and activates the DSHOT peripheral.
Definition esc_dshot.c:155
void dshotSetThrottle(DSHOTDriver *driver, const uint8_t index, const uint16_t throttle)
prepare throttle order for specified ESC
Definition esc_dshot.c:302
static size_t getTimerWidth(const PWMDriver *pwmp)
Definition esc_dshot.c:688
#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:82
#define Min(x, y)
Definition esc_dshot.c:110
uint32_t dshotGetTelemetryFrameCount(const DSHOTDriver *driver)
return number of telemetry succesfull frame since dshotStart
Definition esc_dshot.c:455
#define TICK_FREQ
Definition esc_dshot.c:99
static uint8_t calculateCrc8(const uint8_t *Buf, const uint8_t BufLen)
Definition esc_dshot.c:666
#define DSHOT_MAX_VALUE
Definition esc_dshot.c:107
DshotTelemetry dshotGetTelemetry(DSHOTDriver *driver, uint32_t index)
return last received telemetry data
Definition esc_dshot.c:469
static void setDshotPacketThrottle(DshotPacket *const dp, const uint16_t throttle)
Definition esc_dshot.c:613
void dshotSendThrottles(DSHOTDriver *driver, const uint16_t throttles[DSHOT_CHANNELS])
send throttle packed order to all of the ESCs
Definition esc_dshot.c:386
static void setCrc4(DshotPacket *dp)
Definition esc_dshot.c:588
#define DSHOT_BIT0_DUTY
Definition esc_dshot.c:96
uint32_t dshotGetCrcErrorCount(const DSHOTDriver *driver)
return number of telemetry crc error since dshotStart
Definition esc_dshot.c:443
#define DCR_DBA(pwmd)
Definition esc_dshot.c:105
void dshotStop(DSHOTDriver *driver)
stop the DSHOT driver and free the related resources : pwm driver and dma driver.
Definition esc_dshot.c:261
#define DSHOT_TELEMETRY_TIMEOUT_MS
Telemetry timeout in ms.
Definition esc_dshot.c:61
#define DSHOT_BIT0_DUTY_RATIO
Definition esc_dshot.c:87
void dshotSendFrame(DSHOTDriver *driver)
send throttle order
Definition esc_dshot.c:405
static noreturn void dshotTlmRec(void *arg)
Definition esc_dshot.c:713
#define ARRAY_LEN(a)
Definition esc_dshot.c:109
static void setDshotPacketTlm(DshotPacket *const dp, const bool tlmRequest)
Definition esc_dshot.c:619
#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:51
#define DSHOT_PWM_PERIOD
Definition esc_dshot.c:100
#define DSHOT_BIT1_DUTY
Definition esc_dshot.c:97
static DshotPacket makeDshotPacket(const uint16_t throttle, const bool tlmRequest)
Definition esc_dshot.c:602
#define DCR_DBL
Definition esc_dshot.c:103
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:331
static uint8_t updateCrc8(uint8_t crc, uint8_t crc_seed)
Definition esc_dshot.c:654
DSHOT driver based on ChibiOS.
mutex_t tlmMtx[DSHOT_CHANNELS]
Definition esc_dshot.h:278
#define DSHOT_PRE_FRAME_SILENT_SYNC_BITS
Definition esc_dshot.h:49
SerialDriver * tlm_sd
if non null : dshot telemetry serial driver
Definition esc_dshot.h:205
#define DSHOT_BIT_WIDTHS
DMA buffer size and number of channels.
Definition esc_dshot.h:48
volatile bool onGoingQry
Definition esc_dshot.h:279
PWMDriver * pwmp
PWM driver that feed up to 4 dshot lines.
Definition esc_dshot.h:200
#define DSHOT_DMA_BUFFER_SIZE
Definition esc_dshot.h:51
uint16_t widths16[DSHOT_DMA_BUFFER_SIZE][DSHOT_CHANNELS]
Definition esc_dshot.h:170
#define DSHOT_CHANNEL_FIRST_INDEX
Definition esc_dshot.h:43
DshotTelemetry dt[DSHOT_CHANNELS]
Definition esc_dshot.h:277
uint16_t rawFrame
Definition esc_dshot.h:271
#define DSHOT_ALL_MOTORS
special value for index : send order to all channels
Definition esc_dshot.h:74
#define DSHOT_BIDIR_TLM_EDT
Definition esc_dshot.h:66
DshotDmaBuffer * dma_buf
dshot dma buffer, should be defined in a non Dcached region
Definition esc_dshot.h:210
dshot_special_commands_t
DSHOT special commands (0-47) for KISS and BLHELI ESC.
Definition esc_dshot.h:102
@ DSHOT_CMD_SILENT_MODE_ON_OFF
Definition esc_dshot.h:129
@ DSHOT_CMD_SAVE_SETTINGS
Definition esc_dshot.h:115
@ DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF
Definition esc_dshot.h:128
@ DSHOT_CMD_SETTINGS_REQUEST
Definition esc_dshot.h:114
@ DSHOT_CMD_BIDIR_EDT_MODE_OFF
Definition esc_dshot.h:117
@ DSHOT_CMD_SPIN_DIRECTION_1
Definition esc_dshot.h:110
@ DSHOT_CMD_SPIN_DIRECTION_2
Definition esc_dshot.h:111
@ DSHOT_CMD_3D_MODE_OFF
Definition esc_dshot.h:112
@ DSHOT_CMD_MAX
Definition esc_dshot.h:130
@ DSHOT_CMD_3D_MODE_ON
Definition esc_dshot.h:113
@ DSHOT_CMD_BIDIR_EDT_MODE_ON
Definition esc_dshot.h:116
#define DSHOT_BIDIR_ERR_CRC
special values returned by dshotGetRpm function
Definition esc_dshot.h:65
uint8_t currentTlmQry
Definition esc_dshot.h:280
DshotPacket dp[DSHOT_CHANNELS]
Definition esc_dshot.h:276
DSHOT Driver configuration structure.
Definition esc_dshot.h:182
telemetry with timestamp
Definition esc_dshot.h:158
telemetry packed as sent by some KISS ESC
Definition esc_dshot.h:139
#define DSHOT_CHANNELS
#define DSHOT_BIDIR
void dmaObjectInit(DMADriver *dmap)
void dmaStop(DMADriver *dmap)
Deactivates the DMA peripheral.
void dmaStopTransfert(DMADriver *dmap)
Stops an ongoing transaction.
bool dmaStart(DMADriver *dmap, const DMAConfig *cfg)
Configures and activates the DMA peripheral.
@ DMA_ONESHOT
One transert then stop
@ DMA_DIR_M2P
MEMORY to PERIPHERAL
uint32_t stream
stream associated with transaction
static msg_t dmaTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
@ DMA_READY
Ready.
volatile dmastate_t state
Driver state.
DMA stream configuration structure.
uint16_t foo
Definition main_demo5.c:58
#define STM32_PWM_USE_TIM2
Definition mcuconf_h7.h:419
static uint32_t idx
static const struct usb_config_descriptor config
Definition usb_ser_hw.c:200
DSHOT driver structure.
Definition esc_dshot.h:287
uint32_t crc_errors
number of crc errors
Definition esc_dshot.h:321
DshotPackets dshotMotors
object managing dma control frame for outgoing command
Definition esc_dshot.h:356
mailbox_t mb
mailbox for dshot telemetry thread
Definition esc_dshot.h:316
DMADriver dmap
DMA driver associated with pwm timer.
Definition esc_dshot.h:306
PWMConfig pwm_conf
PWM config associated with pwm timer.
Definition esc_dshot.h:301
uint16_t bit1Duty
Definition esc_dshot.h:330
const DSHOTConfig * config
DMA config associated with pwm timer.
Definition esc_dshot.h:291
msg_t _mbBuf[1]
mailbox buffer for dshot telemetry thread
Definition esc_dshot.h:311
uint32_t tlm_frame_nb
number of sucessful telemetry frame received
Definition esc_dshot.h:326
DMAConfig dma_conf
DMA config associated with pwm timer.
Definition esc_dshot.h:296
uint16_t bit0Duty
Definition esc_dshot.h:329
Architecture independent timing functions.
Implementation of system time functions for ChibiOS arch.
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.