From cee942a83423bf4a02ed2600979509c6607cddf0 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Wed, 9 Mar 2022 17:41:15 +0100 Subject: [PATCH] Streamline pulse driver In preparation of merging with taranis int-module pulse driver. --- .../common/arm/stm32/extmodule_driver.cpp | 150 ++++-------------- .../common/arm/stm32/stm32_pulse_driver.cpp | 123 ++++++++++++++ .../common/arm/stm32/stm32_pulse_driver.h | 50 ++++++ radio/src/targets/horus/CMakeLists.txt | 1 + radio/src/targets/nv14/CMakeLists.txt | 1 + radio/src/targets/taranis/CMakeLists.txt | 1 + radio/src/targets/taranis/hal.h | 9 +- 7 files changed, 207 insertions(+), 128 deletions(-) create mode 100644 radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp create mode 100644 radio/src/targets/common/arm/stm32/stm32_pulse_driver.h diff --git a/radio/src/targets/common/arm/stm32/extmodule_driver.cpp b/radio/src/targets/common/arm/stm32/extmodule_driver.cpp index 42324e091..d73bbcd14 100644 --- a/radio/src/targets/common/arm/stm32/extmodule_driver.cpp +++ b/radio/src/targets/common/arm/stm32/extmodule_driver.cpp @@ -19,112 +19,38 @@ * GNU General Public License for more details. */ -#include "stm32_hal_ll.h" -#include "hal.h" #include "extmodule_driver.h" +#include "stm32_pulse_driver.h" + +#include "hal.h" #include "timers_driver.h" #if defined(CROSSFIRE) #include "pulses/crossfire.h" #endif +static const stm32_pulse_timer_t extmoduleTimer = { + .GPIOx = EXTMODULE_TX_GPIO, + .GPIO_Pin = EXTMODULE_TX_GPIO_PIN, + .GPIO_Alternate = EXTMODULE_TIMER_TX_GPIO_AF, + .TIMx = EXTMODULE_TIMER, + .TIM_Prescaler = __LL_TIM_CALC_PSC(EXTMODULE_TIMER_FREQ, 2000000), + .TIM_Channel = EXTMODULE_TIMER_Channel, + .DMAx = EXTMODULE_TIMER_DMA, + .DMA_Stream = EXTMODULE_TIMER_DMA_STREAM_LL, + .DMA_Channel = EXTMODULE_TIMER_DMA_CHANNEL, +}; + void extmoduleStop() { EXTERNAL_MODULE_OFF(); - - // De-init DMA & timer - LL_DMA_DeInit(EXTMODULE_TIMER_DMA, EXTMODULE_TIMER_DMA_STREAM_LL); - LL_TIM_DeInit(EXTMODULE_TIMER); - - // Reconfigure pin as output - LL_GPIO_InitTypeDef pinInit; - LL_GPIO_StructInit(&pinInit); - - pinInit.Pin = EXTMODULE_TX_GPIO_PIN; - pinInit.Mode = LL_GPIO_MODE_OUTPUT; - LL_GPIO_Init(EXTMODULE_TX_GPIO, &pinInit); -} - -static void extmoduleInitTxTimerPin() -{ - LL_GPIO_InitTypeDef pinInit; - LL_GPIO_StructInit(&pinInit); - pinInit.Pin = EXTMODULE_TX_GPIO_PIN; - pinInit.Mode = LL_GPIO_MODE_ALTERNATE; - pinInit.Alternate = EXTMODULE_TIMER_TX_GPIO_AF; - LL_GPIO_Init(EXTMODULE_TX_GPIO, &pinInit); -} - -static void extmoduleInitBaseTimer() -{ - LL_TIM_InitTypeDef timInit; - LL_TIM_StructInit(&timInit); - - // 0.5uS (2Mhz) - timInit.Prescaler = __LL_TIM_CALC_PSC(EXTMODULE_TIMER_FREQ, 2000000); - timInit.Autoreload = 65535; - LL_TIM_Init(EXTMODULE_TIMER, &timInit); -} - -static void extmoduleStartOutput(LL_TIM_OC_InitTypeDef* p_ocInit) -{ - LL_TIM_DisableCounter(EXTMODULE_TIMER); - LL_TIM_OC_Init(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, p_ocInit); - LL_TIM_OC_EnablePreload(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel); - - if (IS_TIM_BREAK_INSTANCE(EXTMODULE_TIMER)) { - LL_TIM_EnableAllOutputs(EXTMODULE_TIMER); - } - - LL_TIM_EnableDMAReq_UPDATE(EXTMODULE_TIMER); - LL_TIM_EnableCounter(EXTMODULE_TIMER); -} - -static void extmoduleStartTimerDMARequest(const void* pulses, uint16_t length) -{ - LL_DMA_DeInit(EXTMODULE_TIMER_DMA, EXTMODULE_TIMER_DMA_STREAM_LL); - - LL_DMA_InitTypeDef dmaInit; - LL_DMA_StructInit(&dmaInit); - - // Direction - dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - - // Source - dmaInit.MemoryOrM2MDstAddress = CONVERT_PTR_UINT(pulses); - dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - - // Destination - dmaInit.PeriphOrM2MSrcAddress = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); - dmaInit.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - - // Data width - if (IS_TIM_32B_COUNTER_INSTANCE(EXTMODULE_TIMER)) { - dmaInit.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - dmaInit.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - } else { - dmaInit.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; - dmaInit.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; - } - - dmaInit.NbData = length; - dmaInit.Channel = EXTMODULE_TIMER_DMA_CHANNEL; - dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH; - LL_DMA_Init(EXTMODULE_TIMER_DMA, EXTMODULE_TIMER_DMA_STREAM_LL, &dmaInit); - - // Enable DMA - LL_DMA_EnableStream(EXTMODULE_TIMER_DMA, EXTMODULE_TIMER_DMA_STREAM_LL); - - // re-init timer - LL_TIM_GenerateEvent_UPDATE(EXTMODULE_TIMER); - LL_TIM_EnableCounter(EXTMODULE_TIMER); + stm32_pulse_deinit(&extmoduleTimer); } void extmodulePpmStart(uint16_t ppm_delay, bool polarity) { EXTERNAL_MODULE_ON(); - extmoduleInitTxTimerPin(); - extmoduleInitBaseTimer(); + stm32_pulse_init(&extmoduleTimer); // PPM generation principle: // @@ -147,15 +73,14 @@ void extmodulePpmStart(uint16_t ppm_delay, bool polarity) } ocInit.CompareValue = ppm_delay * 2; - extmoduleStartOutput(&ocInit); + stm32_pulse_config_output(&extmoduleTimer, &ocInit); } #if defined(PXX1) void extmodulePxx1PulsesStart() { EXTERNAL_MODULE_ON(); - extmoduleInitTxTimerPin(); - extmoduleInitBaseTimer(); + stm32_pulse_init(&extmoduleTimer); LL_TIM_OC_InitTypeDef ocInit; LL_TIM_OC_StructInit(&ocInit); @@ -166,15 +91,14 @@ void extmodulePxx1PulsesStart() ocInit.OCPolarity = LL_TIM_OCPOLARITY_LOW; ocInit.CompareValue = 9 * 2; // 9 uS - extmoduleStartOutput(&ocInit); + stm32_pulse_config_output(&extmoduleTimer, &ocInit); } #endif void extmoduleSerialStart() { EXTERNAL_MODULE_ON(); - extmoduleInitTxTimerPin(); - extmoduleInitBaseTimer(); + stm32_pulse_init(&extmoduleTimer); LL_TIM_OC_InitTypeDef ocInit; LL_TIM_OC_StructInit(&ocInit); @@ -184,19 +108,15 @@ void extmoduleSerialStart() ocInit.OCPolarity = LL_TIM_OCPOLARITY_LOW; ocInit.CompareValue = 0; - extmoduleStartOutput(&ocInit); + stm32_pulse_config_output(&extmoduleTimer, &ocInit); } void extmoduleSendNextFramePpm(void* pulses, uint16_t length, uint16_t ppm_delay, bool polarity) { - if (LL_DMA_IsEnabledStream(EXTMODULE_TIMER_DMA, - EXTMODULE_TIMER_DMA_STREAM_LL)) + if (!stm32_pulse_stop_if_running(&extmoduleTimer)) return; - // disable timer - LL_TIM_DisableCounter(EXTMODULE_TIMER); - switch(EXTMODULE_TIMER_Channel){ case LL_TIM_CHANNEL_CH1: LL_TIM_OC_SetCompareCH1(EXTMODULE_TIMER, ppm_delay * 2); @@ -215,47 +135,37 @@ void extmoduleSendNextFramePpm(void* pulses, uint16_t length, LL_TIM_OC_SetPolarity(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, ll_polarity); // Start DMA request and re-enable timer - extmoduleStartTimerDMARequest(pulses, length); + stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); } #if defined(PXX1) void extmoduleSendNextFramePxx1(const void* pulses, uint16_t length) { - if (LL_DMA_IsEnabledStream(EXTMODULE_TIMER_DMA, - EXTMODULE_TIMER_DMA_STREAM_LL)) + if (!stm32_pulse_stop_if_running(&extmoduleTimer)) return; - // disable timer - LL_TIM_DisableCounter(EXTMODULE_TIMER); - // Start DMA request and re-enable timer - extmoduleStartTimerDMARequest(pulses, length); + 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) { - if (LL_DMA_IsEnabledStream(EXTMODULE_TIMER_DMA, - EXTMODULE_TIMER_DMA_STREAM_LL)) + if (!stm32_pulse_stop_if_running(&extmoduleTimer)) return; // Start DMA request and re-enable timer - extmoduleStartTimerDMARequest(pulses, length); + stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); } #endif void extmoduleSendNextFrameSoftSerial100kbit(const void* pulses, uint16_t length, bool polarity) { - if (LL_DMA_IsEnabledStream(EXTMODULE_TIMER_DMA, - EXTMODULE_TIMER_DMA_STREAM_LL)) + if (!stm32_pulse_stop_if_running(&extmoduleTimer)) return; - - // disable timer - LL_TIM_DisableCounter(EXTMODULE_TIMER); - uint32_t ll_polarity; if (polarity) { ll_polarity = LL_TIM_OCPOLARITY_LOW; @@ -265,7 +175,7 @@ void extmoduleSendNextFrameSoftSerial100kbit(const void* pulses, uint16_t length LL_TIM_OC_SetPolarity(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, ll_polarity); // Start DMA request and re-enable timer - extmoduleStartTimerDMARequest(pulses, length); + stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length); } void extmoduleSendInvertedByte(uint8_t byte) diff --git a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp new file mode 100644 index 000000000..72345c6c0 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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. + */ + +#include "stm32_pulse_driver.h" +#include "definitions.h" + +void stm32_pulse_init(const stm32_pulse_timer_t* tim) +{ + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + pinInit.Pin = tim->GPIO_Pin; + pinInit.Mode = LL_GPIO_MODE_ALTERNATE; + pinInit.Alternate = tim->GPIO_Alternate; + LL_GPIO_Init(tim->GPIOx, &pinInit); + + LL_TIM_InitTypeDef timInit; + LL_TIM_StructInit(&timInit); + + // 0.5uS (2Mhz) + timInit.Prescaler = tim->TIM_Prescaler; + timInit.Autoreload = 65535; + LL_TIM_Init(tim->TIMx, &timInit); +} + +void stm32_pulse_deinit(const stm32_pulse_timer_t* tim) +{ + // De-init DMA & timer + LL_DMA_DeInit(tim->DMAx, tim->DMA_Stream); + LL_TIM_DeInit(tim->TIMx); + + // Reconfigure pin as output + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + + pinInit.Pin = tim->GPIO_Pin; + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + LL_GPIO_Init(tim->GPIOx, &pinInit); +} + +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); + + if (IS_TIM_BREAK_INSTANCE(tim->TIMx)) { + LL_TIM_EnableAllOutputs(tim->TIMx); + } + + LL_TIM_EnableDMAReq_UPDATE(tim->TIMx); + LL_TIM_EnableCounter(tim->TIMx); +} + +// return true if stopped, false otherwise +bool stm32_pulse_stop_if_running(const stm32_pulse_timer_t* tim) +{ + if (LL_DMA_IsEnabledStream(tim->DMAx, tim->DMA_Stream)) + return false; + + // disable timer + LL_TIM_DisableCounter(tim->TIMx); + return true; +} + +void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, + const void* pulses, uint16_t length) +{ + LL_DMA_DeInit(tim->DMAx, tim->DMA_Stream); + + LL_DMA_InitTypeDef dmaInit; + LL_DMA_StructInit(&dmaInit); + + // Direction + dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + + // Source + dmaInit.MemoryOrM2MDstAddress = CONVERT_PTR_UINT(pulses); + dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + + // Destination + dmaInit.PeriphOrM2MSrcAddress = CONVERT_PTR_UINT(&tim->TIMx->ARR); + dmaInit.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + + // Data width + if (IS_TIM_32B_COUNTER_INSTANCE(tim->TIMx)) { + // TODO: try using 16-bit source as well + dmaInit.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + dmaInit.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + } else { + dmaInit.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; + dmaInit.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; + } + + dmaInit.NbData = length; + dmaInit.Channel = tim->DMA_Channel; + dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH; + LL_DMA_Init(tim->DMAx, tim->DMA_Stream, &dmaInit); + + // Enable DMA + LL_DMA_EnableStream(tim->DMAx, tim->DMA_Stream); + + // re-init timer + LL_TIM_GenerateEvent_UPDATE(tim->TIMx); + 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 new file mode 100644 index 000000000..08d7bf956 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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. + */ + +#pragma once + +#include +#include "stm32_hal_ll.h" + +struct stm32_pulse_timer_t { + + GPIO_TypeDef* GPIOx; + uint32_t GPIO_Pin; + uint32_t GPIO_Alternate; + + TIM_TypeDef* TIMx; + uint16_t TIM_Prescaler; + uint32_t TIM_Channel; + + DMA_TypeDef* DMAx; + uint32_t DMA_Stream; + uint32_t DMA_Channel; +}; + +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); + +// return true if stopped, false otherwise +bool stm32_pulse_stop_if_running(const stm32_pulse_timer_t* tim); + +void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, + const void* pulses, uint16_t length); diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 490d4e06a..fe2853b8d 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -265,6 +265,7 @@ set(FIRMWARE_SRC targets/common/arm/stm32/timers_driver.cpp targets/common/arm/stm32/intmodule_serial_driver.cpp targets/common/arm/stm32/extmodule_driver.cpp + targets/common/arm/stm32/stm32_pulse_driver.cpp targets/common/arm/stm32/extmodule_serial_driver.cpp targets/common/arm/stm32/stm32_usart_driver.cpp targets/common/arm/stm32/rotary_encoder_driver.cpp diff --git a/radio/src/targets/nv14/CMakeLists.txt b/radio/src/targets/nv14/CMakeLists.txt index df2af7b6b..56c0d44cd 100644 --- a/radio/src/targets/nv14/CMakeLists.txt +++ b/radio/src/targets/nv14/CMakeLists.txt @@ -157,6 +157,7 @@ set(FIRMWARE_SRC targets/common/arm/stm32/timers_driver.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp targets/common/arm/stm32/extmodule_driver.cpp + targets/common/arm/stm32/stm32_pulse_driver.cpp targets/common/arm/stm32/extmodule_serial_driver.cpp targets/common/arm/stm32/intmodule_serial_driver.cpp targets/common/arm/stm32/stm32_usart_driver.cpp diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index ec404803a..cf34d2cb3 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -442,6 +442,7 @@ if(HARDWARE_EXTERNAL_MODULE) set(FIRMWARE_SRC ${FIRMWARE_SRC} targets/common/arm/stm32/extmodule_driver.cpp + targets/common/arm/stm32/stm32_pulse_driver.cpp targets/common/arm/stm32/extmodule_serial_driver.cpp targets/common/arm/stm32/stm32_usart_driver.cpp ) diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 61b3daa1c..760f014a2 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -1478,15 +1478,10 @@ #define INTMODULE_GPIO_AF_LL LL_GPIO_AF_7 #define INTMODULE_USART_IRQn USART3_IRQn #define INTMODULE_USART_IRQHandler USART3_IRQHandler + // DMA1_Stream3 is already used by SDIO #define INTMODULE_DMA NULL #define INTMODULE_DMA_CHANNEL 0 #define INTMODULE_DMA_STREAM_LL 0 - // #define INTMODULE_TIMER TIM2 - // #define INTMODULE_TIMER_IRQn TIM2_IRQn - // #define INTMODULE_TIMER_IRQHandler TIM2_IRQHandler - // #define INTMODULE_TIMER_CC_IRQn TIM2_CC_IRQn - // #define INTMODULE_TIMER_CC_IRQHandler TIM2_CC_IRQHandler - // #define INTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) #else #define INTMODULE_PULSES #define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2) @@ -1590,8 +1585,6 @@ #define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream1_IRQn #define EXTMODULE_TIMER_DMA_STREAM_IRQHandler DMA2_Stream1_IRQHandler #define EXTMODULE_TIMER_DMA_FLAG_TC DMA_IT_TCIF1 - #define EXTMODULE_TIMER_OUTPUT_ENABLE TIM_CCER_CC1NE - #define EXTMODULE_TIMER_OUTPUT_POLARITY TIM_CCER_CC1NP #define EXTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) #endif