From 3057652b40c4f5edc13883cf0eb4340dd3bbdeff Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Fri, 11 Mar 2022 19:09:25 +0100 Subject: [PATCH] Force inactive output between pulse trains --- radio/src/pulses/dsm2.cpp | 4 +- radio/src/pulses/ppm.cpp | 4 +- radio/src/pulses/pxx.h | 2 +- radio/src/pulses/sbus.cpp | 4 +- .../common/arm/stm32/extmodule_driver.cpp | 146 ++++++++++++------ .../common/arm/stm32/stm32_pulse_driver.cpp | 32 +++- .../common/arm/stm32/stm32_pulse_driver.h | 2 + radio/src/targets/horus/hal.h | 8 +- 8 files changed, 143 insertions(+), 59 deletions(-) diff --git a/radio/src/pulses/dsm2.cpp b/radio/src/pulses/dsm2.cpp index 7e6b7f6a2..0cd037e2b 100644 --- a/radio/src/pulses/dsm2.cpp +++ b/radio/src/pulses/dsm2.cpp @@ -66,9 +66,9 @@ void sendByteDsm2(uint8_t b) // max 10 changes 0 10 10 10 10 1 void putDsm2Flush() { if (extmodulePulsesData.dsm2.index & 1) - *extmodulePulsesData.dsm2.ptr++ = 60000; + *extmodulePulsesData.dsm2.ptr++ = 255; else - *(extmodulePulsesData.dsm2.ptr - 1) = 60000; + *(extmodulePulsesData.dsm2.ptr - 1) = 255; } // This is the data stream to send, prepare after 19.5 mS diff --git a/radio/src/pulses/ppm.cpp b/radio/src/pulses/ppm.cpp index efea8522d..5844568de 100644 --- a/radio/src/pulses/ppm.cpp +++ b/radio/src/pulses/ppm.cpp @@ -47,7 +47,9 @@ void setupPulsesPPM(PpmPulsesData * ppmPulsesData, uint8_t channelsStart, int // Set the final period to the max // (a new transfer is issued before it expires) - *ppmPulsesData->ptr++ = 65535; + // debug: set the last period to the ppm_delay + *ppmPulsesData->ptr++ = 2000; + //*ppmPulsesData->ptr++ = 65535; // it's needed in case PPM is sent without DMA // (we stop when we reach this 0) diff --git a/radio/src/pulses/pxx.h b/radio/src/pulses/pxx.h index f026c7b1c..14c2ae8a2 100644 --- a/radio/src/pulses/pxx.h +++ b/radio/src/pulses/pxx.h @@ -122,7 +122,7 @@ class PwmPxxBitTransport: public PulsesBuffer { void addTail() { // rest min value is 18000 - 200 * 48 = 8400 (4.2ms) - *(ptr - 1) = 60000; + *(ptr - 1) = 255; } }; diff --git a/radio/src/pulses/sbus.cpp b/radio/src/pulses/sbus.cpp index 0b2c8f407..a1e6535b7 100644 --- a/radio/src/pulses/sbus.cpp +++ b/radio/src/pulses/sbus.cpp @@ -92,9 +92,9 @@ inline int getChannelValue(uint8_t port, int channel) static void sbusFlush() { if (extmodulePulsesData.dsm2.index & 1) - *extmodulePulsesData.dsm2.ptr++ = 60000; + *extmodulePulsesData.dsm2.ptr++ = 255; else - *(extmodulePulsesData.dsm2.ptr - 1) = 60000; + *(extmodulePulsesData.dsm2.ptr - 1) = 255; } void setupPulsesSbus() diff --git a/radio/src/targets/common/arm/stm32/extmodule_driver.cpp b/radio/src/targets/common/arm/stm32/extmodule_driver.cpp index 8deddf726..12dca7046 100644 --- a/radio/src/targets/common/arm/stm32/extmodule_driver.cpp +++ b/radio/src/targets/common/arm/stm32/extmodule_driver.cpp @@ -29,6 +29,8 @@ #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, @@ -36,22 +38,69 @@ static const stm32_pulse_timer_t extmoduleTimer = { .TIMx = EXTMODULE_TIMER, .TIM_Prescaler = __LL_TIM_CALC_PSC(EXTMODULE_TIMER_FREQ, 2000000), .TIM_Channel = EXTMODULE_TIMER_Channel, + .TIM_IRQn = EXTMODULE_TIMER_IRQn, .DMAx = EXTMODULE_TIMER_DMA, .DMA_Stream = EXTMODULE_TIMER_DMA_STREAM_LL, .DMA_Channel = EXTMODULE_TIMER_DMA_CHANNEL, + .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, + "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; + } +} + +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); +} + +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); +} +#endif + void extmoduleStop() { EXTERNAL_MODULE_OFF(); stm32_pulse_deinit(&extmoduleTimer); } -void extmodulePpmStart(uint16_t ppm_delay, bool polarity) +static void config_ppm_output(uint16_t ppm_delay, bool polarity) { - EXTERNAL_MODULE_ON(); - stm32_pulse_init(&extmoduleTimer); - // PPM generation principle: // // Hardware timer in PWM mode is used for PPM generation @@ -65,7 +114,6 @@ void extmodulePpmStart(uint16_t ppm_delay, bool polarity) ocInit.OCMode = LL_TIM_OCMODE_PWM1; ocInit.OCState = LL_TIM_OCSTATE_ENABLE; - ocInit.OCNState = LL_TIM_OCSTATE_ENABLE; if (polarity) { ocInit.OCPolarity = LL_TIM_OCPOLARITY_LOW; @@ -74,28 +122,70 @@ void extmodulePpmStart(uint16_t ppm_delay, bool polarity) } ocInit.CompareValue = ppm_delay * 2; - stm32_pulse_config_output(&extmoduleTimer, &ocInit); + stm32_pulse_config_output(&extmoduleTimer, &ocInit); +} + +void extmodulePpmStart(uint16_t ppm_delay, bool polarity) +{ + EXTERNAL_MODULE_ON(); + stm32_pulse_init(&extmoduleTimer); + config_ppm_output(ppm_delay, polarity); +} + +void extmoduleSendNextFramePpm(void* pulses, uint16_t length, + uint16_t ppm_delay, bool polarity) +{ + if (!stm32_pulse_stop_if_running(&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); + + // Start DMA request and re-enable timer + stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); } #if defined(PXX1) void extmodulePxx1PulsesStart() { EXTERNAL_MODULE_ON(); - stm32_pulse_init(&extmoduleTimer); LL_TIM_OC_InitTypeDef ocInit; LL_TIM_OC_StructInit(&ocInit); ocInit.OCMode = LL_TIM_OCMODE_PWM1; ocInit.OCState = LL_TIM_OCSTATE_ENABLE; - ocInit.OCNState = LL_TIM_OCSTATE_ENABLE; ocInit.OCPolarity = LL_TIM_OCPOLARITY_LOW; ocInit.CompareValue = 9 * 2; // 9 uS stm32_pulse_config_output(&extmoduleTimer, &ocInit); + + stm32_pulse_init(&extmoduleTimer); +} + +void extmoduleSendNextFramePxx1(const void* pulses, uint16_t length) +{ + if (!stm32_pulse_stop_if_running(&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); } #endif +// TODO: polarity? void extmoduleSerialStart() { EXTERNAL_MODULE_ON(); @@ -112,44 +202,6 @@ void extmoduleSerialStart() stm32_pulse_config_output(&extmoduleTimer, &ocInit); } -void extmoduleSendNextFramePpm(void* pulses, uint16_t length, - uint16_t ppm_delay, bool polarity) -{ - if (!stm32_pulse_stop_if_running(&extmoduleTimer)) - return; - - switch(EXTMODULE_TIMER_Channel){ - case LL_TIM_CHANNEL_CH1: - LL_TIM_OC_SetCompareCH1(EXTMODULE_TIMER, ppm_delay * 2); - break; - case LL_TIM_CHANNEL_CH3: - LL_TIM_OC_SetCompareCH3(EXTMODULE_TIMER, ppm_delay * 2); - break; - } - - 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); - - // Start DMA request and re-enable timer - stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); -} - -#if defined(PXX1) -void extmoduleSendNextFramePxx1(const void* pulses, uint16_t length) -{ - if (!stm32_pulse_stop_if_running(&extmoduleTimer)) - return; - - // Start DMA request and re-enable timer - stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); -} -#endif - #if defined(AFHDS3) && !(defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)) void extmoduleSendNextFrameAFHDS3(const void* pulses, uint16_t length) { @@ -174,11 +226,13 @@ void extmoduleSendNextFrameSoftSerial100kbit(const void* pulses, uint16_t length 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); // Start DMA request and re-enable timer stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); } +// Delay based byte sending @ 57600 bps void extmoduleSendInvertedByte(uint8_t byte) { uint16_t time; 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 72345c6c0..207f5cb49 100644 --- a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp @@ -22,6 +22,8 @@ #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; @@ -38,6 +40,16 @@ void stm32_pulse_init(const stm32_pulse_timer_t* tim) timInit.Prescaler = tim->TIM_Prescaler; 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); + + // 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) @@ -57,7 +69,6 @@ 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) { - LL_TIM_DisableCounter(tim->TIMx); LL_TIM_OC_Init(tim->TIMx, tim->TIM_Channel, ocInit); LL_TIM_OC_EnablePreload(tim->TIMx, tim->TIM_Channel); @@ -66,7 +77,6 @@ void stm32_pulse_config_output(const stm32_pulse_timer_t* tim, LL_TIM_OC_InitTyp } LL_TIM_EnableDMAReq_UPDATE(tim->TIMx); - LL_TIM_EnableCounter(tim->TIMx); } // return true if stopped, false otherwise @@ -77,12 +87,15 @@ bool stm32_pulse_stop_if_running(const stm32_pulse_timer_t* tim) // disable timer LL_TIM_DisableCounter(tim->TIMx); + LL_TIM_DisableIT_UPDATE(tim->TIMx); + return true; } void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, const void* pulses, uint16_t length) { + // re-init DMA stream LL_DMA_DeInit(tim->DMAx, tim->DMA_Stream); LL_DMA_InitTypeDef dmaInit; @@ -112,12 +125,25 @@ void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, dmaInit.NbData = length; dmaInit.Channel = tim->DMA_Channel; dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH; + 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); + LL_TIM_DisableDMAReq_UPDATE(tim->TIMx); + LL_TIM_SetCounter(tim->TIMx, 0); LL_DMA_EnableStream(tim->DMAx, tim->DMA_Stream); - // re-init timer + // Trigger update to effect the first DMA transation + // and thus load ARR with the first duration + LL_TIM_EnableDMAReq_UPDATE(tim->TIMx); LL_TIM_GenerateEvent_UPDATE(tim->TIMx); + + // start timer LL_TIM_EnableCounter(tim->TIMx); } 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 08d7bf956..e97df6124 100644 --- a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h +++ b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h @@ -33,10 +33,12 @@ struct stm32_pulse_timer_t { TIM_TypeDef* TIMx; uint16_t TIM_Prescaler; uint32_t TIM_Channel; + IRQn_Type TIM_IRQn; DMA_TypeDef* DMAx; uint32_t DMA_Stream; uint32_t DMA_Channel; + IRQn_Type DMA_IRQn; }; void stm32_pulse_init(const stm32_pulse_timer_t* tim); diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index d3e2fba01..28312663a 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -859,7 +859,7 @@ #define EXTMODULE_TIMER_32BITS #define EXTMODULE_TIMER_DMA_SIZE (DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1) #define EXTMODULE_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) - #define EXTMODULE_TIMER_CC_IRQn TIM2_IRQn + #define EXTMODULE_TIMER_IRQn TIM2_IRQn #define EXTMODULE_TIMER_IRQHandler TIM2_IRQHandler #define EXTMODULE_TIMER_DMA_CHANNEL DMA_Channel_3 #define EXTMODULE_TIMER_DMA_STREAM DMA1_Stream1 @@ -891,8 +891,8 @@ #define EXTMODULE_TIMER TIM1 #define EXTMODULE_TIMER_Channel LL_TIM_CHANNEL_CH3 #define EXTMODULE_TIMER_DMA_SIZE (DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0) - #define EXTMODULE_TIMER_CC_IRQn TIM1_CC_IRQn - #define EXTMODULE_TIMER_IRQHandler TIM1_CC_IRQHandler + #define EXTMODULE_TIMER_IRQn TIM1_UP_TIM10_IRQn + #define EXTMODULE_TIMER_IRQHandler TIM1_UP_TIM10_IRQHandler #define EXTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) #define EXTMODULE_TIMER_DMA_CHANNEL DMA_Channel_6 #define EXTMODULE_TIMER_DMA_STREAM DMA2_Stream5 @@ -913,7 +913,7 @@ #define EXTMODULE_TIMER_Channel LL_TIM_CHANNEL_CH1 #define EXTMODULE_TIMER_32BITS #define EXTMODULE_TIMER_DMA_SIZE (DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1) - #define EXTMODULE_TIMER_CC_IRQn TIM2_IRQn + #define EXTMODULE_TIMER_IRQn TIM2_IRQn #define EXTMODULE_TIMER_IRQHandler TIM2_IRQHandler #define EXTMODULE_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) #define EXTMODULE_TIMER_DMA_CHANNEL DMA_Channel_3