diff --git a/radio/src/pulses/ppm.cpp b/radio/src/pulses/ppm.cpp index 33b2a8820..efea8522d 100644 --- a/radio/src/pulses/ppm.cpp +++ b/radio/src/pulses/ppm.cpp @@ -22,40 +22,51 @@ #include "opentx.h" template -void setupPulsesPPM(PpmPulsesData * ppmPulsesData, uint8_t channelsStart, int8_t channelsCount, int8_t frameLength) +void setupPulsesPPM(PpmPulsesData * ppmPulsesData, uint8_t channelsStart, int8_t channelsCount) { - int16_t PPM_range = g_model.extendedLimits ? (512*LIMIT_EXT_PERCENT/100) * 2 : 512 * 2; // range of 0.7 .. 1.7msec + int16_t PPM_range = g_model.extendedLimits ? + // range of 0.7 .. 1.7msec + (512*LIMIT_EXT_PERCENT/100) * 2 : 512 * 2; // Total frame length = 22.5msec // each pulse is 0.7..1.7ms long with a 0.3ms stop tail // The pulse ISR is 2mhz that's why everything is multiplied by 2 uint8_t firstCh = channelsStart; - uint8_t lastCh = min(MAX_OUTPUT_CHANNELS, firstCh + 8 + channelsCount); + uint8_t lastCh = + min(MAX_OUTPUT_CHANNELS, firstCh + 8 + channelsCount); ppmPulsesData->ptr = ppmPulsesData->pulses; - int32_t rest = 22500u * 2; - rest += int32_t(frameLength) * 1000; - for (uint32_t i=firstCh; iptr++ = v; /* as Pat MacKenzie suggests */ + for (uint32_t i = firstCh; i < lastCh; i++) { + int16_t v = + limit((int16_t)-PPM_range, channelOutputs[i], (int16_t)PPM_range) + + 2 * PPM_CH_CENTER(i); + *ppmPulsesData->ptr++ = v; } - rest = limit(9000, rest, 65535); /* avoids that CCR2 is bigger than ARR which would cause reboot */ - *ppmPulsesData->ptr++ = rest; - *ppmPulsesData->ptr = 0; // it's needed in case PPM is sent without DMA (we stop when we reach this 0) + + // Set the final period to the max + // (a new transfer is issued before it expires) + *ppmPulsesData->ptr++ = 65535; + + // it's needed in case PPM is sent without DMA + // (we stop when we reach this 0) + *ppmPulsesData->ptr = 0; } void setupPulsesPPMTrainer() { - setupPulsesPPM(&trainerPulsesData.ppm, g_model.trainerData.channelsStart, g_model.trainerData.channelsCount, g_model.trainerData.frameLength); + setupPulsesPPM( + &trainerPulsesData.ppm, g_model.trainerData.channelsStart, + g_model.trainerData.channelsCount); } #if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) void setupPulsesPPMInternalModule() { - setupPulsesPPM(&intmodulePulsesData.ppm, g_model.moduleData[INTERNAL_MODULE].channelsStart, g_model.moduleData[INTERNAL_MODULE].channelsCount, g_model.moduleData[INTERNAL_MODULE].ppm.frameLength); + setupPulsesPPM(&intmodulePulsesData.ppm, + g_model.moduleData[INTERNAL_MODULE].channelsStart, + g_model.moduleData[INTERNAL_MODULE].channelsCount); } #endif @@ -63,6 +74,5 @@ void setupPulsesPPMExternalModule() { setupPulsesPPM(&extmodulePulsesData.ppm, g_model.moduleData[EXTERNAL_MODULE].channelsStart, - g_model.moduleData[EXTERNAL_MODULE].channelsCount, - g_model.moduleData[EXTERNAL_MODULE].ppm.frameLength); + g_model.moduleData[EXTERNAL_MODULE].channelsCount); } diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index 38c6e8fcb..801c75098 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -550,7 +550,9 @@ void enablePulsesExternalModule(uint8_t protocol) #if defined(PPM) case PROTOCOL_CHANNELS_PPM: - extmodulePpmStart(); + extmodulePpmStart( + GET_MODULE_PPM_DELAY(EXTERNAL_MODULE), + GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE)); mixerSchedulerSetPeriod(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE)); break; #endif @@ -664,15 +666,14 @@ void extmoduleSendNextFrame() switch (moduleState[EXTERNAL_MODULE].protocol) { - // Note: this is called directly from the EXTMODULE_TIMER_IRQHandler() - // periodically (the only non-synchronous pulse driver - // - // case PROTOCOL_CHANNELS_PPM: - // extmoduleSendNextFramePpm( - // extmodulePulsesData.ppm.pulses, - // extmodulePulsesData.ppm.ptr - extmodulePulsesData.ppm.pulses, - // *(extmodulePulsesData.ppm.ptr - 1)); - // break; + case PROTOCOL_CHANNELS_PPM: + extmoduleSendNextFramePpm( + extmodulePulsesData.ppm.pulses, + extmodulePulsesData.ppm.ptr - extmodulePulsesData.ppm.pulses, + GET_MODULE_PPM_DELAY(EXTERNAL_MODULE), + GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE)); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE)); + break; #if defined(PXX1) case PROTOCOL_CHANNELS_PXX1_PULSES: @@ -702,6 +703,12 @@ void extmoduleSendNextFrame() #if defined(SBUS) || defined(DSM2) || defined(MULTIMODULE) case PROTOCOL_CHANNELS_SBUS: + extmoduleSendNextFrameSoftSerial100kbit( + extmodulePulsesData.dsm2.pulses, + extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses, + GET_SBUS_POLARITY(EXTERNAL_MODULE)); + break; + case PROTOCOL_CHANNELS_DSM2_LP45: case PROTOCOL_CHANNELS_DSM2_DSM2: case PROTOCOL_CHANNELS_DSM2_DSMX: diff --git a/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt b/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt index 8db9dfd6f..f0d52d368 100644 --- a/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt @@ -1,12 +1,17 @@ set(CPU_FAMILY STM32) set(MCU cortex-m4) set(FPU_FLAGS "-mfloat-abi=hard -mfpu=fpv4-sp-d16") -set(STM32LIB_DIR ${THIRDPARTY_DIR}/STM32F4xx_DSP_StdPeriph_Lib_V1.8.0/Libraries) +# StdPeriph library +set(STM32LIB_DIR ${THIRDPARTY_DIR}/STM32F4xx_DSP_StdPeriph_Lib_V1.8.0/Libraries) include_directories(${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/inc) include_directories(${STM32LIB_DIR}/CMSIS/Device/ST/STM32F4xx/Include) include_directories(${STM32LIB_DIR}/CMSIS/Include) +# STM32 HAL/LL library +#set(STM32CUBE_DIR ${THIRDPARTY_DIR}/STM32F4xx_HAL_Driver) +#include_directories(${STM32CUBE_DIR}/Inc) + add_definitions(-DSTM32F4) set(STM32LIB_SRC diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 7ccc99c67..c5c7b09c3 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -164,7 +164,7 @@ endif() set(FIRMWARE_DEPENDENCIES datacopy) -add_definitions(-DPCBHORUS -DSTM32F429_439xx -DSDRAM -DCCMRAM -DCOLORLCD -DHARDWARE_KEYS) +add_definitions(-DPCBHORUS -DSTM32F429_439xx -DSTM32F429xx -DSDRAM -DCCMRAM -DCOLORLCD -DHARDWARE_KEYS) add_definitions(-DEEPROM_VARIANT=0 -DAUDIO -DVOICE -DRTCLOCK) add_definitions(-DGPS_USART_BAUDRATE=${INTERNAL_GPS_BAUDRATE}) add_definitions(-DPWR_BUTTON_${PWR_BUTTON}) diff --git a/radio/src/targets/horus/extmodule_driver.cpp b/radio/src/targets/horus/extmodule_driver.cpp index 2ac865adf..34ce1d059 100644 --- a/radio/src/targets/horus/extmodule_driver.cpp +++ b/radio/src/targets/horus/extmodule_driver.cpp @@ -19,7 +19,9 @@ * GNU General Public License for more details. */ -#include "opentx.h" +#include "CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h" +#include "STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_gpio.h" +#include "hal.h" #include "extmodule_driver.h" #include "timers_driver.h" @@ -27,6 +29,30 @@ #include "pulses/crossfire.h" #endif +// PPM delay in uS +#define DEFAULT_PPM_DELAY 300 +static uint32_t (*getPPMDelayCb)() = nullptr; + +static inline uint32_t getPPMDelay() +{ + if (getPPMDelayCb) + return getPPMDelayCb(); + + return DEFAULT_PPM_DELAY; +} + +// PPM polarity +#define DEFAULT_PPM_POLARITY (true) +static bool (*getPPMPolarityCb)() = nullptr; + +static inline bool getPPMPolarity() +{ + if (getPPMPolarityCb) + return getPPMPolarityCb(); + + return DEFAULT_PPM_POLARITY; +} + void extmoduleStop() { EXTERNAL_MODULE_OFF(); @@ -47,7 +73,7 @@ void extmoduleStop() GPIO_Init(EXTMODULE_TX_GPIO, &GPIO_InitStructure); } -void extmodulePpmStart() +void extmodulePpmStart(uint16_t ppm_delay, bool polarity) { EXTERNAL_MODULE_ON(); @@ -68,25 +94,21 @@ void extmodulePpmStart() // CCR1 register defines duration of pulse length and is constant // AAR register defines duration of each pulse, it is // updated after every pulse in Update interrupt handler. - // CCR2 register defines duration of no pulses (time between two pulse trains) - // it is calculated every round to have PPM period constant. - // CC2 interrupt is then used to setup new PPM values for the - // next PPM pulses train. EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop timer EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz) #if defined(PCBX10) || PCBREV >= 13 - EXTMODULE_TIMER->CCR3 = GET_MODULE_PPM_DELAY(EXTERNAL_MODULE)*2; - EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | (GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0); + EXTMODULE_TIMER->CCR3 = ppm_delay * 2; + EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | (polarity ? TIM_CCER_CC3P : 0); EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0; // Force O/P high EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; EXTMODULE_TIMER->EGR = 1; // Reloads register values now EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2; // PWM mode 1 #else - EXTMODULE_TIMER->CCR1 = GET_MODULE_PPM_DELAY(EXTERNAL_MODULE)*2; + EXTMODULE_TIMER->CCR1 = ppm_delay * 2; EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | - (GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE) ? + (getPPMPolarity() ? #if defined(PCBNV14) 0 : TIM_CCER_CC1P #else @@ -98,16 +120,13 @@ void extmodulePpmStart() EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC2PE; // PWM mode 1 #endif - EXTMODULE_TIMER->ARR = 45000; - EXTMODULE_TIMER->CCR2 = 40000; // The first frame will be sent in 20ms + EXTMODULE_TIMER->ARR = 65535; // start with max period EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - EXTMODULE_TIMER->DIER |= TIM_DIER_UDE | TIM_DIER_CC2IE; // Enable this interrupt + EXTMODULE_TIMER->DIER |= TIM_DIER_UDE /*| TIM_DIER_CC2IE*/; // Enable this interrupt EXTMODULE_TIMER->CR1 = TIM_CR1_CEN; // Start timer NVIC_EnableIRQ(EXTMODULE_TIMER_DMA_STREAM_IRQn); NVIC_SetPriority(EXTMODULE_TIMER_DMA_STREAM_IRQn, 7); - NVIC_EnableIRQ(EXTMODULE_TIMER_CC_IRQn); - NVIC_SetPriority(EXTMODULE_TIMER_CC_IRQn, 7); } #if defined(PXX1) @@ -157,8 +176,6 @@ void extmodulePxx1PulsesStart() NVIC_EnableIRQ(EXTMODULE_TIMER_DMA_STREAM_IRQn); NVIC_SetPriority(EXTMODULE_TIMER_DMA_STREAM_IRQn, 7); - NVIC_EnableIRQ(EXTMODULE_TIMER_CC_IRQn); - NVIC_SetPriority(EXTMODULE_TIMER_CC_IRQn, 7); } #endif @@ -209,30 +226,32 @@ void extmoduleSerialStart() NVIC_SetPriority(EXTMODULE_TIMER_DMA_STREAM_IRQn, 7); } -static void extmoduleSendNextFramePpm(void* pulses, uint16_t length, - uint16_t trailing_pulse) +void extmoduleSendNextFramePpm(void* pulses, uint16_t length, + uint16_t ppm_delay, bool polarity) { + if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) return; + + // disable timer + EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; + #if defined(PCBX10) || PCBREV >= 13 // Using timer channel 3 - EXTMODULE_TIMER->CCR3 = GET_MODULE_PPM_DELAY(EXTERNAL_MODULE) * 2; + EXTMODULE_TIMER->CCR3 = ppm_delay * 2; EXTMODULE_TIMER->CCER = - TIM_CCER_CC3E | - (GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0); + TIM_CCER_CC3E | (polarity ? TIM_CCER_CC3P : 0); #else // Using timer channel 1 - EXTMODULE_TIMER->CCR1 = GET_MODULE_PPM_DELAY(EXTERNAL_MODULE) * 2; - EXTMODULE_TIMER->CCER = - TIM_CCER_CC1E | (GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE) ? + EXTMODULE_TIMER->CCR1 = ppm_delay * 2; + EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | (polarity ? #if defined(PCBNV14) - 0 - : TIM_CCER_CC1P + 0 + : TIM_CCER_CC1P #else - TIM_CCER_CC1P - : 0 + TIM_CCER_CC1P + : 0 #endif - ); + ); #endif - EXTMODULE_TIMER->CCR2 = trailing_pulse - 4000; // 2mS in advance EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | @@ -241,6 +260,10 @@ static void extmoduleSendNextFramePpm(void* pulses, uint16_t length, EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(pulses); EXTMODULE_TIMER_DMA_STREAM->NDTR = length; EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA + + // re-init timer + EXTMODULE_TIMER->EGR = 1; + EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; } #if defined(PXX1) @@ -284,22 +307,23 @@ void extmoduleSendNextFrameAFHDS3(const void* dataPtr, uint16_t dataSize) } #endif -void extmoduleSendNextFrameSoftSerial100kbit(const void* pulses, uint16_t length) +void extmoduleSendNextFrameSoftSerial100kbit(const void* pulses, uint16_t length, + bool polarity) { if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) return; - if (PROTOCOL_CHANNELS_SBUS == moduleState[EXTERNAL_MODULE].protocol) { + //if (PROTOCOL_CHANNELS_SBUS == moduleState[EXTERNAL_MODULE].protocol) { // reverse polarity for Sbus if needed EXTMODULE_TIMER->CCER = #if defined(PCBX10) || PCBREV >= 13 - TIM_CCER_CC3E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0) + TIM_CCER_CC3E | (polarity ? TIM_CCER_CC3P : 0) #elif defined(PCBNV14) - TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? 0 : TIM_CCER_CC1P) + TIM_CCER_CC1E | (polarity ? 0 : TIM_CCER_CC1P) #else - TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0) + TIM_CCER_CC1E | (polarity ? TIM_CCER_CC1P : 0) #endif ; // - } + //} // disable timer EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; @@ -358,22 +382,5 @@ extern "C" void EXTMODULE_TIMER_DMA_IRQHandler() DMA_ClearITPendingBit(EXTMODULE_TIMER_DMA_STREAM, EXTMODULE_TIMER_DMA_FLAG_TC); - switch (moduleState[EXTERNAL_MODULE].protocol) { - case PROTOCOL_CHANNELS_PPM: - EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt - break; - } -} -extern "C" void EXTMODULE_TIMER_IRQHandler() -{ - EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt - EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; - - setupPulsesExternalModule(); - extmoduleSendNextFramePpm( - extmodulePulsesData.ppm.pulses, - extmodulePulsesData.ppm.ptr - extmodulePulsesData.ppm.pulses, - *(extmodulePulsesData.ppm.ptr - 1)); } diff --git a/radio/src/targets/horus/extmodule_driver.h b/radio/src/targets/horus/extmodule_driver.h index 0420d19c9..f7324dacb 100644 --- a/radio/src/targets/horus/extmodule_driver.h +++ b/radio/src/targets/horus/extmodule_driver.h @@ -24,7 +24,7 @@ #include void extmoduleStop(); -void extmodulePpmStart(); +void extmodulePpmStart(uint16_t ppm_delay, bool polarity); #if defined(PXX1) void extmodulePxx1PulsesStart(); @@ -38,7 +38,12 @@ void extmoduleSerialStart(); void extmoduleSendNextFrameAFHDS3(const void* dataPtr, uint16_t dataSize); #endif -void extmoduleSendNextFrameSoftSerial100kbit(const void* pulses, uint16_t length); +void extmoduleSendNextFramePpm(void* pulses, uint16_t length, + uint16_t ppm_delay, bool polarity); + +void extmoduleSendNextFrameSoftSerial100kbit(const void* pulses, + uint16_t length, + bool polarity = true); // Bitbang serial void extmoduleSendInvertedByte(uint8_t byte); diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp index 4efb230d4..95bb4ef69 100644 --- a/radio/src/tasks.cpp +++ b/radio/src/tasks.cpp @@ -66,6 +66,7 @@ bool isForcePowerOffRequested() return false; } +// TODO: remove this!!! bool isModuleSynchronous(uint8_t moduleIdx) { switch(moduleState[moduleIdx].protocol) { @@ -83,7 +84,7 @@ bool isModuleSynchronous(uint8_t moduleIdx) #if defined(INTMODULE_USART) || defined(EXTMODULE_USART) case PROTOCOL_CHANNELS_PXX1_SERIAL: #endif - // case PROTOCOL_CHANNELS_PPM: + case PROTOCOL_CHANNELS_PPM: case PROTOCOL_CHANNELS_PXX1_PULSES: #if defined(DSM2) case PROTOCOL_CHANNELS_SBUS: