diff --git a/src/main/drivers/pwm_output.h b/src/main/drivers/pwm_output.h index 7a954218fc..d0021d1b75 100644 --- a/src/main/drivers/pwm_output.h +++ b/src/main/drivers/pwm_output.h @@ -109,9 +109,14 @@ typedef enum { typedef struct { TIM_TypeDef *timer; - uint16_t timerDmaSources; -#ifdef USE_DSHOT_DMAR +#if defined(USE_DSHOT_DMAR) +#if !defined(USE_HAL_DRIVER) + DMA_Stream_TypeDef *dmaBurstRef; + uint16_t dmaBurstLength; +#endif uint32_t dmaBurstBuffer[DSHOT_DMA_BUFFER_SIZE * 4]; +#else + uint16_t timerDmaSources; #endif } motorDmaTimer_t; @@ -119,7 +124,9 @@ typedef struct { ioTag_t ioTag; const timerHardware_t *timerHardware; uint16_t value; +#if !defined(USE_DSHOT_DMAR) uint16_t timerDmaSource; +#endif motorDmaTimer_t *timer; volatile bool requestTelemetry; #if defined(STM32F3) || defined(STM32F4) || defined(STM32F7) diff --git a/src/main/drivers/pwm_output_dshot.c b/src/main/drivers/pwm_output_dshot.c index 3fbedafaa6..7922a2d83f 100644 --- a/src/main/drivers/pwm_output_dshot.c +++ b/src/main/drivers/pwm_output_dshot.c @@ -22,6 +22,8 @@ #ifdef USE_DSHOT +#include "build/debug.h" + #include "drivers/io.h" #include "timer.h" #if defined(STM32F4) @@ -58,17 +60,34 @@ void pwmWriteDshotInt(uint8_t index, uint16_t value) { motorDmaOutput_t *const motor = &dmaMotors[index]; +#ifdef USE_DSHOT_DMAR + if (!motor->timerHardware || !motor->timerHardware->dmaTimUPRef) { + return; + } +#else if (!motor->timerHardware || !motor->timerHardware->dmaRef) { return; } +#endif uint16_t packet = prepareDshotPacket(motor, value); + // XXX Replace this with striding loader in the next refactor uint8_t bufferSize = loadDmaBuffer(motor, packet); +#ifdef USE_DSHOT_DMAR + // Load channel data into burst buffer + uint8_t channelIndex = timerLookupChannelIndex(motor->timerHardware->channel); + // XXX This copy will be deleted once the striding loader is available + for (int i = 0; i < bufferSize; i++) { + motor->timer->dmaBurstBuffer[channelIndex + i * 4] = motor->dmaBuffer[i]; + } + motor->timer->dmaBurstLength = bufferSize * 4; +#else motor->timer->timerDmaSources |= motor->timerDmaSource; DMA_SetCurrDataCounter(motor->timerHardware->dmaRef, bufferSize); DMA_Cmd(motor->timerHardware->dmaRef, ENABLE); +#endif } void pwmCompleteDshotMotorUpdate(uint8_t motorCount) @@ -76,9 +95,16 @@ void pwmCompleteDshotMotorUpdate(uint8_t motorCount) UNUSED(motorCount); for (int i = 0; i < dmaMotorTimerCount; i++) { +#ifdef USE_DSHOT_DMAR + DMA_SetCurrDataCounter(dmaMotorTimers[i].dmaBurstRef, dmaMotorTimers[i].dmaBurstLength); + DMA_Cmd(dmaMotorTimers[i].dmaBurstRef, ENABLE); + TIM_DMAConfig(dmaMotorTimers[i].timer, TIM_DMABase_CCR1, TIM_DMABurstLength_4Transfers); + TIM_DMACmd(dmaMotorTimers[i].timer, TIM_DMA_Update, ENABLE); +#else TIM_SetCounter(dmaMotorTimers[i].timer, 0); TIM_DMACmd(dmaMotorTimers[i].timer, dmaMotorTimers[i].timerDmaSources, ENABLE); dmaMotorTimers[i].timerDmaSources = 0; +#endif } } @@ -86,14 +112,35 @@ static void motor_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor) { if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) { motorDmaOutput_t * const motor = &dmaMotors[descriptor->userParam]; +#ifdef USE_DSHOT_DMAR + DMA_Cmd(motor->timerHardware->dmaTimUPRef, DISABLE); + TIM_DMACmd(motor->timerHardware->tim, TIM_DMA_Update, DISABLE); +#else DMA_Cmd(motor->timerHardware->dmaRef, DISABLE); TIM_DMACmd(motor->timerHardware->tim, motor->timerDmaSource, DISABLE); +#endif DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF); } } void pwmDshotMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, motorPwmProtocolTypes_e pwmProtocolType, uint8_t output) { +#if defined(STM32F3) + DMA_Channel_TypeDef *dmaRef = timerHardware->dmaRef; +#elif defined(STM32F4) +#ifdef USE_DSHOT_DMAR + DMA_Stream_TypeDef *dmaRef = timerHardware->dmaTimUPRef; +#else + DMA_Stream_TypeDef *dmaRef = timerHardware->dmaRef; +#endif +#else +#error "No MCU specified in DSHOT" +#endif + + if (dmaRef == NULL) { + return; + } + TIM_OCInitTypeDef TIM_OCInitStructure; DMA_InitTypeDef DMA_InitStructure; @@ -138,9 +185,6 @@ void pwmDshotMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t m timerOCInit(timer, timerHardware->channel, &TIM_OCInitStructure); timerOCPreloadConfig(timer, timerHardware->channel, TIM_OCPreload_Enable); - motor->timerDmaSource = timerDmaSource(timerHardware->channel); - motor->timer = &dmaMotorTimers[timerIndex]; - motor->timer->timerDmaSources &= ~motor->timerDmaSource; if (output & TIMER_OUTPUT_N_CHANNEL) { TIM_CCxNCmd(timer, timerHardware->channel, TIM_CCxN_Enable); @@ -154,25 +198,47 @@ void pwmDshotMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t m TIM_Cmd(timer, ENABLE); } -#if defined(STM32F3) - DMA_Channel_TypeDef *dmaRef = timerHardware->dmaRef; -#elif defined(STM32F4) - DMA_Stream_TypeDef *dmaRef = timerHardware->dmaRef; -#else -#error "No MCU specified in DSHOT" -#endif + motor->timer = &dmaMotorTimers[timerIndex]; - if (dmaRef == NULL) { +#ifdef USE_DSHOT_DMAR + motor->timer->dmaBurstRef = dmaRef; + + if (!configureTimer) { return; } - - dmaInit(timerHardware->dmaIrqHandler, OWNER_MOTOR, RESOURCE_INDEX(motorIndex)); - dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex); +#else + motor->timerDmaSource = timerDmaSource(timerHardware->channel); + motor->timer->timerDmaSources &= ~motor->timerDmaSource; +#endif DMA_Cmd(dmaRef, DISABLE); DMA_DeInit(dmaRef); - DMA_StructInit(&DMA_InitStructure); + +#ifdef USE_DSHOT_DMAR + dmaInit(timerHardware->dmaTimUPIrqHandler, OWNER_TIMUP, timerGetTIMNumber(timerHardware->tim)); + dmaSetHandler(timerHardware->dmaTimUPIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex); + + DMA_InitStructure.DMA_Channel = timerHardware->dmaTimUPChannel; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)motor->timer->dmaBurstBuffer; + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&timerHardware->tim->DMAR; + DMA_InitStructure.DMA_BufferSize = (pwmProtocolType == PWM_TYPE_PROSHOT1000) ? PROSHOT_DMA_BUFFER_SIZE : DSHOT_DMA_BUFFER_SIZE; // XXX + 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; + +#else // !USE_DSHOT_DMAR + dmaInit(timerHardware->dmaIrqHandler, OWNER_MOTOR, RESOURCE_INDEX(motorIndex)); + dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex); + #if defined(STM32F3) DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)motor->dmaBuffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; @@ -194,6 +260,9 @@ void pwmDshotMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t m DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; +#endif // USE_DSHOT_DMAR + + // XXX Consolidate common settings in the next refactor DMA_Init(dmaRef, &DMA_InitStructure); DMA_ITConfig(dmaRef, DMA_IT_TC, ENABLE); diff --git a/src/main/drivers/timer.c b/src/main/drivers/timer.c index 70e4b9c202..c94b4659d3 100644 --- a/src/main/drivers/timer.c +++ b/src/main/drivers/timer.c @@ -193,11 +193,85 @@ TIM_TypeDef * const usedTimers[USED_TIMER_COUNT] = { #undef _DEF }; +// Map timer index to timer number (Straight copy of usedTimers array) +const int8_t timerNumbers[USED_TIMER_COUNT] = { +#define _DEF(i) i + +#if USED_TIMERS & TIM_N(1) + _DEF(1), +#endif +#if USED_TIMERS & TIM_N(2) + _DEF(2), +#endif +#if USED_TIMERS & TIM_N(3) + _DEF(3), +#endif +#if USED_TIMERS & TIM_N(4) + _DEF(4), +#endif +#if USED_TIMERS & TIM_N(5) + _DEF(5), +#endif +#if USED_TIMERS & TIM_N(6) + _DEF(6), +#endif +#if USED_TIMERS & TIM_N(7) + _DEF(7), +#endif +#if USED_TIMERS & TIM_N(8) + _DEF(8), +#endif +#if USED_TIMERS & TIM_N(9) + _DEF(9), +#endif +#if USED_TIMERS & TIM_N(10) + _DEF(10), +#endif +#if USED_TIMERS & TIM_N(11) + _DEF(11), +#endif +#if USED_TIMERS & TIM_N(12) + _DEF(12), +#endif +#if USED_TIMERS & TIM_N(13) + _DEF(13), +#endif +#if USED_TIMERS & TIM_N(14) + _DEF(14), +#endif +#if USED_TIMERS & TIM_N(15) + _DEF(15), +#endif +#if USED_TIMERS & TIM_N(16) + _DEF(16), +#endif +#if USED_TIMERS & TIM_N(17) + _DEF(17), +#endif +#undef _DEF +}; + +int8_t timerGetTIMNumber(const TIM_TypeDef *tim) +{ + uint8_t index = lookupTimerIndex(tim); + + if (index < USED_TIMER_COUNT) { + return timerNumbers[index]; + } else { + return 0; + } +} + static inline uint8_t lookupChannelIndex(const uint16_t channel) { return channel >> 2; } +uint8_t timerLookupChannelIndex(const uint16_t channel) +{ + return lookupChannelIndex(channel); +} + rccPeriphTag_t timerRCC(TIM_TypeDef *tim) { for (int i = 0; i < HARDWARE_TIMER_DEFINITION_COUNT; i++) { diff --git a/src/main/drivers/timer.h b/src/main/drivers/timer.h index 9c7779e79d..1b838c1333 100644 --- a/src/main/drivers/timer.h +++ b/src/main/drivers/timer.h @@ -104,7 +104,7 @@ typedef struct timerHardware_s { DMA_Channel_TypeDef *dmaRef; #endif uint8_t dmaIrqHandler; -#if defined(STM32F7) +#if defined(STM32F4) || defined(STM32F7) // TIMUP DMA_Stream_TypeDef *dmaTimUPRef; uint32_t dmaTimUPChannel; @@ -212,3 +212,4 @@ uint16_t timerGetPrescalerByDesiredMhz(TIM_TypeDef *tim, uint16_t mhz); uint16_t timerGetPeriodByPrescaler(TIM_TypeDef *tim, uint16_t prescaler, uint32_t hz); int8_t timerGetTIMNumber(const TIM_TypeDef *tim); +uint8_t timerLookupChannelIndex(const uint16_t channel); diff --git a/src/main/drivers/timer_def.h b/src/main/drivers/timer_def.h index 300f4488ee..b0a4dc0bb9 100644 --- a/src/main/drivers/timer_def.h +++ b/src/main/drivers/timer_def.h @@ -374,6 +374,11 @@ DEF_TIM_DMA_STREAM(dmaopt, TCH_## tim ## _ ## chan), \ DEF_TIM_DMA_CHANNEL(dmaopt, TCH_## tim ## _ ## chan), \ DEF_TIM_DMA_HANDLER(dmaopt, TCH_## tim ## _ ## chan) \ + ), \ + DEF_TIM_DMA_COND( \ + DEF_TIM_DMA_STREAM(0, TCH_## tim ## _UP), \ + DEF_TIM_DMA_CHANNEL(0, TCH_## tim ## _UP), \ + DEF_TIM_DMA_HANDLER(0, TCH_## tim ## _UP) \ ) \ } \ /**/ @@ -447,6 +452,22 @@ #define DEF_TIM_DMA__BTCH_TIM14_CH1 NONE +// TIM_UP table +#define DEF_TIM_DMA__BTCH_TIM1_UP D(2, 5, 6) +#define DEF_TIM_DMA__BTCH_TIM2_UP D(1, 7, 3) +#define DEF_TIM_DMA__BTCH_TIM3_UP D(1, 2, 5) +#define DEF_TIM_DMA__BTCH_TIM4_UP D(1, 6, 2) +#define DEF_TIM_DMA__BTCH_TIM5_UP D(1, 0, 6) +#define DEF_TIM_DMA__BTCH_TIM6_UP D(1, 1, 7) +#define DEF_TIM_DMA__BTCH_TIM7_UP D(1, 4, 1) +#define DEF_TIM_DMA__BTCH_TIM8_UP D(2, 1, 7) +#define DEF_TIM_DMA__BTCH_TIM9_UP NONE +#define DEF_TIM_DMA__BTCH_TIM10_UP NONE +#define DEF_TIM_DMA__BTCH_TIM11_UP NONE +#define DEF_TIM_DMA__BTCH_TIM12_UP NONE +#define DEF_TIM_DMA__BTCH_TIM13_UP NONE +#define DEF_TIM_DMA__BTCH_TIM14_UP NONE + #elif defined(STM32F7) #define DEF_TIM(tim, chan, pin, flags, out, dmaopt) { \ tim, \ diff --git a/src/main/target/OMNIBUSF4/target.mk b/src/main/target/OMNIBUSF4/target.mk index 2322ae374b..a7a01edc5a 100644 --- a/src/main/target/OMNIBUSF4/target.mk +++ b/src/main/target/OMNIBUSF4/target.mk @@ -9,4 +9,4 @@ TARGET_SRC = \ drivers/barometer/barometer_ms5611.c \ drivers/compass/compass_hmc5883l.c \ drivers/max7456.c - \ No newline at end of file + diff --git a/src/main/target/common_fc_pre.h b/src/main/target/common_fc_pre.h index d96eea06bd..15e42e28f8 100644 --- a/src/main/target/common_fc_pre.h +++ b/src/main/target/common_fc_pre.h @@ -46,6 +46,7 @@ #ifdef STM32F4 #define USE_DSHOT +#define USE_DSHOT_DMAR #define USE_ESC_SENSOR #define I2C3_OVERCLOCK true #define USE_TELEMETRY_IBUS