31 #include <stdnoreturn.h>
48 #define DSHOT_SPEED 600
54 #ifndef DSHOT_TELEMETRY_BAUD
55 #define DSHOT_TELEMETRY_BAUD 115200
60 #ifndef DSHOT_TELEMETRY_TIMEOUT_MS
61 #define DSHOT_TELEMETRY_TIMEOUT_MS 3
65 #define PWM_FREQ (STM32_SYSCLK/2000)
73 #define TICKS_PER_PERIOD 1000
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)))
84 #define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
85 #define Min(x,y) (x < y ? x : y)
87 #define DSHOT_MAX_VALUE ((1<<11)-1) // 11 bits used to send command, so maximum value is 2047
126 static const SerialConfig tlmcfg = {
129 .cr2 = USART_CR2_STOP1_BITS,
141 .psize = timerWidthInBytes,
142 .msize = timerWidthInBytes,
143 .inc_peripheral_addr =
false,
144 .inc_memory_addr =
true,
160 .mode = PWM_OUTPUT_ACTIVE_HIGH,
164 .mode =
DSHOT_CHANNELS > 1 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED,
168 .mode =
DSHOT_CHANNELS > 2 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED,
172 .mode =
DSHOT_CHANNELS > 3 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED,
176 .cr2 = STM32_TIM_CR2_CCDS,
177 .dier = STM32_TIM_DIER_UDE
181 memset(&driver->
dsdb, 0UL,
sizeof(driver->
dsdb));
190 chThdCreateStatic(driver->waDshotTlmRec,
sizeof(driver->waDshotTlmRec), NORMALPRIO,
274 chThdSleepMilliseconds(1);
361 .telemetryRequest = (tlmRequest ? 1 : 0),
366 uint16_t csum = (_throttle << 1) | dp.telemetryRequest;
367 for (
int i = 0; i < 3; i++) {
377 dp->throttle = throttle;
378 dp->telemetryRequest = 0;
383 dp->telemetryRequest = tlmRequest ? 1 : 0;
392 uint16_t csum = (dp->throttle << 1) | dp->telemetryRequest;
393 for (
int i = 0; i < 3; i++) {
400 (1 << ((DSHOT_BIT_WIDTHS - 1) - bitIdx)) ?
402 if (timerWidth == 2) {
403 dma->
widths16[bitIdx][chanIdx] = value;
405 #if DSHOT_AT_LEAST_ONE_32B_TIMER
406 dma->widths32[bitIdx][chanIdx] = value;
408 chSysHalt(
"use of 32 bit timer implies to define DSHOT_AT_LEAST_ONE_32B_TIMER to TRUE");
421 for (
int i = 0; i < 8; i++) {
422 crc_u = (crc_u & 0x80) ? 0x7 ^ (crc_u << 1) : (crc_u << 1);
431 for (
int i = 0; i < BufLen; i++) {
438 __attribute__((
const))
447 #if STM32_PWM_USE_TIM5
469 chRegSetThreadName(
"dshotTlmRec");
471 chMBFetchTimeout(&driver->
mb, (msg_t *) &escIdx, TIME_INFINITE);
480 while (sdGetTimeout(driver->
config->
tlm_sd, TIME_IMMEDIATE) >= 0) {};
#define DSHOT_TELEMETRY_TIMEOUT_MS
Telemetry timeout in ms.
DSHOT driver based on ChibiOS.
telemetry packed as sent by some KISS ESC
#define DSHOT_BIT_WIDTHS
DMA buffer size and number of channels.
static void setDshotPacketTlm(DshotPacket *const dp, const bool tlmRequest)
bool dmaStart(DMADriver *dmap, const DMAConfig *cfg)
Configures and activates the DMA peripheral.
DshotTelemetry dt[DSHOT_CHANNELS]
PWMConfig pwm_conf
PWM config associated with pwm timer.
static size_t getTimerWidth(const PWMDriver *pwmp)
uint32_t stream
stream associated with transaction
DSHOT Driver configuration structure.
PWMDriver * pwmp
PWM driver that feed up to 4 dshot lines.
static void setDshotPacketThrottle(DshotPacket *const dp, const uint16_t throttle)
void dshotStart(DSHOTDriver *driver, const DSHOTConfig *config)
Configures and activates the DSHOT peripheral.
void dshotSetThrottle(DSHOTDriver *driver, const uint8_t index, const uint16_t throttle)
prepare throttle order for specified ESC
void dshotSendFrame(DSHOTDriver *driver)
send throttle order
void dshotSendSpecialCommand(DSHOTDriver *driver, const uint8_t index, const dshot_special_commands_t specmd)
send special order to one of the ESC (BHELIX, KISS, ...)
const DSHOTConfig * config
DMA config associated with pwm timer.
dmastate_t state
Driver state.
#define DSHOT_ALL_MOTORS
special value for index : send order to all channels
static DshotPacket makeDshotPacket(const uint16_t throttle, const bool tlmRequest)
DMA stream configuration structure.
static void buildDshotDmaBuffer(DshotPackets *const dsp, DshotDmaBuffer *const dma, const size_t timerWidth)
#define DSHOT_TELEMETRY_BAUD
Baudrate of the serial link used for telemetry data Can depend on the ESC, but only 115k have been us...
SerialDriver * tlm_sd
if non null : dshot telemetry serial driver
volatile uint8_t currentTlmQry
#define STM32_PWM_USE_TIM2
const DshotTelemetry * dshotGetTelemetry(const DSHOTDriver *driver, const uint32_t index)
return last received telemetry data
uint8_t dma_channel
: dma channel associated with pwm timer used to generate dshot output
mailbox_t mb
mailbox for dshot telemetry thread
uint32_t crc_errors
number of crc errors
static uint8_t updateCrc8(uint8_t crc, uint8_t crc_seed)
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
static const struct usb_config_descriptor config
void dmaObjectInit(DMADriver *dmap)
dshot_special_commands_t
DSHOT special commands (0-47) for KISS and BLHELI ESC.
static noreturn void dshotTlmRec(void *arg)
DMADriver dmap
DMA driver associated with pwm timer.
DMAConfig dma_conf
DMA config associated with pwm timer.
uint32_t dshotGetCrcErrorsCount(DSHOTDriver *driver)
return number of telemetry crc error since dshotStart
DshotPacket dp[DSHOT_CHANNELS]
static uint8_t calculateCrc8(const uint8_t *Buf, const uint8_t BufLen)
void dshotSendThrottles(DSHOTDriver *driver, const uint16_t throttles[DSHOT_CHANNELS])
send throttle packed order to all of the ESCs
msg_t _mbBuf[1]
mailbox buffer for dshot telemetry thread
uint16_t widths16[DSHOT_DMA_BUFFER_SIZE][DSHOT_CHANNELS]
#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...
#define DSHOT_DMA_BUFFER_SIZE