diff --git a/radio/src/targets/common/arm/stm32/extmodule_driver.cpp b/radio/src/targets/common/arm/stm32/extmodule_driver.cpp index 2c0d6fdd3..daf9e5238 100644 --- a/radio/src/targets/common/arm/stm32/extmodule_driver.cpp +++ b/radio/src/targets/common/arm/stm32/extmodule_driver.cpp @@ -25,12 +25,6 @@ #include "hal.h" #include "timers_driver.h" -#if defined(CROSSFIRE) -#include "pulses/crossfire.h" -#endif - -#define STOP_TIMER_ON_LAST_UPDATE - static const stm32_pulse_timer_t extmoduleTimer = { .GPIOx = EXTMODULE_TX_GPIO, .GPIO_Pin = EXTMODULE_TX_GPIO_PIN, @@ -45,53 +39,23 @@ static const stm32_pulse_timer_t extmoduleTimer = { .DMA_IRQn = EXTMODULE_TIMER_DMA_STREAM_IRQn, }; -#if defined(STOP_TIMER_ON_LAST_UPDATE) - -static_assert(EXTMODULE_TIMER_Channel == LL_TIM_CHANNEL_CH1 - || EXTMODULE_TIMER_Channel == LL_TIM_CHANNEL_CH1N - || EXTMODULE_TIMER_Channel == LL_TIM_CHANNEL_CH3, +// Make sure the timer channel is supported +static_assert(__STM32_PULSE_IS_TIMER_CHANNEL_SUPPORTED(EXTMODULE_TIMER_Channel), "Unsupported timer channel"); -static void set_compare_reg(uint32_t val) -{ - switch(EXTMODULE_TIMER_Channel){ - case LL_TIM_CHANNEL_CH1: - case LL_TIM_CHANNEL_CH1N: - LL_TIM_OC_SetCompareCH1(EXTMODULE_TIMER, val); - break; - case LL_TIM_CHANNEL_CH3: - LL_TIM_OC_SetCompareCH3(EXTMODULE_TIMER, val); - break; - } -} +// Make sure the DMA channel is supported +static_assert(__STM32_PULSE_IS_DMA_STREAM_SUPPORTED(EXTMODULE_TIMER_DMA_STREAM_LL), + "Unsupported DMA stream"); extern "C" void EXTMODULE_TIMER_DMA_IRQHandler() { - if (!LL_DMA_IsActiveFlag_TC5(EXTMODULE_TIMER_DMA)) - return; - - LL_DMA_ClearFlag_TC5(EXTMODULE_TIMER_DMA); - - LL_TIM_ClearFlag_UPDATE(EXTMODULE_TIMER); - LL_TIM_EnableIT_UPDATE(EXTMODULE_TIMER); - - set_compare_reg(0); - LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, LL_TIM_OCMODE_PWM1); + stm32_pulse_dma_tc_isr(&extmoduleTimer); } extern "C" void EXTMODULE_TIMER_IRQHandler() { - if (!LL_TIM_IsActiveFlag_UPDATE(EXTMODULE_TIMER)) - return; - - LL_TIM_ClearFlag_UPDATE(EXTMODULE_TIMER); - LL_TIM_DisableIT_UPDATE(EXTMODULE_TIMER); - - // Halt pulses and force to inactive level - LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, - LL_TIM_OCMODE_FORCED_INACTIVE); + stm32_pulse_tim_update_isr(&extmoduleTimer); } -#endif void extmoduleStop() { @@ -135,23 +99,15 @@ void extmodulePpmStart(uint16_t ppm_delay, bool polarity) void extmoduleSendNextFramePpm(void* pulses, uint16_t length, uint16_t ppm_delay, bool polarity) { - if (!stm32_pulse_stop_if_running(&extmoduleTimer)) + if (!stm32_pulse_if_not_running_disable(&extmoduleTimer)) return; - // Config output - set_compare_reg(ppm_delay * 2); - - uint32_t ll_polarity; - if (polarity) { - ll_polarity = LL_TIM_OCPOLARITY_LOW; - } else { - ll_polarity = LL_TIM_OCPOLARITY_HIGH; - } - LL_TIM_OC_SetPolarity(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, ll_polarity); - LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, LL_TIM_OCMODE_PWM1); + // Set polarity + stm32_pulse_set_polarity(&extmoduleTimer, !polarity); // Start DMA request and re-enable timer - stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); + stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length, + LL_TIM_OCMODE_PWM1, ppm_delay * 2); } #if defined(PXX1) @@ -174,14 +130,12 @@ void extmodulePxx1PulsesStart() void extmoduleSendNextFramePxx1(const void* pulses, uint16_t length) { - if (!stm32_pulse_stop_if_running(&extmoduleTimer)) + if (!stm32_pulse_if_not_running_disable(&extmoduleTimer)) return; - set_compare_reg(9 * 2); - LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, LL_TIM_OCMODE_PWM1); - // Start DMA request and re-enable timer - stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); + stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length, + LL_TIM_OCMODE_PWM1, 9 * 2); } #endif @@ -204,20 +158,14 @@ void extmoduleSerialStart() void extmoduleSendNextFrameSoftSerial(const void* pulses, uint16_t length, bool polarity) { - if (!stm32_pulse_stop_if_running(&extmoduleTimer)) + if (!stm32_pulse_if_not_running_disable(&extmoduleTimer)) return; - uint32_t ll_polarity; - if (polarity) { - ll_polarity = LL_TIM_OCPOLARITY_HIGH; - } else { - ll_polarity = LL_TIM_OCPOLARITY_LOW; - } - LL_TIM_OC_SetPolarity(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, ll_polarity); - LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, LL_TIM_OCMODE_TOGGLE); - + // Set polarity + stm32_pulse_set_polarity(&extmoduleTimer, polarity); + // Start DMA request and re-enable timer - stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); + stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length, LL_TIM_OCMODE_TOGGLE, 0); } // Delay based byte sending @ 57600 bps diff --git a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp index 207f5cb49..6dbb5bde0 100644 --- a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp @@ -22,8 +22,6 @@ #include "stm32_pulse_driver.h" #include "definitions.h" -#define STOP_TIMER_ON_LAST_UPDATE - void stm32_pulse_init(const stm32_pulse_timer_t* tim) { LL_GPIO_InitTypeDef pinInit; @@ -41,7 +39,6 @@ void stm32_pulse_init(const stm32_pulse_timer_t* tim) timInit.Autoreload = 65535; LL_TIM_Init(tim->TIMx, &timInit); -#if defined(STOP_TIMER_ON_LAST_UPDATE) // Enable DMA IRQ NVIC_EnableIRQ(tim->DMA_IRQn); NVIC_SetPriority(tim->DMA_IRQn, 7); @@ -49,11 +46,14 @@ void stm32_pulse_init(const stm32_pulse_timer_t* tim) // Enable timer IRQ NVIC_EnableIRQ(tim->TIM_IRQn); NVIC_SetPriority(tim->TIM_IRQn, 7); -#endif } void stm32_pulse_deinit(const stm32_pulse_timer_t* tim) { + // Disable IRQs + NVIC_DisableIRQ(tim->DMA_IRQn); + NVIC_DisableIRQ(tim->TIM_IRQn); + // De-init DMA & timer LL_DMA_DeInit(tim->DMAx, tim->DMA_Stream); LL_TIM_DeInit(tim->TIMx); @@ -79,8 +79,19 @@ void stm32_pulse_config_output(const stm32_pulse_timer_t* tim, LL_TIM_OC_InitTyp LL_TIM_EnableDMAReq_UPDATE(tim->TIMx); } +void stm32_pulse_set_polarity(const stm32_pulse_timer_t* tim, bool polarity) +{ + uint32_t ll_polarity; + if (polarity) { + ll_polarity = LL_TIM_OCPOLARITY_HIGH; + } else { + ll_polarity = LL_TIM_OCPOLARITY_LOW; + } + LL_TIM_OC_SetPolarity(tim->TIMx, tim->TIM_Channel, ll_polarity); +} + // return true if stopped, false otherwise -bool stm32_pulse_stop_if_running(const stm32_pulse_timer_t* tim) +bool stm32_pulse_if_not_running_disable(const stm32_pulse_timer_t* tim) { if (LL_DMA_IsEnabledStream(tim->DMAx, tim->DMA_Stream)) return false; @@ -92,8 +103,22 @@ bool stm32_pulse_stop_if_running(const stm32_pulse_timer_t* tim) return true; } +static void set_compare_reg(const stm32_pulse_timer_t* tim, uint32_t val) +{ + switch(tim->TIM_Channel){ + case LL_TIM_CHANNEL_CH1: + case LL_TIM_CHANNEL_CH1N: + LL_TIM_OC_SetCompareCH1(tim->TIMx, val); + break; + case LL_TIM_CHANNEL_CH3: + LL_TIM_OC_SetCompareCH3(tim->TIMx, val); + break; + } +} + void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, - const void* pulses, uint16_t length) + const void* pulses, uint16_t length, + uint32_t ocmode, uint32_t cmp_val) { // re-init DMA stream LL_DMA_DeInit(tim->DMAx, tim->DMA_Stream); @@ -128,10 +153,8 @@ void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, LL_DMA_Init(tim->DMAx, tim->DMA_Stream, &dmaInit); -#if defined(STOP_TIMER_ON_LAST_UPDATE) // Enable TC IRQ LL_DMA_EnableIT_TC(tim->DMAx, tim->DMA_Stream); -#endif // Enable DMA LL_TIM_ClearFlag_UPDATE(tim->TIMx); @@ -139,6 +162,10 @@ void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, LL_TIM_SetCounter(tim->TIMx, 0); LL_DMA_EnableStream(tim->DMAx, tim->DMA_Stream); + // Re-configure timer output + set_compare_reg(tim, cmp_val); + LL_TIM_OC_SetMode(tim->TIMx, tim->TIM_Channel, ocmode); + // Trigger update to effect the first DMA transation // and thus load ARR with the first duration LL_TIM_EnableDMAReq_UPDATE(tim->TIMx); @@ -147,3 +174,45 @@ void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, // start timer LL_TIM_EnableCounter(tim->TIMx); } + +static bool check_and_clean_dma_tc_flag(const stm32_pulse_timer_t* tim) +{ + switch(tim->DMA_Stream) { + case LL_DMA_STREAM_1: + if (!LL_DMA_IsActiveFlag_TC1(tim->DMAx)) return false; + LL_DMA_ClearFlag_TC1(tim->DMAx); + break; + case LL_DMA_STREAM_5: + if (!LL_DMA_IsActiveFlag_TC5(tim->DMAx)) return false; + LL_DMA_ClearFlag_TC5(tim->DMAx); + break; + case LL_DMA_STREAM_7: + if (!LL_DMA_IsActiveFlag_TC7(tim->DMAx)) return false; + LL_DMA_ClearFlag_TC7(tim->DMAx); + break; + } + return true; +} + +void stm32_pulse_dma_tc_isr(const stm32_pulse_timer_t* tim) +{ + if (!check_and_clean_dma_tc_flag(tim)) return; + + LL_TIM_ClearFlag_UPDATE(tim->TIMx); + LL_TIM_EnableIT_UPDATE(tim->TIMx); + + set_compare_reg(tim, 0); + LL_TIM_OC_SetMode(tim->TIMx, tim->TIM_Channel, LL_TIM_OCMODE_PWM1); +} + +void stm32_pulse_tim_update_isr(const stm32_pulse_timer_t* tim) +{ + if (!LL_TIM_IsActiveFlag_UPDATE(tim->TIMx)) + return; + + LL_TIM_ClearFlag_UPDATE(tim->TIMx); + LL_TIM_DisableIT_UPDATE(tim->TIMx); + + // Halt pulses by forcing to inactive level + LL_TIM_OC_SetMode(tim->TIMx, tim->TIM_Channel, LL_TIM_OCMODE_FORCED_INACTIVE); +} diff --git a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h index e97df6124..cce089da8 100644 --- a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h +++ b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h @@ -44,9 +44,25 @@ struct stm32_pulse_timer_t { void stm32_pulse_init(const stm32_pulse_timer_t* tim); void stm32_pulse_deinit(const stm32_pulse_timer_t* tim); void stm32_pulse_config_output(const stm32_pulse_timer_t* tim, LL_TIM_OC_InitTypeDef* ocInit); +void stm32_pulse_set_polarity(const stm32_pulse_timer_t* tim, bool polarity); -// return true if stopped, false otherwise -bool stm32_pulse_stop_if_running(const stm32_pulse_timer_t* tim); +// return true if it could be disabled without interrupting a pulse train, false otherwise +bool stm32_pulse_if_not_running_disable(const stm32_pulse_timer_t* tim); void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, - const void* pulses, uint16_t length); + const void* pulses, uint16_t length, + uint32_t ocmode, uint32_t cmp_val); + +// Must be called from DMA TC IRQ handler +void stm32_pulse_dma_tc_isr(const stm32_pulse_timer_t* tim); + +// Must be called from timer UPDATE IRQ handler +void stm32_pulse_tim_update_isr(const stm32_pulse_timer_t* tim); + +#define __STM32_PULSE_IS_TIMER_CHANNEL_SUPPORTED(ch) \ + ((ch) == LL_TIM_CHANNEL_CH1 || (ch) == LL_TIM_CHANNEL_CH1N || \ + (ch) == LL_TIM_CHANNEL_CH3) + +#define __STM32_PULSE_IS_DMA_STREAM_SUPPORTED(stream) \ + ((stream) == LL_DMA_STREAM_1 || (stream) == LL_DMA_STREAM_5 || \ + (stream) == LL_DMA_STREAM_7)