diff --git a/Makefile b/Makefile
index a0540d557c..3b7ab5634c 100644
--- a/Makefile
+++ b/Makefile
@@ -534,6 +534,7 @@ STM32F30x_COMMON_SRC = \
drivers/dma.c \
drivers/gpio_stm32f30x.c \
drivers/light_ws2811strip_stm32f30x.c \
+ drivers/pwm_output_stm32f3xx.c \
drivers/serial_uart_stm32f30x.c \
drivers/system_stm32f30x.c \
drivers/timer_stm32f30x.c
@@ -548,6 +549,7 @@ STM32F4xx_COMMON_SRC = \
drivers/gpio_stm32f4xx.c \
drivers/inverter.c \
drivers/light_ws2811strip_stm32f4xx.c \
+ drivers/pwm_output_stm32f4xx.c \
drivers/serial_uart_stm32f4xx.c \
drivers/system_stm32f4xx.c \
drivers/timer_stm32f4xx.c
diff --git a/src/main/drivers/pwm_output.c b/src/main/drivers/pwm_output.c
index af832c00e0..82a286417d 100644
--- a/src/main/drivers/pwm_output.c
+++ b/src/main/drivers/pwm_output.c
@@ -29,6 +29,7 @@
#define MULTISHOT_20US_MULT (MULTISHOT_TIMER_MHZ * 20 / 1000.0f)
static pwmOutputPort_t motors[MAX_SUPPORTED_MOTORS];
+static pwmCompleteWriteFuncPtr pwmCompleteWritePtr = NULL;
#ifdef USE_SERVOS
static pwmOutputPort_t servos[MAX_SUPPORTED_SERVOS];
@@ -153,7 +154,7 @@ void pwmEnableMotors(void)
pwmMotorsEnabled = true;
}
-void pwmCompleteOneshotMotorUpdate(uint8_t motorCount)
+static void pwmCompleteOneshotMotorUpdate(uint8_t motorCount)
{
for (int index = 0; index < motorCount; index++) {
bool overflowed = false;
@@ -173,40 +174,59 @@ void pwmCompleteOneshotMotorUpdate(uint8_t motorCount)
}
}
+void pwmCompleteMotorUpdate(uint8_t motorCount)
+{
+ if (pwmCompleteWritePtr) {
+ pwmCompleteWritePtr(motorCount);
+ }
+}
+
void motorInit(const motorConfig_t *motorConfig, uint16_t idlePulse, uint8_t motorCount)
{
uint32_t timerMhzCounter;
pwmWriteFuncPtr pwmWritePtr;
bool useUnsyncedPwm = motorConfig->useUnsyncedPwm;
-
+ bool isDigital = false;
+
switch (motorConfig->motorPwmProtocol) {
default:
- case (PWM_TYPE_ONESHOT125):
+ case PWM_TYPE_ONESHOT125:
timerMhzCounter = ONESHOT125_TIMER_MHZ;
pwmWritePtr = pwmWriteOneShot125;
break;
- case (PWM_TYPE_ONESHOT42):
+ case PWM_TYPE_ONESHOT42:
timerMhzCounter = ONESHOT42_TIMER_MHZ;
pwmWritePtr = pwmWriteOneShot42;
break;
- case (PWM_TYPE_MULTISHOT):
+ case PWM_TYPE_MULTISHOT:
timerMhzCounter = MULTISHOT_TIMER_MHZ;
pwmWritePtr = pwmWriteMultiShot;
break;
- case (PWM_TYPE_BRUSHED):
+ case PWM_TYPE_BRUSHED:
timerMhzCounter = PWM_BRUSHED_TIMER_MHZ;
pwmWritePtr = pwmWriteBrushed;
useUnsyncedPwm = true;
idlePulse = 0;
break;
- case (PWM_TYPE_STANDARD):
+ case PWM_TYPE_STANDARD:
timerMhzCounter = PWM_TIMER_MHZ;
pwmWritePtr = pwmWriteStandard;
useUnsyncedPwm = true;
idlePulse = 0;
break;
+#ifdef USE_DSHOT
+ case PWM_TYPE_DSHOT600:
+ case PWM_TYPE_DSHOT150:
+ pwmCompleteWritePtr = pwmCompleteDigitalMotorUpdate;
+ isDigital = true;
+ break;
+#endif
}
+ if (!useUnsyncedPwm && !isDigital) {
+ pwmCompleteWritePtr = pwmCompleteOneshotMotorUpdate;
+ }
+
for (int motorIndex = 0; motorIndex < MAX_SUPPORTED_MOTORS && motorIndex < motorCount; motorIndex++) {
const ioTag_t tag = motorConfig->ioTags[motorIndex];
@@ -214,30 +234,43 @@ void motorInit(const motorConfig_t *motorConfig, uint16_t idlePulse, uint8_t mot
break;
}
+ const timerHardware_t *timerHardware = timerGetByTag(tag, TIMER_OUTPUT_ENABLED);
+
+ if (timerHardware == NULL) {
+ /* flag failure and disable ability to arm */
+ break;
+ }
+
+#ifdef USE_DSHOT
+ if (isDigital) {
+ pwmDigitalMotorHardwareConfig(timerHardware, motorIndex, motorConfig->motorPwmProtocol);
+ motors[motorIndex].pwmWritePtr = pwmWriteDigital;
+ motors[motorIndex].enabled = true;
+ continue;
+ }
+#endif
motors[motorIndex].io = IOGetByTag(tag);
IOInit(motors[motorIndex].io, OWNER_MOTOR, RESOURCE_OUTPUT, RESOURCE_INDEX(motorIndex));
IOConfigGPIO(motors[motorIndex].io, IOCFG_AF_PP);
- const timerHardware_t *timer = timerGetByTag(tag, TIMER_OUTPUT_ENABLED);
-
- if (timer == NULL) {
- /* flag failure and disable ability to arm */
- break;
- }
-
motors[motorIndex].pwmWritePtr = pwmWritePtr;
if (useUnsyncedPwm) {
const uint32_t hz = timerMhzCounter * 1000000;
- pwmOutConfig(&motors[motorIndex], timer, timerMhzCounter, hz / motorConfig->motorPwmProtocol, idlePulse);
+ pwmOutConfig(&motors[motorIndex], timerHardware, timerMhzCounter, hz / motorConfig->motorPwmProtocol, idlePulse);
} else {
- pwmOutConfig(&motors[motorIndex], timer, timerMhzCounter, 0xFFFF, 0);
+ pwmOutConfig(&motors[motorIndex], timerHardware, timerMhzCounter, 0xFFFF, 0);
}
motors[motorIndex].enabled = true;
}
}
-pwmOutputPort_t *pwmGetMotors()
+bool pwmIsSynced(void)
+{
+ return pwmCompleteWritePtr != NULL;
+}
+
+pwmOutputPort_t *pwmGetMotors(void)
{
return motors;
}
diff --git a/src/main/drivers/pwm_output.h b/src/main/drivers/pwm_output.h
index fc3e9518df..7bc478af79 100644
--- a/src/main/drivers/pwm_output.h
+++ b/src/main/drivers/pwm_output.h
@@ -26,10 +26,12 @@ typedef enum {
PWM_TYPE_ONESHOT125,
PWM_TYPE_ONESHOT42,
PWM_TYPE_MULTISHOT,
- PWM_TYPE_BRUSHED
+ PWM_TYPE_BRUSHED,
+ PWM_TYPE_DSHOT600,
+ PWM_TYPE_DSHOT150
} motorPwmProtocolTypes_e;
-#define PWM_TIMER_MHZ 1
+#define PWM_TIMER_MHZ 1
#if defined(STM32F40_41xxx) // must be multiples of timer clock
#define ONESHOT125_TIMER_MHZ 12
@@ -43,8 +45,28 @@ typedef enum {
#define PWM_BRUSHED_TIMER_MHZ 24
#endif
+#define MOTOR_DMA_BUFFER_SIZE 18 /* resolution + frame reset (2us) */
+
+typedef struct {
+ TIM_TypeDef *timer;
+ uint16_t timerDmaSources;
+} motorDmaTimer_t;
+
+typedef struct {
+ ioTag_t ioTag;
+ const timerHardware_t *timerHardware;
+ uint16_t value;
+ uint16_t timerDmaSource;
+#if defined(STM32F3) || defined(STM32F4)
+ uint32_t dmaBuffer[MOTOR_DMA_BUFFER_SIZE];
+#else
+ uint8_t dmaBuffer[MOTOR_DMA_BUFFER_SIZE];
+#endif
+} motorDmaOutput_t;
+
struct timerHardware_s;
typedef void(*pwmWriteFuncPtr)(uint8_t index, uint16_t value); // function pointer used to write motors
+typedef void(*pwmCompleteWriteFuncPtr)(uint8_t motorCount); // function pointer used after motors are written
typedef struct {
volatile timCCR_t *ccr;
@@ -60,13 +82,20 @@ void servoInit(const servoConfig_t *servoConfig);
void pwmServoConfig(const struct timerHardware_s *timerHardware, uint8_t servoIndex, uint16_t servoPwmRate, uint16_t servoCenterPulse);
+#ifdef USE_DSHOT
+void pwmWriteDigital(uint8_t index, uint16_t value);
+void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, motorPwmProtocolTypes_e pwmProtocolType);
+void pwmCompleteDigitalMotorUpdate(uint8_t motorCount);
+#endif
+
void pwmWriteMotor(uint8_t index, uint16_t value);
void pwmShutdownPulsesForAllMotors(uint8_t motorCount);
-void pwmCompleteOneshotMotorUpdate(uint8_t motorCount);
+void pwmCompleteMotorUpdate(uint8_t motorCount);
void pwmWriteServo(uint8_t index, uint16_t value);
-pwmOutputPort_t *pwmGetMotors();
+pwmOutputPort_t *pwmGetMotors(void);
+bool pwmIsSynced(void);
void pwmDisableMotors(void);
void pwmEnableMotors(void);
diff --git a/src/main/drivers/pwm_output_stm32f3xx.c b/src/main/drivers/pwm_output_stm32f3xx.c
new file mode 100644
index 0000000000..9fae6b555d
--- /dev/null
+++ b/src/main/drivers/pwm_output_stm32f3xx.c
@@ -0,0 +1,218 @@
+/*
+ * This file is part of Betaflight.
+ *
+ * Betaflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Betaflight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Betaflight. If not, see .
+ */
+#include
+#include
+#include
+
+#include "platform.h"
+
+#include "io.h"
+#include "timer.h"
+#include "pwm_output.h"
+#include "nvic.h"
+#include "dma.h"
+#include "system.h"
+#include "rcc.h"
+
+#ifdef USE_DSHOT
+
+#define MAX_DMA_TIMERS 8
+
+#define MOTOR_DSHOT600_MHZ 24
+#define MOTOR_DSHOT150_MHZ 6
+
+#define MOTOR_BIT_0 14
+#define MOTOR_BIT_1 29
+#define MOTOR_BITLENGTH 39
+
+static uint8_t dmaMotorTimerCount = 0;
+static motorDmaTimer_t dmaMotorTimers[MAX_DMA_TIMERS];
+static motorDmaOutput_t dmaMotors[MAX_SUPPORTED_MOTORS];
+
+uint8_t getTimerIndex(TIM_TypeDef *timer)
+{
+ for (int i = 0; i < dmaMotorTimerCount; i++) {
+ if (dmaMotorTimers[i].timer == timer) {
+ return i;
+ }
+ }
+ dmaMotorTimers[dmaMotorTimerCount++].timer = timer;
+ return dmaMotorTimerCount-1;
+}
+
+void pwmWriteDigital(uint8_t index, uint16_t value)
+{
+ motorDmaOutput_t * const motor = &dmaMotors[index];
+
+ value = (value <= 1000) ? 0 : ((value - 1000) * 2);
+ motor->value = value;
+
+ motor->dmaBuffer[0] = (value & 0x400) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[1] = (value & 0x200) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[2] = (value & 0x100) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[3] = (value & 0x80) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[4] = (value & 0x40) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[5] = (value & 0x20) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[6] = (value & 0x10) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[7] = (value & 0x8) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[8] = (value & 0x4) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[9] = (value & 0x2) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[10] = (value & 0x1) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[11] = MOTOR_BIT_0; /* telemetry is always false for the moment */
+
+ /* check sum */
+ motor->dmaBuffer[12] = (value & 0x400) ^ (value & 0x40) ^ (value & 0x4) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[13] = (value & 0x200) ^ (value & 0x20) ^ (value & 0x2) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[14] = (value & 0x100) ^ (value & 0x10) ^ (value & 0x1) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[15] = (value & 0x80) ^ (value & 0x8) ^ (0x0) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+
+ DMA_SetCurrDataCounter(motor->timerHardware->dmaChannel, MOTOR_DMA_BUFFER_SIZE);
+ DMA_Cmd(motor->timerHardware->dmaChannel, ENABLE);
+}
+
+void pwmCompleteDigitalMotorUpdate(uint8_t motorCount)
+{
+ UNUSED(motorCount);
+
+ for (uint8_t i = 0; i < dmaMotorTimerCount; i++) {
+ TIM_SetCounter(dmaMotorTimers[i].timer, 0);
+ TIM_DMACmd(dmaMotorTimers[i].timer, dmaMotorTimers[i].timerDmaSources, ENABLE);
+ }
+}
+
+static void motor_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor)
+{
+ if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) {
+ motorDmaOutput_t * const motor = &dmaMotors[descriptor->userParam];
+ DMA_Cmd(descriptor->channel, DISABLE);
+ TIM_DMACmd(motor->timerHardware->tim, motor->timerDmaSource, DISABLE);
+ DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
+ }
+}
+
+void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, motorPwmProtocolTypes_e pwmProtocolType)
+{
+ TIM_OCInitTypeDef TIM_OCInitStructure;
+ DMA_InitTypeDef DMA_InitStructure;
+
+ motorDmaOutput_t * const motor = &dmaMotors[motorIndex];
+ motor->timerHardware = timerHardware;
+
+ TIM_TypeDef *timer = timerHardware->tim;
+ const IO_t motorIO = IOGetByTag(timerHardware->tag);
+
+ const uint8_t timerIndex = getTimerIndex(timer);
+ const bool configureTimer = (timerIndex == dmaMotorTimerCount-1);
+
+ IOInit(motorIO, OWNER_MOTOR, RESOURCE_OUTPUT, 0);
+ IOConfigGPIOAF(motorIO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP), timerHardware->alternateFunction);
+
+ if (configureTimer) {
+ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
+
+ RCC_ClockCmd(timerRCC(timer), ENABLE);
+ TIM_Cmd(timer, DISABLE);
+
+ uint32_t hz = (pwmProtocolType == PWM_TYPE_DSHOT600 ? MOTOR_DSHOT600_MHZ : MOTOR_DSHOT150_MHZ) * 1000000;
+ TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)((SystemCoreClock / timerClockDivisor(timer) / hz) - 1);
+ TIM_TimeBaseStructure.TIM_Period = MOTOR_BITLENGTH;
+ TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
+ TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+ TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
+ }
+
+ TIM_OCStructInit(&TIM_OCInitStructure);
+ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
+ if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
+ TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
+ TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
+ TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
+ TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
+ TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_Low;
+ TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
+ } else {
+ TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
+ TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
+ TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
+ TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
+ TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_High;
+ TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
+ }
+ TIM_OCInitStructure.TIM_Pulse = 0;
+
+ uint32_t timerChannelAddress = 0;
+ switch (timerHardware->channel) {
+ case TIM_Channel_1:
+ TIM_OC1Init(timer, &TIM_OCInitStructure);
+ motor->timerDmaSource = TIM_DMA_CC1;
+ timerChannelAddress = (uint32_t)(&timer->CCR1);
+ TIM_OC1PreloadConfig(timer, TIM_OCPreload_Enable);
+ break;
+ case TIM_Channel_2:
+ TIM_OC2Init(timer, &TIM_OCInitStructure);
+ motor->timerDmaSource = TIM_DMA_CC2;
+ timerChannelAddress = (uint32_t)(&timer->CCR2);
+ TIM_OC2PreloadConfig(timer, TIM_OCPreload_Enable);
+ break;
+ case TIM_Channel_3:
+ TIM_OC3Init(timer, &TIM_OCInitStructure);
+ motor->timerDmaSource = TIM_DMA_CC3;
+ timerChannelAddress = (uint32_t)(&timer->CCR3);
+ TIM_OC3PreloadConfig(timer, TIM_OCPreload_Enable);
+ break;
+ case TIM_Channel_4:
+ TIM_OC4Init(timer, &TIM_OCInitStructure);
+ motor->timerDmaSource = TIM_DMA_CC4;
+ timerChannelAddress = (uint32_t)(&timer->CCR4);
+ TIM_OC4PreloadConfig(timer, TIM_OCPreload_Enable);
+ break;
+ }
+ dmaMotorTimers[timerIndex].timerDmaSources |= motor->timerDmaSource;
+
+ TIM_CCxCmd(timer, motor->timerHardware->channel, TIM_CCx_Enable);
+
+ if (configureTimer) {
+ TIM_CtrlPWMOutputs(timer, ENABLE);
+ TIM_ARRPreloadConfig(timer, ENABLE);
+ TIM_Cmd(timer, ENABLE);
+ }
+
+ DMA_Channel_TypeDef *channel = timerHardware->dmaChannel;
+
+ dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
+
+ DMA_Cmd(channel, DISABLE);
+ DMA_DeInit(channel);
+ DMA_StructInit(&DMA_InitStructure);
+ DMA_InitStructure.DMA_PeripheralBaseAddr = timerChannelAddress;
+ DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)motor->dmaBuffer;
+ DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
+ DMA_InitStructure.DMA_BufferSize = MOTOR_DMA_BUFFER_SIZE;
+ DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
+ DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
+ DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+ DMA_InitStructure.DMA_Priority = DMA_Priority_High;
+ DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+
+ DMA_Init(channel, &DMA_InitStructure);
+
+ DMA_ITConfig(channel, DMA_IT_TC, ENABLE);
+}
+
+#endif
\ No newline at end of file
diff --git a/src/main/drivers/pwm_output_stm32f4xx.c b/src/main/drivers/pwm_output_stm32f4xx.c
new file mode 100644
index 0000000000..4f0baa5464
--- /dev/null
+++ b/src/main/drivers/pwm_output_stm32f4xx.c
@@ -0,0 +1,218 @@
+/*
+ * This file is part of Betaflight.
+ *
+ * Betaflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Betaflight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Betaflight. If not, see .
+ */
+#include
+#include
+#include
+
+#include "platform.h"
+
+#include "io.h"
+#include "timer.h"
+#include "pwm_output.h"
+#include "nvic.h"
+#include "dma.h"
+#include "system.h"
+#include "rcc.h"
+
+#ifdef USE_DSHOT
+
+#define MAX_DMA_TIMERS 8
+
+#define MOTOR_DSHOT600_MHZ 12
+#define MOTOR_DSHOT150_MHZ 3
+
+#define MOTOR_BIT_0 7
+#define MOTOR_BIT_1 14
+#define MOTOR_BITLENGTH 19
+
+static uint8_t dmaMotorTimerCount = 0;
+static motorDmaTimer_t dmaMotorTimers[MAX_DMA_TIMERS];
+static motorDmaOutput_t dmaMotors[MAX_SUPPORTED_MOTORS];
+
+uint8_t getTimerIndex(TIM_TypeDef *timer)
+{
+ for (int i = 0; i < dmaMotorTimerCount; i++) {
+ if (dmaMotorTimers[i].timer == timer) {
+ return i;
+ }
+ }
+ dmaMotorTimers[dmaMotorTimerCount++].timer = timer;
+ return dmaMotorTimerCount-1;
+}
+
+void pwmWriteDigital(uint8_t index, uint16_t value)
+{
+ motorDmaOutput_t * const motor = &dmaMotors[index];
+
+ value = (value <= 1000) ? 0 : ((value - 1000) * 2);
+ motor->value = value;
+
+ motor->dmaBuffer[0] = (value & 0x400) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[1] = (value & 0x200) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[2] = (value & 0x100) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[3] = (value & 0x80) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[4] = (value & 0x40) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[5] = (value & 0x20) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[6] = (value & 0x10) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[7] = (value & 0x8) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[8] = (value & 0x4) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[9] = (value & 0x2) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[10] = (value & 0x1) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[11] = MOTOR_BIT_0; /* telemetry is always false for the moment */
+
+ /* check sum */
+ motor->dmaBuffer[12] = (value & 0x400) ^ (value & 0x40) ^ (value & 0x4) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[13] = (value & 0x200) ^ (value & 0x20) ^ (value & 0x2) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[14] = (value & 0x100) ^ (value & 0x10) ^ (value & 0x1) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+ motor->dmaBuffer[15] = (value & 0x80) ^ (value & 0x8) ^ (0x0) ? MOTOR_BIT_1 : MOTOR_BIT_0;
+
+ DMA_SetCurrDataCounter(motor->timerHardware->dmaStream, MOTOR_DMA_BUFFER_SIZE);
+ DMA_Cmd(motor->timerHardware->dmaStream, ENABLE);
+}
+
+void pwmCompleteDigitalMotorUpdate(uint8_t motorCount)
+{
+ UNUSED(motorCount);
+
+ for (uint8_t i = 0; i < dmaMotorTimerCount; i++) {
+ TIM_SetCounter(dmaMotorTimers[i].timer, 0);
+ TIM_DMACmd(dmaMotorTimers[i].timer, dmaMotorTimers[i].timerDmaSources, ENABLE);
+ }
+}
+
+static void motor_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor)
+{
+ if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) {
+ motorDmaOutput_t * const motor = &dmaMotors[descriptor->userParam];
+ DMA_Cmd(descriptor->stream, DISABLE);
+ TIM_DMACmd(motor->timerHardware->tim, motor->timerDmaSource, DISABLE);
+ DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
+ }
+}
+
+void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, motorPwmProtocolTypes_e pwmProtocolType)
+{
+ TIM_OCInitTypeDef TIM_OCInitStructure;
+ DMA_InitTypeDef DMA_InitStructure;
+
+ motorDmaOutput_t * const motor = &dmaMotors[motorIndex];
+ motor->timerHardware = timerHardware;
+
+ TIM_TypeDef *timer = timerHardware->tim;
+ const IO_t motorIO = IOGetByTag(timerHardware->tag);
+
+ const uint8_t timerIndex = getTimerIndex(timer);
+ const bool configureTimer = (timerIndex == dmaMotorTimerCount-1);
+
+ IOInit(motorIO, OWNER_MOTOR, RESOURCE_OUTPUT, 0);
+ IOConfigGPIOAF(motorIO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP), timerHardware->alternateFunction);
+
+ if (configureTimer) {
+ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
+
+ RCC_ClockCmd(timerRCC(timer), ENABLE);
+ TIM_Cmd(timer, DISABLE);
+
+ uint32_t hz = (pwmProtocolType == PWM_TYPE_DSHOT600 ? MOTOR_DSHOT600_MHZ : MOTOR_DSHOT150_MHZ) * 1000000;
+ TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / timerClockDivisor(timer) / hz) - 1;
+ TIM_TimeBaseStructure.TIM_Period = MOTOR_BITLENGTH;
+ TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
+ TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+ TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
+ }
+
+ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
+ TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
+ TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
+ TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_High;
+ TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
+ TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
+ TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
+ TIM_OCInitStructure.TIM_Pulse = 0;
+
+ uint32_t timerChannelAddress = 0;
+ uint32_t dmaItFlag = 0;
+ switch (timerHardware->channel) {
+ case TIM_Channel_1:
+ TIM_OC1Init(timer, &TIM_OCInitStructure);
+ motor->timerDmaSource = TIM_DMA_CC1;
+ timerChannelAddress = (uint32_t)(&timer->CCR1);
+ TIM_OC1PreloadConfig(timer, TIM_OCPreload_Enable);
+ dmaItFlag = DMA_IT_TCIF1;
+ break;
+ case TIM_Channel_2:
+ TIM_OC2Init(timer, &TIM_OCInitStructure);
+ motor->timerDmaSource = TIM_DMA_CC2;
+ timerChannelAddress = (uint32_t)(&timer->CCR2);
+ TIM_OC2PreloadConfig(timer, TIM_OCPreload_Enable);
+ dmaItFlag = DMA_IT_TCIF2;
+ break;
+ case TIM_Channel_3:
+ TIM_OC3Init(timer, &TIM_OCInitStructure);
+ motor->timerDmaSource = TIM_DMA_CC3;
+ timerChannelAddress = (uint32_t)(&timer->CCR3);
+ TIM_OC3PreloadConfig(timer, TIM_OCPreload_Enable);
+ dmaItFlag = DMA_IT_TCIF3;
+ break;
+ case TIM_Channel_4:
+ TIM_OC4Init(timer, &TIM_OCInitStructure);
+ motor->timerDmaSource = TIM_DMA_CC4;
+ timerChannelAddress = (uint32_t)(&timer->CCR4);
+ TIM_OC4PreloadConfig(timer, TIM_OCPreload_Enable);
+ dmaItFlag = DMA_IT_TCIF4;
+ break;
+ }
+ dmaMotorTimers[timerIndex].timerDmaSources |= motor->timerDmaSource;
+
+ TIM_CCxCmd(timer, motor->timerHardware->channel, TIM_CCx_Enable);
+
+ if (configureTimer) {
+ TIM_CtrlPWMOutputs(timer, ENABLE);
+ TIM_ARRPreloadConfig(timer, ENABLE);
+ TIM_Cmd(timer, ENABLE);
+ }
+
+ DMA_Stream_TypeDef *stream = timerHardware->dmaStream;
+
+ DMA_Cmd(stream, DISABLE);
+ DMA_DeInit(stream);
+ DMA_StructInit(&DMA_InitStructure);
+ DMA_InitStructure.DMA_Channel = timerHardware->dmaChannel;
+ DMA_InitStructure.DMA_PeripheralBaseAddr = timerChannelAddress;
+ DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)motor->dmaBuffer;
+ DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
+ DMA_InitStructure.DMA_BufferSize = MOTOR_DMA_BUFFER_SIZE;
+ DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
+ DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
+ DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+ DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
+ DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
+ DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
+ DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
+ DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
+
+ DMA_Init(stream, &DMA_InitStructure);
+
+ DMA_ITConfig(stream, DMA_IT_TC, ENABLE);
+ DMA_ClearITPendingBit(stream, dmaItFlag);
+
+ dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
+}
+
+#endif
\ No newline at end of file
diff --git a/src/main/drivers/timer.c b/src/main/drivers/timer.c
index 701ea14999..c0425eb137 100755
--- a/src/main/drivers/timer.c
+++ b/src/main/drivers/timer.c
@@ -227,23 +227,7 @@ void configTimeBase(TIM_TypeDef *tim, uint16_t period, uint8_t mhz)
// "The counter clock frequency (CK_CNT) is equal to f CK_PSC / (PSC[15:0] + 1)." - STM32F10x Reference Manual 14.4.11
// Thus for 1Mhz: 72000000 / 1000000 = 72, 72 - 1 = 71 = TIM_Prescaler
-#if defined (STM32F40_41xxx)
- if (tim == TIM1 || tim == TIM8 || tim == TIM9 || tim == TIM10 || tim == TIM11) {
- TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / ((uint32_t)mhz * 1000000)) - 1;
- }
- else {
- TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 2 / ((uint32_t)mhz * 1000000)) - 1;
- }
-#elif defined (STM32F411xE)
- if (tim == TIM1 || tim == TIM9 || tim == TIM10 || tim == TIM11) {
- TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / ((uint32_t)mhz * 1000000)) - 1;
- }
- else {
- TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 2 / ((uint32_t)mhz * 1000000)) - 1;
- }
-#else
- TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / ((uint32_t)mhz * 1000000)) - 1;
-#endif
+ TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / timerClockDivisor(tim) / ((uint32_t)mhz * 1000000)) - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
diff --git a/src/main/drivers/timer.h b/src/main/drivers/timer.h
index 50ff96f323..244ca3bec0 100644
--- a/src/main/drivers/timer.h
+++ b/src/main/drivers/timer.h
@@ -80,6 +80,15 @@ typedef struct timerHardware_s {
#if defined(STM32F3) || defined(STM32F4)
uint8_t alternateFunction;
#endif
+#if defined(USE_DSHOT)
+#if defined(STM32F4)
+ DMA_Stream_TypeDef *dmaStream;
+ uint32_t dmaChannel;
+#elif defined(STM32F3)
+ DMA_Channel_TypeDef *dmaChannel;
+#endif
+ uint8_t dmaIrqHandler;
+#endif
} timerHardware_t;
typedef enum {
@@ -149,6 +158,8 @@ void timerInit(void);
void timerStart(void);
void timerForceOverflow(TIM_TypeDef *tim);
+uint8_t timerClockDivisor(TIM_TypeDef *tim);
+
void configTimeBase(TIM_TypeDef *tim, uint16_t period, uint8_t mhz); // TODO - just for migration
rccPeriphTag_t timerRCC(TIM_TypeDef *tim);
diff --git a/src/main/drivers/timer_stm32f10x.c b/src/main/drivers/timer_stm32f10x.c
index d918b07112..2d366e5010 100644
--- a/src/main/drivers/timer_stm32f10x.c
+++ b/src/main/drivers/timer_stm32f10x.c
@@ -37,6 +37,12 @@ const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
#endif
};
+uint8_t timerClockDivisor(TIM_TypeDef *tim)
+{
+ UNUSED(tim);
+ return 1;
+}
+
/**
* @brief Selects the TIM Output Compare Mode.
* @note This function does NOT disable the selected channel before changing the Output
diff --git a/src/main/drivers/timer_stm32f30x.c b/src/main/drivers/timer_stm32f30x.c
index 3f7107b4cd..6265d7fd77 100644
--- a/src/main/drivers/timer_stm32f30x.c
+++ b/src/main/drivers/timer_stm32f30x.c
@@ -29,6 +29,11 @@ const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
{ .TIMx = TIM17, .rcc = RCC_APB2(TIM17) },
};
+uint8_t timerClockDivisor(TIM_TypeDef *tim)
+{
+ UNUSED(tim);
+ return 1;
+}
/**
* @brief Selects the TIM Output Compare Mode.
diff --git a/src/main/drivers/timer_stm32f4xx.c b/src/main/drivers/timer_stm32f4xx.c
index 810b3a4286..be299b1168 100644
--- a/src/main/drivers/timer_stm32f4xx.c
+++ b/src/main/drivers/timer_stm32f4xx.c
@@ -58,6 +58,54 @@ const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
{ .TIMx = TIM14, .rcc = RCC_APB1(TIM14) },
};
+/*
+ need a mapping from dma and timers to pins, and the values should all be set here to the dmaMotors array.
+ this mapping could be used for both these motors and for led strip.
+
+ only certain pins have OC output (already used in normal PWM et al) but then
+ there are only certain DMA streams/channels available for certain timers and channels.
+ *** (this may highlight some hardware limitations on some targets) ***
+
+ DMA1
+
+ Channel Stream0 Stream1 Stream2 Stream3 Stream4 Stream5 Stream6 Stream7
+ 0
+ 1
+ 2 TIM4_CH1 TIM4_CH2 TIM4_CH3
+ 3 TIM2_CH3 TIM2_CH1 TIM2_CH1 TIM2_CH4
+ TIM2_CH4
+ 4
+ 5 TIM3_CH4 TIM3_CH1 TIM3_CH2 TIM3_CH3
+ 6 TIM5_CH3 TIM5_CH4 TIM5_CH1 TIM5_CH4 TIM5_CH2
+ 7
+
+ DMA2
+
+ Channel Stream0 Stream1 Stream2 Stream3 Stream4 Stream5 Stream6 Stream7
+ 0 TIM8_CH1 TIM1_CH1
+ TIM8_CH2 TIM1_CH2
+ TIM8_CH3 TIM1_CH3
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6 TIM1_CH1 TIM1_CH2 TIM1_CH1 TIM1_CH4 TIM1_CH3
+ 7 TIM8_CH1 TIM8_CH2 TIM8_CH3 TIM8_CH4
+*/
+
+uint8_t timerClockDivisor(TIM_TypeDef *tim)
+{
+#if defined (STM32F40_41xxx)
+ if (tim == TIM8) return 1;
+#endif
+ if (tim == TIM1 || tim == TIM9 || tim == TIM10 || tim == TIM11) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
void TIM_SelectOCxM_NoDisable(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode)
{
uint32_t tmp = 0;
diff --git a/src/main/flight/mixer.c b/src/main/flight/mixer.c
index 48b7f490ef..a8b462e0d1 100755
--- a/src/main/flight/mixer.c
+++ b/src/main/flight/mixer.c
@@ -331,7 +331,6 @@ const mixerRules_t servoMixers[] = {
static servoMixer_t *customServoMixers;
#endif
-
static motorMixer_t *customMixers;
void mixerUseConfigs(
@@ -404,14 +403,12 @@ void mixerInit(mixerMode_e mixerMode, motorMixer_t *initialCustomMixers)
void loadCustomServoMixer(void)
{
- uint8_t i;
-
// reset settings
servoRuleCount = 0;
memset(currentServoMixer, 0, sizeof(currentServoMixer));
// load custom mixer into currentServoMixer
- for (i = 0; i < MAX_SERVO_RULES; i++) {
+ for (uint8_t i = 0; i < MAX_SERVO_RULES; i++) {
// check if done
if (customServoMixers[i].rate == 0)
break;
@@ -421,13 +418,13 @@ void loadCustomServoMixer(void)
}
}
-void mixerUsePWMOutputConfiguration(bool use_unsyncedPwm)
+void mixerConfigureOutput(void)
{
int i;
motorCount = 0;
- syncMotorOutputWithPidLoop = !use_unsyncedPwm;
+ syncMotorOutputWithPidLoop = pwmIsSynced();
if (currentMixerMode == MIXER_CUSTOM || currentMixerMode == MIXER_CUSTOM_TRI || currentMixerMode == MIXER_CUSTOM_AIRPLANE) {
// load custom mixer into currentMixer
@@ -518,18 +515,14 @@ void mixerLoadMix(int index, motorMixer_t *customMixers)
customMixers[i] = mixers[index].motor[i];
}
}
-
#else
-
-void mixerUsePWMOutputConfiguration(bool use_unsyncedPwm)
+void mixerConfigureOutput(void)
{
+ syncMotorOutputWithPidLoop = pwmIsSynced();
- syncMotorOutputWithPidLoop = !use_unsyncedPwm;
-
- motorCount = 4;
+ motorCount = QUAD_MOTOR_COUNT;
- uint8_t i;
- for (i = 0; i < motorCount; i++) {
+ for (uint8_t i = 0; i < motorCount; i++) {
currentMixer[i] = mixerQuadX[i];
}
@@ -631,23 +624,22 @@ void writeServos(void)
void writeMotors(void)
{
- uint8_t i;
-
- for (i = 0; i < motorCount; i++)
+ for (uint8_t i = 0; i < motorCount; i++) {
pwmWriteMotor(i, motor[i]);
+ }
if (syncMotorOutputWithPidLoop) {
- pwmCompleteOneshotMotorUpdate(motorCount);
+ pwmCompleteMotorUpdate(motorCount);
}
}
void writeAllMotors(int16_t mc)
{
- uint8_t i;
-
// Sends commands to all motors
- for (i = 0; i < motorCount; i++)
+ for (uint8_t i = 0; i < motorCount; i++) {
motor[i] = mc;
+ }
+
writeMotors();
}
@@ -658,7 +650,7 @@ void stopMotors(void)
delay(50); // give the timers and ESCs a chance to react.
}
-void stopPwmAllMotors()
+void stopPwmAllMotors(void)
{
pwmShutdownPulsesForAllMotors(motorCount);
delayMicroseconds(1500);
diff --git a/src/main/flight/mixer.h b/src/main/flight/mixer.h
index a6a7cee6d2..4622cfd3f9 100644
--- a/src/main/flight/mixer.h
+++ b/src/main/flight/mixer.h
@@ -20,6 +20,8 @@
#define MAX_SUPPORTED_MOTORS 12
#define MAX_SUPPORTED_SERVOS 8
+#define QUAD_MOTOR_COUNT 4
+
// Note: this is called MultiType/MULTITYPE_* in baseflight.
typedef enum mixerMode
{
@@ -213,7 +215,7 @@ int servoDirection(int servoIndex, int fromChannel);
#endif
void mixerInit(mixerMode_e mixerMode, motorMixer_t *customMotorMixers);
-void mixerUsePWMOutputConfiguration(bool use_unsyncedPwm);
+void mixerConfigureOutput(void);
void mixerResetDisarmedMotors(void);
void mixTable(void *pidProfilePtr);
diff --git a/src/main/io/serial_cli.c b/src/main/io/serial_cli.c
index a1c205e5a8..aac2360c58 100755
--- a/src/main/io/serial_cli.c
+++ b/src/main/io/serial_cli.c
@@ -516,7 +516,10 @@ static const char * const lookupTableSuperExpoYaw[] = {
};
static const char * const lookupTablePwmProtocol[] = {
- "OFF", "ONESHOT125", "ONESHOT42", "MULTISHOT", "BRUSHED"
+ "OFF", "ONESHOT125", "ONESHOT42", "MULTISHOT", "BRUSHED",
+#ifdef USE_DSHOT
+ "DSHOT600", "DSHOT150"
+#endif
};
static const char * const lookupTableRcInterpolation[] = {
diff --git a/src/main/main.c b/src/main/main.c
index 813b23b423..3ff79d02ad 100644
--- a/src/main/main.c
+++ b/src/main/main.c
@@ -259,8 +259,9 @@ void init(void)
featureClear(FEATURE_3D);
idlePulse = 0; // brushed motors
}
+
#ifdef USE_QUAD_MIXER_ONLY
- motorInit(&masterConfig.motorConfig, idlePulse, 4);
+ motorInit(&masterConfig.motorConfig, idlePulse, QUAD_MOTOR_COUNT);
#else
motorInit(&masterConfig.motorConfig, idlePulse, mixers[masterConfig.mixerMode].motorCount);
#endif
@@ -281,10 +282,7 @@ void init(void)
pwmRxSetInputFilteringMode(masterConfig.inputFilteringMode);
#endif
- bool usingUnsyncedOutput = (masterConfig.motorConfig.useUnsyncedPwm
- || masterConfig.motorConfig.motorPwmProtocol == PWM_TYPE_BRUSHED
- || masterConfig.motorConfig.motorPwmProtocol == PWM_TYPE_STANDARD);
- mixerUsePWMOutputConfiguration(usingUnsyncedOutput);
+ mixerConfigureOutput();
systemState |= SYSTEM_STATE_MOTORS_READY;
diff --git a/src/main/target/BLUEJAYF4/target.c b/src/main/target/BLUEJAYF4/target.c
index a725c47a37..c82953b221 100644
--- a/src/main/target/BLUEJAYF4/target.c
+++ b/src/main/target/BLUEJAYF4/target.c
@@ -20,14 +20,15 @@
#include
#include "drivers/io.h"
#include "drivers/timer.h"
+#include "drivers/dma.h"
-const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
- { TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // PPM IN
- { TIM5, IO_TAG(PA0), TIM_Channel_1, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S1_OUT
- { TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S2_OUT
- { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2 }, // S3_OUT
- { TIM9, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM9_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM9 }, // S4_OUT
- { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S5_OUT
- { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S6_OUT
+const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
+ { TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // PPM IN
+ { TIM5, IO_TAG(PA0), TIM_Channel_1, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, DMA1_Stream2, DMA_Channel_6, DMA1_ST2_HANDLER }, // S1_OUT
+ { TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, DMA1_Stream4, DMA_Channel_6, DMA1_ST4_HANDLER }, // S2_OUT
+ { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream1, DMA_Channel_3, DMA1_ST1_HANDLER }, // S3_OUT
+ { TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream6, DMA_Channel_3, DMA1_ST6_HANDLER }, // S4_OUT
+ { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream2, DMA_Channel_5, DMA1_ST2_HANDLER }, // S5_OUT
+ { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream7, DMA_Channel_5, DMA1_ST7_HANDLER }, // S6_OUT
};
diff --git a/src/main/target/BLUEJAYF4/target.h b/src/main/target/BLUEJAYF4/target.h
index d860ee66af..a013e3fb2d 100644
--- a/src/main/target/BLUEJAYF4/target.h
+++ b/src/main/target/BLUEJAYF4/target.h
@@ -140,6 +140,7 @@
#define USE_ADC
#define VBAT_ADC_PIN PC3
+#define USE_DSHOT
#define LED_STRIP
// LED Strip can run off Pin 6 (PB1) of the ESC outputs.
#define WS2811_PIN PB1
diff --git a/src/main/target/BLUEJAYF4/target.mk b/src/main/target/BLUEJAYF4/target.mk
index 5714bce5b3..f4802c88b9 100644
--- a/src/main/target/BLUEJAYF4/target.mk
+++ b/src/main/target/BLUEJAYF4/target.mk
@@ -4,5 +4,5 @@ FEATURES += SDCARD VCP ONBOARDFLASH
TARGET_SRC = \
drivers/accgyro_spi_mpu6500.c \
drivers/accgyro_mpu6500.c \
- drivers/barometer_ms5611.c
+ drivers/barometer_ms5611.c
diff --git a/src/main/target/FURYF3/target.c b/src/main/target/FURYF3/target.c
index 7de36bf968..504e3b6c2d 100644
--- a/src/main/target/FURYF3/target.c
+++ b/src/main/target/FURYF3/target.c
@@ -21,17 +21,20 @@
#include "drivers/io.h"
#include "drivers/timer.h"
+#include "drivers/dma.h"
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
- { TIM2, IO_TAG(PB3), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1 }, // PPM IN
- { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // SS1 - PB0 - *TIM3_CH3, TIM1_CH2N, TIM8_CH2N
- { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // SS1 - PB1 - *TIM3_CH4, TIM1_CH3N, TIM8_CH3N
- { TIM4, IO_TAG(PB7), TIM_Channel_2, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2 }, // PWM4 - S1
- { TIM4, IO_TAG(PB6), TIM_Channel_1, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2 }, // PWM5 - S2
- { TIM17, IO_TAG(PB5), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, 1, IOCFG_AF_PP, GPIO_AF_10}, // PWM6 - S3
- { TIM16, IO_TAG(PB4), TIM_Channel_1, TIM1_UP_TIM16_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1 }, // PWM7 - S4
+ { TIM2, IO_TAG(PB3), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 }, // PPM IN
+ { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 }, // SS1 - PB0 - *TIM3_CH3, TIM1_CH2N, TIM8_CH2N
+ { TIM1, IO_TAG(PB1), TIM_Channel_3, TIM1_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_6, NULL, 0 }, // SS1 - PB1 - *TIM3_CH4, TIM1_CH3N, TIM8_CH3N
+
+ { TIM3, IO_TAG(PB7), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_10, DMA1_Channel3, DMA1_CH3_HANDLER }, // PWM4 - S1
+ { TIM8, IO_TAG(PB6), TIM_Channel_1, TIM8_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_5, DMA2_Channel3, DMA2_CH3_HANDLER }, // PWM5 - S2
+ { TIM8, IO_TAG(PB5), TIM_Channel_3, TIM8_CC_IRQn, (1 | TIMER_OUTPUT_N_CHANNEL), IOCFG_AF_PP, GPIO_AF_3, DMA2_Channel1, DMA2_CH1_HANDLER }, // PWM6 - S3
+ { TIM3, IO_TAG(PB4), TIM_Channel_1, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2, DMA1_Channel6, DMA1_CH6_HANDLER }, // PWM7 - S4
+
+ { TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_6, NULL, 0 }, // GPIO TIMER - LED_STRIP
- { TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_6 }, // GPIO TIMER - LED_STRIP
};
diff --git a/src/main/target/FURYF3/target.h b/src/main/target/FURYF3/target.h
index bd9a09eca8..f8c74899ef 100644
--- a/src/main/target/FURYF3/target.h
+++ b/src/main/target/FURYF3/target.h
@@ -167,6 +167,8 @@
#define USE_SERIAL_4WAY_BLHELI_INTERFACE
+#define USE_DSHOT
+
#define TARGET_IO_PORTA 0xffff
#define TARGET_IO_PORTB 0xffff
#define TARGET_IO_PORTC 0xffff
@@ -174,5 +176,5 @@
#define TARGET_IO_PORTF (BIT(4))
#define USABLE_TIMER_CHANNEL_COUNT 8
-#define USED_TIMERS (TIM_N(1) | TIM_N(2) | TIM_N(3) | TIM_N(4) | TIM_N(16) |TIM_N(17))
+#define USED_TIMERS (TIM_N(1) | TIM_N(2) | TIM_N(3) | TIM_N(4) | TIM_N(8) | TIM_N(16) | TIM_N(17))
diff --git a/src/main/target/FURYF3/target.mk b/src/main/target/FURYF3/target.mk
index 1cbb887de4..b7049e3469 100644
--- a/src/main/target/FURYF3/target.mk
+++ b/src/main/target/FURYF3/target.mk
@@ -8,5 +8,6 @@ TARGET_SRC = \
drivers/accgyro_spi_mpu6000.c \
drivers/accgyro_mpu6500.c \
drivers/accgyro_spi_mpu6500.c \
- drivers/accgyro_spi_icm20689.c
+ drivers/accgyro_spi_icm20689.c \
+ drivers/pwm_output_stm32f3xx.c
diff --git a/src/main/target/FURYF4/target.c b/src/main/target/FURYF4/target.c
index 90db896c53..af6feb53c6 100644
--- a/src/main/target/FURYF4/target.c
+++ b/src/main/target/FURYF4/target.c
@@ -19,16 +19,17 @@
#include
#include "drivers/io.h"
-
+#include "drivers/dma.h"
#include "drivers/timer.h"
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
- { TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // PPM_IN
- { TIM9, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM9_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM9 }, // S1_OUT
- { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S2_OUT
- { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S3_OUT
- { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2 }, // S4_OUT
+ { TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // PPM_IN
+
+ { TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream6, DMA_Channel_3, DMA1_ST6_HANDLER }, // S1_OUT
+ { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream7, DMA_Channel_5, DMA1_ST7_HANDLER }, // S2_OUT
+ { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream2, DMA_Channel_5, DMA1_ST2_HANDLER }, // S3_OUT
+ { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream1, DMA_Channel_3, DMA1_ST1_HANDLER }, // S4_OUT
// { TIM5, GPIOA, Pin_0, TIM_Channel_1, TIM5_IRQn, 1, GPIO_Mode_AF, GPIO_PinSource0, GPIO_AF_TIM5 }, // LED Strip
};
diff --git a/src/main/target/FURYF4/target.h b/src/main/target/FURYF4/target.h
index 8b767e8651..64091a079b 100644
--- a/src/main/target/FURYF4/target.h
+++ b/src/main/target/FURYF4/target.h
@@ -183,11 +183,13 @@
#define USE_SERIAL_4WAY_BLHELI_INTERFACE
+#define USE_DSHOT
+
#define TARGET_IO_PORTA 0xffff
#define TARGET_IO_PORTB 0xffff
#define TARGET_IO_PORTC 0xffff
#define TARGET_IO_PORTD (BIT(2))
#define USABLE_TIMER_CHANNEL_COUNT 5
-#define USED_TIMERS ( TIM_N(2) | TIM_N(3) | TIM_N(8) | TIM_N(9))
+#define USED_TIMERS ( TIM_N(2) | TIM_N(3) | TIM_N(8) )
diff --git a/src/main/target/FURYF4/target.mk b/src/main/target/FURYF4/target.mk
index b35c30a577..e1fb3c41bf 100644
--- a/src/main/target/FURYF4/target.mk
+++ b/src/main/target/FURYF4/target.mk
@@ -6,5 +6,6 @@ TARGET_SRC = \
drivers/accgyro_spi_mpu6500.c \
drivers/accgyro_mpu6500.c \
drivers/accgyro_spi_icm20689.c \
- drivers/barometer_ms5611.c
+ drivers/barometer_ms5611.c \
+ drivers/pwm_output_stm32f4xx.c
diff --git a/src/main/target/KISSFC/target.c b/src/main/target/KISSFC/target.c
index 743f531e3d..d36fa9903a 100644
--- a/src/main/target/KISSFC/target.c
+++ b/src/main/target/KISSFC/target.c
@@ -19,22 +19,23 @@
#include
#include "drivers/io.h"
+#include "drivers/dma.h"
#include "drivers/timer.h"
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
- { TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_6},
- { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_2},
- { TIM15, IO_TAG(PB14), TIM_Channel_1, TIM1_BRK_TIM15_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1},
- { TIM15, IO_TAG(PB15), TIM_Channel_2, TIM1_BRK_TIM15_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1},
- { TIM16, IO_TAG(PA6), TIM_Channel_1, TIM1_UP_TIM16_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1},
- { TIM17, IO_TAG(PA7), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1},
+ { TIM15, IO_TAG(PB15), TIM_Channel_1, TIM1_BRK_TIM15_IRQn, TIMER_OUTPUT_ENABLED, IOCFG_AF_PP, GPIO_AF_6, DMA1_Channel5, DMA1_CH5_HANDLER },
+ { TIM8, IO_TAG(PB0), TIM_Channel_2, TIM8_CC_IRQn, TIMER_OUTPUT_ENABLED, IOCFG_AF_PP, GPIO_AF_2, DMA2_Channel5, DMA2_CH5_HANDLER },
+ { TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel2, DMA1_CH2_HANDLER },
+ { TIM1, IO_TAG(PB14), TIM_Channel_2, TIM1_CC_IRQn, TIMER_OUTPUT_ENABLED, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel3, DMA1_CH3_HANDLER },
+ { TIM3, IO_TAG(PA6), TIM_Channel_1, TIM3_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel6, DMA1_CH6_HANDLER },
+ { TIM17, IO_TAG(PA7), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel7, DMA1_CH7_HANDLER },
- { TIM2, IO_TAG(PB3), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1}, // TODO - Cleanup. KISS FC uses the same pin for serial and PPM
- { TIM2, IO_TAG(PA15), TIM_Channel_1, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1},
- { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1},
- { TIM2, IO_TAG(PB11), TIM_Channel_4, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1},
- { TIM4, IO_TAG(PA13), TIM_Channel_2, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_10},
- { TIM8, IO_TAG(PA14), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_5},
+ { TIM2, IO_TAG(PB3), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0}, // TODO - Cleanup. KISS FC uses the same pin for serial and PPM
+ { TIM2, IO_TAG(PA15), TIM_Channel_1, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0},
+ { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0},
+ { TIM2, IO_TAG(PB11), TIM_Channel_4, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0},
+ { TIM4, IO_TAG(PA13), TIM_Channel_2, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_10, NULL, 0},
+ { TIM8, IO_TAG(PA14), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_5, NULL, 0},
};
diff --git a/src/main/target/KISSFC/target.h b/src/main/target/KISSFC/target.h
index 7eff58c7bf..f8a6062776 100644
--- a/src/main/target/KISSFC/target.h
+++ b/src/main/target/KISSFC/target.h
@@ -23,6 +23,8 @@
#define SBUS_PORT_OPTIONS (SERIAL_STOPBITS_2 | SERIAL_PARITY_EVEN | SERIAL_INVERTED | SERIAL_BIDIR)
+#define USE_DSHOT
+
#define LED0 PB1
#define BEEPER PB13
diff --git a/src/main/target/KISSFC/target.mk b/src/main/target/KISSFC/target.mk
index c59af03e59..4b307e198c 100644
--- a/src/main/target/KISSFC/target.mk
+++ b/src/main/target/KISSFC/target.mk
@@ -4,5 +4,5 @@ FEATURES = VCP
TARGET_SRC = \
drivers/accgyro_mpu.c \
drivers/display_ug2864hsweg01.c \
- drivers/accgyro_mpu6050.c
+ drivers/accgyro_mpu6050.c
diff --git a/src/main/target/OMNIBUS/target.c b/src/main/target/OMNIBUS/target.c
index ee01852829..c194fc9752 100644
--- a/src/main/target/OMNIBUS/target.c
+++ b/src/main/target/OMNIBUS/target.c
@@ -21,18 +21,22 @@
#include "drivers/io.h"
#include "drivers/timer.h"
+#include "drivers/dma.h"
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
// PPM Pad
- { TIM3, IO_TAG(PB4), TIM_Channel_1, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PPM - PB4
+ { TIM3, IO_TAG(PB4), TIM_Channel_1, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 }, // PPM - PB4
// PB5 / TIM3 CH2 is connected to USBPresent
- { TIM4, IO_TAG(PB8), TIM_Channel_3, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2 }, // PWM1 - PB8
- { TIM4, IO_TAG(PB9), TIM_Channel_4, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2 }, // PWM2 - PB9
- { TIM15, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM15_IRQn, 1, IOCFG_AF_PP, GPIO_AF_9 }, // PWM3 - PA3
- { TIM15, IO_TAG(PA2), TIM_Channel_1, TIM1_BRK_TIM15_IRQn, 1, IOCFG_AF_PP, GPIO_AF_9 }, // PWM4 - PA2
+ { TIM8, IO_TAG(PB8), TIM_Channel_2, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_10, DMA2_Channel5, DMA2_CH5_HANDLER }, // PWM1 - PB8
+ { TIM8, IO_TAG(PB9), TIM_Channel_3, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_10, DMA2_Channel1, DMA2_CH1_HANDLER }, // PWM2 - PB9
+ { TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel7, DMA1_CH7_HANDLER }, // PWM3 - PA3
+ { TIM15, IO_TAG(PA2), TIM_Channel_1, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_9, DMA1_Channel5, DMA1_CH5_HANDLER }, // PWM4 - PA2
// UART3 RX/TX
- { TIM2, IO_TAG(PB10), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1 }, // PWM5 - PB10 - TIM2_CH3 / UART3_TX (AF7)
- { TIM2, IO_TAG(PB11), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1 }, // PWM6 - PB11 - TIM2_CH4 / UART3_RX (AF7)
+ //{ TIM2, IO_TAG(PB10), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 }, // PWM5 - PB10 - TIM2_CH3 / UART3_TX (AF7)
+ //{ TIM2, IO_TAG(PB11), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 }, // PWM6 - PB11 - TIM2_CH4 / UART3_RX (AF7)
+ { TIM4, IO_TAG(PB7), TIM_Channel_2, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 }, // PWM7 - PB7
+ { TIM4, IO_TAG(PB6), TIM_Channel_1, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 }, // PWM8 - PB6
+ //{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_6, DMA1_Channel2, DMA1_CH2_HANDLER }, // GPIO_TIMER / LED_STRIP
};
diff --git a/src/main/target/OMNIBUS/target.h b/src/main/target/OMNIBUS/target.h
index 97a2c7c87f..4b392c32fd 100644
--- a/src/main/target/OMNIBUS/target.h
+++ b/src/main/target/OMNIBUS/target.h
@@ -140,6 +140,7 @@
//#define RSSI_ADC_PIN PB1
//#define ADC_INSTANCE ADC3
+#define USE_DSHOT
#define LED_STRIP
#define WS2811_PIN PA8
@@ -193,4 +194,4 @@
#define TARGET_IO_PORTF (BIT(0)|BIT(1)|BIT(4))
#define USABLE_TIMER_CHANNEL_COUNT 7 // PPM + 6 Outputs (2 shared with UART3)
-#define USED_TIMERS (TIM_N(1) | TIM_N(2) | TIM_N(3) | TIM_N(4) | TIM_N(15))
+#define USED_TIMERS (TIM_N(1) | TIM_N(2) | TIM_N(3) | TIM_N(4) | TIM_N(8) | TIM_N(15))
diff --git a/src/main/target/OMNIBUSF4/target.c b/src/main/target/OMNIBUSF4/target.c
index b289fb5ee7..5e63b90590 100644
--- a/src/main/target/OMNIBUSF4/target.c
+++ b/src/main/target/OMNIBUSF4/target.c
@@ -21,19 +21,20 @@
#include "drivers/io.h"
#include "drivers/timer.h"
+#include "drivers/dma.h"
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
- { TIM12, IO_TAG(PB14), TIM_Channel_1, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12 },// PPM (5th pin on FlexiIO port)
- { TIM12, IO_TAG(PB15), TIM_Channel_2, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12 },// S2_IN - GPIO_PartialRemap_TIM3
- { TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S3_IN
- { TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S4_IN
- { TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S5_IN
- { TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S6_IN
+ { TIM12, IO_TAG(PB14), TIM_Channel_1, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12, NULL, 0, 0 }, // PPM (5th pin on FlexiIO port)
+ { TIM12, IO_TAG(PB15), TIM_Channel_2, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12, NULL, 0, 0 }, // S2_IN - GPIO_PartialRemap_TIM3
+ { TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S3_IN
+ { TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S4_IN
+ { TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S5_IN
+ { TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S6_IN
- { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S1_OUT
- { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S2_OUT
- { TIM9, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM9_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM9 }, // S4_OUT
- { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2 }, // S4_OUT
- { TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S5_OUT - GPIO_PartialRemap_TIM3
- { TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM1 }, // S6_OUT
+ { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream7, DMA_Channel_5, DMA1_ST7_HANDLER }, // S1_OUT
+ { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream2, DMA_Channel_5, DMA1_ST2_HANDLER }, // S2_OUT
+ { TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream6, DMA_Channel_3, DMA1_ST6_HANDLER }, // S4_OUT
+ { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream1, DMA_Channel_3, DMA1_ST1_HANDLER }, // S4_OUT
+ { TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, NULL, 0, 0 }, // S5_OUT - GPIO_PartialRemap_TIM3
+ { TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM1, NULL, 0, 0 }, // S6_OUT
};
diff --git a/src/main/target/OMNIBUSF4/target.h b/src/main/target/OMNIBUSF4/target.h
index 9fd6c180c8..d1e205b8d8 100644
--- a/src/main/target/OMNIBUSF4/target.h
+++ b/src/main/target/OMNIBUSF4/target.h
@@ -116,6 +116,8 @@
#define VBAT_ADC_PIN PC2
//#define RSSI_ADC_PIN PA0
+#define USE_DSHOT
+
#define LED_STRIP
// LED Strip can run off Pin 5 (PA1) of the MOTOR outputs.
#define WS2811_PIN PA1
diff --git a/src/main/target/REVO/target.c b/src/main/target/REVO/target.c
index 31d22875b9..f8be6e2eab 100644
--- a/src/main/target/REVO/target.c
+++ b/src/main/target/REVO/target.c
@@ -19,20 +19,21 @@
#include
#include "drivers/io.h"
+#include "drivers/dma.h"
#include "drivers/timer.h"
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
- { TIM12, IO_TAG(PB14), TIM_Channel_1, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12 }, // PPM (5th pin on FlexiIO port)
- { TIM12, IO_TAG(PB15), TIM_Channel_2, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12 }, // S2_IN - GPIO_PartialRemap_TIM3
- { TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S3_IN
- { TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S4_IN
- { TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S5_IN
- { TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S6_IN
- { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S1_OUT
- { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S2_OUT
- { TIM9, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM9_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM9 }, // S3_OUT
- { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2 }, // S4_OUT
- { TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S5_OUT - GPIO_PartialRemap_TIM3
- { TIM5, IO_TAG(PA0), TIM_Channel_1, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S6_OUT
+ { TIM12, IO_TAG(PB14), TIM_Channel_1, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12, NULL, 0, 0 }, // PPM (5th pin on FlexiIO port)
+ { TIM12, IO_TAG(PB15), TIM_Channel_2, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12, NULL, 0, 0 }, // S2_IN
+ { TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S3_IN
+ { TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S4_IN
+ { TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S5_IN
+ { TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S6_IN
+ { TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream7, DMA_Channel_5, DMA1_ST7_HANDLER }, // S1_OUT
+ { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream2, DMA_Channel_5, DMA1_ST2_HANDLER }, // S2_OUT
+ { TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream6, DMA_Channel_3, DMA1_ST6_HANDLER }, // S3_OUT
+ { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream1, DMA_Channel_3, DMA1_ST1_HANDLER }, // S4_OUT
+ { TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, DMA1_Stream4, DMA_Channel_6, DMA1_ST4_HANDLER }, // S5_OUT
+ { TIM5, IO_TAG(PA0), TIM_Channel_1, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, DMA1_Stream2, DMA_Channel_6, DMA1_ST2_HANDLER }, // S6_OUT
};
diff --git a/src/main/target/REVO/target.h b/src/main/target/REVO/target.h
index 8a20b31bb0..97b66191df 100644
--- a/src/main/target/REVO/target.h
+++ b/src/main/target/REVO/target.h
@@ -26,6 +26,8 @@
#define USBD_SERIALNUMBER_STRING "0x8020000"
#endif
+#define USE_DSHOT
+
#define LED0 PB5
// Disable LED1, conflicts with AirbotF4/Flip32F4 beeper
//#define LED1 PB4
diff --git a/src/main/target/STM32F3DISCOVERY/target.c b/src/main/target/STM32F3DISCOVERY/target.c
index 1820565927..8cd9a3584f 100644
--- a/src/main/target/STM32F3DISCOVERY/target.c
+++ b/src/main/target/STM32F3DISCOVERY/target.c
@@ -21,21 +21,22 @@
#include "drivers/io.h"
#include "drivers/timer.h"
+#include "drivers/dma.h"
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
- { TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_6 }, // PWM1 - PA8
- { TIM16, IO_TAG(PB8), TIM_Channel_1, TIM1_UP_TIM16_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_1 }, // PWM2 - PB8
- { TIM17, IO_TAG(PB9), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_1 }, // PWM3 - PB9
- { TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4 }, // PWM4 - PC6
- { TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4 }, // PWM5 - PC7
- { TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4 }, // PWM6 - PC8
- { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_2 }, // PWM7 - PB1
- { TIM3, IO_TAG(PA4), TIM_Channel_2, TIM3_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_2 }, // PWM8 - PA2
- { TIM4, IO_TAG(PD12), TIM_Channel_1, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PWM9 - PD12
- { TIM4, IO_TAG(PD13), TIM_Channel_2, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PWM10 - PD13
- { TIM4, IO_TAG(PD14), TIM_Channel_3, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PWM11 - PD14
- { TIM4, IO_TAG(PD15), TIM_Channel_4, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PWM12 - PD15
- { TIM2, IO_TAG(PA1), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1 }, // PWM13 - PA1
- { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1 } // PWM14 - PA2
+ { TIM16, IO_TAG(PB8), TIM_Channel_1, TIM1_UP_TIM16_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_1, NULL, 0 },
+ { TIM17, IO_TAG(PB9), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_1, NULL, 0 },
+ { TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_6, DMA1_Channel2, DMA1_CH2_HANDLER },
+ { TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4, DMA2_Channel3, DMA2_CH3_HANDLER },
+ { TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4, DMA2_Channel5, DMA2_CH5_HANDLER },
+ { TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4, DMA2_Channel1, DMA2_CH1_HANDLER },
+ { TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_2, NULL, 0 },
+ { TIM3, IO_TAG(PA4), TIM_Channel_2, TIM3_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_2, NULL, 0 },
+ { TIM4, IO_TAG(PD12), TIM_Channel_1, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 },
+ { TIM4, IO_TAG(PD13), TIM_Channel_2, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 },
+ { TIM4, IO_TAG(PD14), TIM_Channel_3, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 },
+ { TIM4, IO_TAG(PD15), TIM_Channel_4, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 },
+ { TIM2, IO_TAG(PA1), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 },
+ { TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 }
};
diff --git a/src/main/target/STM32F3DISCOVERY/target.h b/src/main/target/STM32F3DISCOVERY/target.h
index 9cba1c51f8..687fa1924a 100644
--- a/src/main/target/STM32F3DISCOVERY/target.h
+++ b/src/main/target/STM32F3DISCOVERY/target.h
@@ -164,6 +164,8 @@
#define RSSI_ADC_PIN PC2
#define EXTERNAL1_ADC_PIN PC3
+#define USE_DSHOT
+
#define LED_STRIP
#define WS2811_PIN PB8 // TIM16_CH1
#define WS2811_TIMER TIM16