From 4e529642d159136bd6063d17548ee47df5347df2 Mon Sep 17 00:00:00 2001 From: blckmn Date: Thu, 13 Oct 2016 22:03:37 +1100 Subject: [PATCH] Initial implementation of DSHOT protocol (600 and 150) --- src/main/drivers/pwm_output.c | 67 ++++++--- src/main/drivers/pwm_output.h | 37 ++++- src/main/drivers/pwm_stm32f3xx.c | 200 ++++++++++++++++++++++++++ src/main/drivers/pwm_stm32f4xx.c | 216 ++++++++++++++++++++++++++++ src/main/drivers/timer.c | 18 +-- src/main/drivers/timer.h | 11 ++ src/main/drivers/timer_stm32f10x.c | 6 + src/main/drivers/timer_stm32f30x.c | 4 + src/main/drivers/timer_stm32f4xx.c | 48 +++++++ src/main/flight/mixer.c | 36 ++--- src/main/flight/mixer.h | 4 +- src/main/io/serial_cli.c | 5 +- src/main/main.c | 8 +- src/main/target/BLUEJAYF4/target.c | 17 +-- src/main/target/BLUEJAYF4/target.h | 1 + src/main/target/BLUEJAYF4/target.mk | 1 + src/main/target/KISSFC/target.c | 25 ++-- src/main/target/KISSFC/target.h | 2 + src/main/target/KISSFC/target.mk | 3 +- src/main/target/REVO/target.c | 25 ++-- src/main/target/REVO/target.h | 2 + src/main/target/REVO/target.mk | 1 + 22 files changed, 637 insertions(+), 100 deletions(-) create mode 100644 src/main/drivers/pwm_stm32f3xx.c create mode 100644 src/main/drivers/pwm_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..507ed519ef 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(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_stm32f3xx.c b/src/main/drivers/pwm_stm32f3xx.c new file mode 100644 index 0000000000..047b721d4e --- /dev/null +++ b/src/main/drivers/pwm_stm32f3xx.c @@ -0,0 +1,200 @@ +/* + * 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_mapping.h" +#include "pwm_output.h" +#include "nvic.h" +#include "dma.h" +#include "system.h" +#include "rcc.h" + +#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_PWM_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) * 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) ? MOTOR_BIT_1 : MOTOR_BIT_0; + motor->dmaBuffer[13] = (value & 0x200) ? MOTOR_BIT_1 : MOTOR_BIT_0; + motor->dmaBuffer[14] = (value & 0x100) ? MOTOR_BIT_1 : MOTOR_BIT_0; + motor->dmaBuffer[15] = (value & 0x80) ? 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)) { + DMA_Cmd(descriptor->channel, 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), timerGPIOAF(timer)); + + 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_OCStructInit(&TIM_OCInitStructure); + TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; + TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; + TIM_OCInitStructure.TIM_Pulse = 0; + TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; + + 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; + } + + if (configureTimer) { + TIM_CtrlPWMOutputs(timer, ENABLE); + TIM_ARRPreloadConfig(timer, ENABLE); + TIM_Cmd(timer, ENABLE); + } + + DMA_Channel_TypeDef *channel = timerHardware->dmaChannel; + + 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_HalfWord; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; + + TIM_DMACmd(timer, motor->timerDmaSource, ENABLE); + + DMA_ITConfig(channel, DMA_IT_TC, ENABLE); + DMA_Init(channel, &DMA_InitStructure); + + dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex); +} + + diff --git a/src/main/drivers/pwm_stm32f4xx.c b/src/main/drivers/pwm_stm32f4xx.c new file mode 100644 index 0000000000..e514b7200b --- /dev/null +++ b/src/main/drivers/pwm_stm32f4xx.c @@ -0,0 +1,216 @@ +/* + * 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" + +#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) * 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) ? MOTOR_BIT_1 : MOTOR_BIT_0; + motor->dmaBuffer[13] = (value & 0x200) ? MOTOR_BIT_1 : MOTOR_BIT_0; + motor->dmaBuffer[14] = (value & 0x100) ? MOTOR_BIT_1 : MOTOR_BIT_0; + motor->dmaBuffer[15] = (value & 0x80) ? 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), timerGPIOAF(timer)); + + 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); +} + + 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..bdb70bb63f 100644 --- a/src/main/drivers/timer_stm32f30x.c +++ b/src/main/drivers/timer_stm32f30x.c @@ -29,6 +29,10 @@ const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = { { .TIMx = TIM17, .rcc = RCC_APB2(TIM17) }, }; +uint8_t timerClockDivisor(TIM_TypeDef *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 77e6275404..a4f4411616 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 8fd14951a6..613a8366bc 100755 --- a/src/main/io/serial_cli.c +++ b/src/main/io/serial_cli.c @@ -520,7 +520,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 lookupTableDeltaMethod[] = { diff --git a/src/main/main.c b/src/main/main.c index c495a2eb5e..5ba35eceaa 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..2e1d85f2b0 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_TIM9, 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..78e7624769 100644 --- a/src/main/target/BLUEJAYF4/target.mk +++ b/src/main/target/BLUEJAYF4/target.mk @@ -5,4 +5,5 @@ TARGET_SRC = \ drivers/accgyro_spi_mpu6500.c \ drivers/accgyro_mpu6500.c \ drivers/barometer_ms5611.c + drivers/pwm_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..aa0490b07f 100644 --- a/src/main/target/KISSFC/target.mk +++ b/src/main/target/KISSFC/target.mk @@ -4,5 +4,6 @@ FEATURES = VCP TARGET_SRC = \ drivers/accgyro_mpu.c \ drivers/display_ug2864hsweg01.c \ - drivers/accgyro_mpu6050.c + drivers/accgyro_mpu6050.c \ + drivers/pwm_stm32f3xx.c 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/REVO/target.mk b/src/main/target/REVO/target.mk index 2711b19dac..377ad79bc5 100644 --- a/src/main/target/REVO/target.mk +++ b/src/main/target/REVO/target.mk @@ -5,3 +5,4 @@ TARGET_SRC = \ drivers/accgyro_spi_mpu6000.c \ drivers/barometer_ms5611.c \ drivers/compass_hmc5883l.c + drivers/pwm_stm32f4xx.c