From ffefd0f6dd39c9a090c9aba8f95cfc05aceb85ca Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sat, 20 Nov 2021 07:46:01 +0100 Subject: [PATCH] External serial driver moved to a separate driver --- radio/src/hal/serial_driver.h | 2 +- radio/src/io/multi_firmware_update.cpp | 2 + radio/src/pulses/crossfire.cpp | 142 +++-- radio/src/pulses/crossfire.h | 3 +- radio/src/pulses/pulses.cpp | 578 ++++++++++-------- radio/src/pulses/pulses.h | 1 + radio/src/pulses/pxx2.cpp | 166 ++--- radio/src/pulses/pxx2.h | 6 +- .../arm/stm32/extmodule_serial_driver.cpp | 194 ++++++ .../arm/stm32/extmodule_serial_driver.h | 36 ++ .../arm/stm32/intmodule_serial_driver.cpp | 19 +- .../arm/stm32/intmodule_serial_driver.h | 2 +- radio/src/targets/horus/CMakeLists.txt | 1 + radio/src/targets/horus/board.h | 6 - radio/src/targets/horus/extmodule_driver.cpp | 300 +++------ radio/src/targets/horus/extmodule_driver.h | 44 ++ radio/src/targets/horus/hal.h | 1 + 17 files changed, 885 insertions(+), 618 deletions(-) create mode 100644 radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp create mode 100644 radio/src/targets/common/arm/stm32/extmodule_serial_driver.h create mode 100644 radio/src/targets/horus/extmodule_driver.h diff --git a/radio/src/hal/serial_driver.h b/radio/src/hal/serial_driver.h index 6172689ac..98119f6b6 100644 --- a/radio/src/hal/serial_driver.h +++ b/radio/src/hal/serial_driver.h @@ -51,7 +51,7 @@ struct etx_serial_init { void (*on_error)(); // = nullptr; }; -struct etx_hal_serial_driver_t { +struct etx_serial_driver_t { // Init module communication void (*init)(const etx_serial_init* params); diff --git a/radio/src/io/multi_firmware_update.cpp b/radio/src/io/multi_firmware_update.cpp index ed9071977..e5d50abdb 100644 --- a/radio/src/io/multi_firmware_update.cpp +++ b/radio/src/io/multi_firmware_update.cpp @@ -41,6 +41,8 @@ #include "intmodule_serial_driver.h" #endif +#include "extmodule_driver.h" + #define UPDATE_MULTI_EXT_BIN ".bin" class MultiFirmwareUpdateDriver diff --git a/radio/src/pulses/crossfire.cpp b/radio/src/pulses/crossfire.cpp index bbcec7e1e..9f329cf2f 100644 --- a/radio/src/pulses/crossfire.cpp +++ b/radio/src/pulses/crossfire.cpp @@ -21,6 +21,7 @@ #include "opentx.h" #include "mixer_scheduler.h" +#include "hal/module_driver.h" #if defined(INTMODULE_USART) #include "intmodule_serial_driver.h" @@ -99,14 +100,13 @@ static void setupPulsesCrossfire(uint8_t idx, CrossfirePulsesData* p_data, } } -static void setupPulsesCrossfire(uint8_t idx, int16_t* channels, uint8_t nChannels) +static void crossfireSetupMixerScheduler(uint8_t module) { - if (idx == INTERNAL_MODULE) { - auto* p_data = &intmodulePulsesData.crossfire; - setupPulsesCrossfire(idx, p_data, 0, channels, nChannels); - } else if (telemetryProtocol == PROTOCOL_TELEMETRY_CROSSFIRE) { - auto* p_data = &extmodulePulsesData.crossfire; - setupPulsesCrossfire(idx, p_data, TELEMETRY_ENDPOINT_SPORT, channels, nChannels); + ModuleSyncStatus& status = getModuleSyncStatus(module); + if (status.isValid()) { + mixerSchedulerSetPeriod(module, status.getAdjustedRefreshRate()); + } else { + mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD); } } @@ -137,83 +137,91 @@ static const etx_serial_init intmoduleCrossfireInitParams = { .on_receive = intmoduleCRSF_rx, .on_error = nullptr, }; -#endif -static void* crossfireInit(uint8_t module) +static void* crossfireInitInternal(uint8_t module) { - if (module == INTERNAL_MODULE) { -#if defined(INTERNAL_MODULE_CRSF) - // serial port setup - etx_serial_init params(intmoduleCrossfireInitParams); - params.baudrate = CROSSFIRE_BAUDRATE; + (void)module; - // wakeup mixer when rx buffer is quarter full (16 bytes) - params.on_receive = intmoduleCRSF_rx; + // serial port setup + etx_serial_init params(intmoduleCrossfireInitParams); + params.baudrate = CROSSFIRE_BAUDRATE; - intmoduleFifo.clear(); - IntmoduleSerialDriver.init(¶ms); -#endif - } else { - // TODO: setup S.PORT - // - for now, the init is still done via telemetryWakeup().... - telemetryInit(PROTOCOL_TELEMETRY_CROSSFIRE); - } + // wakeup mixer when rx buffer is quarter full (16 bytes) + params.on_receive = intmoduleCRSF_rx; - // mixer setup - mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD); - return (void*)(ulong)module; + intmoduleFifo.clear(); + IntmoduleSerialDriver.init(¶ms); + + return nullptr; } -static void crossfireDeInit(void* context) +static void crossfireDeInitInternal(void* context) { - ulong module = (ulong)context; + (void)context; - if (module == INTERNAL_MODULE) { -#if defined(INTERNAL_MODULE_CRSF) - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); - intmoduleStop(); - intmoduleFifo.clear(); -#endif - } else { - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - } + mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); + intmoduleStop(); + intmoduleFifo.clear(); } -static void crossfireSetupPulses(void* context, int16_t* channels, uint8_t nChannels) +static void crossfireSetupPulsesInternal(void* context, int16_t* channels, uint8_t nChannels) { - ulong module = (ulong)context; - - ModuleSyncStatus& status = getModuleSyncStatus(module); - if (status.isValid()) { - mixerSchedulerSetPeriod(module, status.getAdjustedRefreshRate()); - } else { - mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD); - } - - setupPulsesCrossfire(module, channels, nChannels); + auto* p_data = &intmodulePulsesData.crossfire; + crossfireSetupMixerScheduler(INTERNAL_MODULE); + setupPulsesCrossfire(INTERNAL_MODULE, p_data, 0, channels, nChannels); } -static void crossfireSendPulses(void* context) +static void crossfireSendPulsesInternal(void* context) { - ulong module = (ulong)context; + (void)context; - if (module == INTERNAL_MODULE) { -#if defined(INTERNAL_MODULE_CRSF) - IntmoduleSerialDriver.sendBuffer(intmodulePulsesData.crossfire.pulses, - intmodulePulsesData.crossfire.length); -#endif - } else { - sportSendBuffer(extmodulePulsesData.crossfire.pulses, - extmodulePulsesData.crossfire.length); - } + IntmoduleSerialDriver.sendBuffer(intmodulePulsesData.crossfire.pulses, + intmodulePulsesData.crossfire.length); } -#include "hal/module_driver.h" - -etx_module_driver_t CrossfireModuleDriver = { +etx_module_driver_t CrossfireInternalDriver = { .protocol = PROTOCOL_CHANNELS_CROSSFIRE, - .init = crossfireInit, - .deinit = crossfireDeInit, - .setupPulses = crossfireSetupPulses, - .sendPulses = crossfireSendPulses + .init = crossfireInitInternal, + .deinit = crossfireDeInitInternal, + .setupPulses = crossfireSetupPulsesInternal, + .sendPulses = crossfireSendPulsesInternal, +}; +#endif + +static void* crossfireInitExternal(uint8_t module) +{ + telemetryInit(PROTOCOL_TELEMETRY_CROSSFIRE); + mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD); + return nullptr; +} + +static void crossfireDeInitExternal(void* context) +{ + (void)context; + telemetryProtocol = 0xFF; + mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); +} + +static void crossfireSetupPulsesExternal(void* context, int16_t* channels, uint8_t nChannels) +{ + auto* p_data = &extmodulePulsesData.crossfire; + crossfireSetupMixerScheduler(EXTERNAL_MODULE); + setupPulsesCrossfire(EXTERNAL_MODULE, p_data, TELEMETRY_ENDPOINT_SPORT, + channels, nChannels); +} + +static void crossfireSendPulsesExternal(void* context) +{ + (void)context; + + sportSendBuffer(extmodulePulsesData.crossfire.pulses, + extmodulePulsesData.crossfire.length); +} + +etx_module_driver_t CrossfireExternalDriver = { + .protocol = PROTOCOL_CHANNELS_CROSSFIRE, + .init = crossfireInitExternal, + .deinit = crossfireDeInitExternal, + .setupPulses = crossfireSetupPulsesExternal, + .sendPulses = crossfireSendPulsesExternal }; diff --git a/radio/src/pulses/crossfire.h b/radio/src/pulses/crossfire.h index 08d5b16f1..511911c64 100644 --- a/radio/src/pulses/crossfire.h +++ b/radio/src/pulses/crossfire.h @@ -23,4 +23,5 @@ #include "hal/module_driver.h" -extern etx_module_driver_t CrossfireModuleDriver; +extern etx_module_driver_t CrossfireInternalDriver; +extern etx_module_driver_t CrossfireExternalDriver; diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index ada5476fb..00d399717 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -34,6 +34,8 @@ #include "intmodule_pulses_driver.h" #endif +#include "extmodule_driver.h" + #if defined(CROSSFIRE) #include "pulses/crossfire.h" #endif @@ -277,10 +279,255 @@ uint8_t getRequiredProtocol(uint8_t module) return protocol; } +#if defined(HARDWARE_INTERNAL_MODULE) +static void* internalModuleContext = nullptr; +static const etx_module_driver_t* internalModuleDriver = nullptr; + +static void enablePulsesInternalModule(uint8_t protocol) +{ + // start new protocol hardware here + if (internalModuleDriver) { + internalModuleDriver->deinit(internalModuleContext); + internalModuleContext = nullptr; + internalModuleDriver = nullptr; + } else { + intmoduleStop(); + } + + switch (protocol) { +#if defined(PXX1) && !defined(INTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_PULSES: + intmodulePxx1PulsesStart(); +#if defined(INTMODULE_HEARTBEAT) + init_intmodule_heartbeat(); +#endif + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); + break; +#endif + +#if defined(PXX1) && defined(INTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_SERIAL: + intmodulePxx1SerialStart(); +#if defined(INTMODULE_HEARTBEAT) + init_intmodule_heartbeat(); +#endif + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); + break; +#endif + +#if defined(PXX2) + case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: + internalModuleContext = Pxx2InternalDriver.init(INTERNAL_MODULE); + internalModuleDriver = &Pxx2InternalDriver; + break; +#endif + +#if defined(INTERNAL_MODULE_MULTI) + case PROTOCOL_CHANNELS_MULTIMODULE: + // TODO: use module interface + // serial port setup + intmodulePulsesData.multi.initFrame(); + intmoduleFifo.clear(); + IntmoduleSerialDriver.init(&multiSerialInitParams); + + // mixer setup + mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD); + + // reset status + getMultiModuleStatus(INTERNAL_MODULE).failsafeChecked = false; + getMultiModuleStatus(INTERNAL_MODULE).flags = 0; + +#if defined(MULTI_PROTOLIST) + TRACE("enablePulsesInternalModule(): trigger scan"); + MultiRfProtocols::instance(INTERNAL_MODULE)->triggerScan(); + TRACE("counter = %d", moduleState[INTERNAL_MODULE].counter); +#endif + break; +#endif + +#if defined(INTERNAL_MODULE_CRSF) + case PROTOCOL_CHANNELS_CROSSFIRE: + internalModuleContext = CrossfireInternalDriver.init(INTERNAL_MODULE); + internalModuleDriver = &CrossfireInternalDriver; + break; +#endif + +#if defined(INTERNAL_MODULE_PPM) + case PROTOCOL_CHANNELS_PPM: + intmodulePpmStart(); + mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE)); + break; +#endif + +#if defined(AFHDS2) + case PROTOCOL_CHANNELS_AFHDS2A: + // serial port setup + resetPulsesAFHDS2(); + intmoduleFifo.clear(); + IntmoduleSerialDriver.init(&afhds2SerialInitParams) + + // mixer setup + mixerSchedulerSetPeriod(INTERNAL_MODULE, AFHDS2_PERIOD); + break; +#endif + + default: + // internal module stopped, use default mixer period + mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); + break; + } +} + +bool setupPulsesInternalModule(uint8_t protocol) +{ + uint8_t channelStart = g_model.moduleData[INTERNAL_MODULE].channelsStart; + int16_t* channels = &channelOutputs[channelStart]; + uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart + + if (internalModuleDriver) { + internalModuleDriver->setupPulses(internalModuleContext, + channels, nChannels); + return true; + } + + switch (protocol) { +#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_PULSES: + intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE); + return true; +#endif + +#if defined(PXX1) && defined(INTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_SERIAL: + intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE); + return true; +#endif + +#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) + case PROTOCOL_CHANNELS_PPM: + setupPulsesPPMInternalModule(); + return true; +#endif + +#if defined(INTERNAL_MODULE_MULTI) + case PROTOCOL_CHANNELS_MULTIMODULE: + setupPulsesMultiInternalModule(); + mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD); + return true; +#endif + +#if defined(AFHDS2) + case PROTOCOL_CHANNELS_AFHDS2A: + { + ModuleSyncStatus& status = getModuleSyncStatus(INTERNAL_MODULE); + mixerSchedulerSetPeriod( + INTERNAL_MODULE, + status.isValid() ? status.getAdjustedRefreshRate() : AFHDS2_PERIOD); + status.invalidate(); + setupPulsesAFHDS2(); + return true; + } +#endif + + default: + return false; + } +} + +void stopPulsesInternalModule() +{ + if (moduleState[INTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) { + if (internalModuleDriver) { + internalModuleDriver->deinit(internalModuleContext); + internalModuleDriver = nullptr; + internalModuleContext = nullptr; + } else { + mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); + intmoduleStop(); + } + moduleState[INTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE; + } +} + +void intmoduleSendNextFrame() +{ + if (internalModuleDriver) { + internalModuleDriver->sendPulses(internalModuleContext); + return; + } + + switch (moduleState[INTERNAL_MODULE].protocol) { + +#if defined(INTERNAL_MODULE_PPM) + case PROTOCOL_CHANNELS_PPM: + intmoduleSendNextFramePPM( + intmodulePulsesData.ppm.pulses, + intmodulePulsesData.ppm.ptr - intmodulePulsesData.ppm.pulses); + break; +#endif + +#if defined(PXX1) +#if defined(INTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_SERIAL: + IntmoduleSerialDriver.sendBuffer(intmodulePulsesData.pxx_uart.getData(), + intmodulePulsesData.pxx_uart.getSize()); + break; +#else + case PROTOCOL_CHANNELS_PXX1_PULSES: + intmoduleSendNextFramePxx1(intmodulePulsesData.pxx.getData(), + intmodulePulsesData.pxx.getSize()); + break; +#endif +#endif + +#if defined(INTERNAL_MODULE_MULTI) + case PROTOCOL_CHANNELS_MULTIMODULE: + IntmoduleSerialDriver.sendBuffer(intmodulePulsesData.multi.getData(), + intmodulePulsesData.multi.getSize()); + break; +#endif + +#if defined(AFHDS2) + case PROTOCOL_CHANNELS_AFHDS2A: { + uint8_t* data = (uint8_t*)intmodulePulsesData.flysky.pulses; + uint16_t size = intmodulePulsesData.flysky.ptr - data; + intmoduleSendBuffer(data, size); + } break; +#endif + } +} + +bool setupPulsesInternalModule() +{ + uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE); + + heartbeat |= (HEART_TIMER_PULSES << INTERNAL_MODULE); + + if (moduleState[INTERNAL_MODULE].protocol != protocol) { + enablePulsesInternalModule(protocol); + moduleState[INTERNAL_MODULE].protocol = protocol; + return false; + } + else { + return setupPulsesInternalModule(protocol); + } +} +#endif + #if defined(HARDWARE_EXTERNAL_MODULE) +static void* externalModuleContext = nullptr; +static const etx_module_driver_t* externalModuleDriver = nullptr; + void enablePulsesExternalModule(uint8_t protocol) { // start new protocol hardware here + if (externalModuleDriver) { + externalModuleDriver->deinit(externalModuleContext); + externalModuleDriver = nullptr; + externalModuleContext = nullptr; + } else { + extmoduleStop(); + } switch (protocol) { #if defined(PXX1) @@ -301,16 +548,20 @@ void enablePulsesExternalModule(uint8_t protocol) case PROTOCOL_CHANNELS_DSM2_LP45: case PROTOCOL_CHANNELS_DSM2_DSM2: case PROTOCOL_CHANNELS_DSM2_DSMX: +#if defined(PCBSKY9X) + extmoduleSerialStart(DSM2_BAUDRATE, DSM2_PERIOD * 2000, false); +#else extmoduleSerialStart(); mixerSchedulerSetPeriod(EXTERNAL_MODULE, DSM2_PERIOD); +#endif break; #endif #if defined(CROSSFIRE) case PROTOCOL_CHANNELS_CROSSFIRE: EXTERNAL_MODULE_ON(); - if (CrossfireModuleDriver.init) - CrossfireModuleDriver.init(EXTERNAL_MODULE); + externalModuleContext = CrossfireExternalDriver.init(EXTERNAL_MODULE); + externalModuleDriver = &CrossfireExternalDriver; break; #endif @@ -323,18 +574,24 @@ void enablePulsesExternalModule(uint8_t protocol) #if defined(PXX2) && defined(EXTMODULE_USART) case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: - Pxx2ModuleDriver.init(EXTERNAL_MODULE); + externalModuleContext = Pxx2ExternalDriver.init(EXTERNAL_MODULE); + externalModuleDriver = &Pxx2ExternalDriver; break; case PROTOCOL_CHANNELS_PXX2_LOWSPEED: - Pxx2LowSpeedModuleDriver.init(EXTERNAL_MODULE); + externalModuleContext = Pxx2LowSpeedExternalDriver.init(EXTERNAL_MODULE); + externalModuleDriver = &Pxx2LowSpeedExternalDriver; break; #endif #if defined(MULTIMODULE) case PROTOCOL_CHANNELS_MULTIMODULE: +#if defined(PCBSKY9X) + extmoduleSerialStart(MULTIMODULE_BAUDRATE, MULTIMODULE_PERIOD * 2000, true); +#else extmoduleSerialStart(); mixerSchedulerSetPeriod(EXTERNAL_MODULE, MULTIMODULE_PERIOD); +#endif getMultiModuleStatus(EXTERNAL_MODULE).failsafeChecked = false; getMultiModuleStatus(EXTERNAL_MODULE).flags = 0; #if defined(MULTI_PROTOLIST) @@ -345,8 +602,12 @@ void enablePulsesExternalModule(uint8_t protocol) #if defined(SBUS) case PROTOCOL_CHANNELS_SBUS: +#if defined(PCBSKY9X) + extmoduleSerialStart(SBUS_BAUDRATE, SBUS_PERIOD_HALF_US, false); +#else extmoduleSerialStart(); mixerSchedulerSetPeriod(EXTERNAL_MODULE, SBUS_PERIOD); +#endif break; #endif @@ -374,10 +635,16 @@ void enablePulsesExternalModule(uint8_t protocol) bool setupPulsesExternalModule(uint8_t protocol) { - int16_t* channels = - &channelOutputs[g_model.moduleData[EXTERNAL_MODULE].channelsStart]; + uint8_t channelStart = g_model.moduleData[EXTERNAL_MODULE].channelsStart; + int16_t* channels = &channelOutputs[channelStart]; uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart + if (externalModuleDriver) { + externalModuleDriver->setupPulses(externalModuleContext, + channels, nChannels); + return true; + } + switch (protocol) { #if defined(PXX1) @@ -392,13 +659,6 @@ bool setupPulsesExternalModule(uint8_t protocol) return true; #endif -#if defined(PXX2) - case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: - case PROTOCOL_CHANNELS_PXX2_LOWSPEED: - Pxx2ModuleDriver.setupPulses((void*)EXTERNAL_MODULE, channels, nChannels); - return true; -#endif - #if defined(SBUS) case PROTOCOL_CHANNELS_SBUS: setupPulsesSbus(); @@ -415,15 +675,6 @@ bool setupPulsesExternalModule(uint8_t protocol) return true; #endif -#if defined(CROSSFIRE) - case PROTOCOL_CHANNELS_CROSSFIRE: - if (CrossfireModuleDriver.setupPulses) { - CrossfireModuleDriver.setupPulses((void*)EXTERNAL_MODULE, channels, - nChannels); - } - return true; -#endif - #if defined(GHOST) case PROTOCOL_CHANNELS_GHOST: { @@ -466,255 +717,85 @@ bool setupPulsesExternalModule(uint8_t protocol) return false; } } -#endif -#if defined(HARDWARE_INTERNAL_MODULE) - -static void enablePulsesInternalModule(uint8_t protocol) +void extmoduleSendNextFrame() { - // start new protocol hardware here - - switch (protocol) { -#if defined(PXX1) && !defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_PULSES: - intmodulePxx1PulsesStart(); -#if defined(INTMODULE_HEARTBEAT) - init_intmodule_heartbeat(); -#endif - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); - break; -#endif - -#if defined(PXX1) && defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_SERIAL: - intmodulePxx1SerialStart(); -#if defined(INTMODULE_HEARTBEAT) - init_intmodule_heartbeat(); -#endif - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); - break; -#endif - -#if defined(PXX2) - case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: - Pxx2ModuleDriver.init(INTERNAL_MODULE); - break; -#endif - -#if defined(INTERNAL_MODULE_MULTI) - case PROTOCOL_CHANNELS_MULTIMODULE: - // serial port setup - intmodulePulsesData.multi.initFrame(); - intmoduleFifo.clear(); - IntmoduleSerialDriver.init(&multiSerialInitParams); - - // mixer setup - mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD); - - // reset status - getMultiModuleStatus(INTERNAL_MODULE).failsafeChecked = false; - getMultiModuleStatus(INTERNAL_MODULE).flags = 0; - -#if defined(MULTI_PROTOLIST) - TRACE("enablePulsesInternalModule(): trigger scan"); - MultiRfProtocols::instance(INTERNAL_MODULE)->triggerScan(); - TRACE("counter = %d", moduleState[INTERNAL_MODULE].counter); -#endif - break; -#endif - -#if defined(INTERNAL_MODULE_CRSF) - case PROTOCOL_CHANNELS_CROSSFIRE: - if (CrossfireModuleDriver.init) { - // TODO: save context - CrossfireModuleDriver.init(INTERNAL_MODULE); - } - break; -#endif - -#if defined(INTERNAL_MODULE_PPM) - case PROTOCOL_CHANNELS_PPM: - intmodulePpmStart(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE)); - break; -#endif - -#if defined(AFHDS2) - case PROTOCOL_CHANNELS_AFHDS2A: - // serial port setup - resetPulsesAFHDS2(); - intmoduleFifo.clear(); - IntmoduleSerialDriver.init(&afhds2SerialInitParams) - - // mixer setup - mixerSchedulerSetPeriod(INTERNAL_MODULE, AFHDS2_PERIOD); - break; -#endif - - default: - // internal module stopped, use default mixer period - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); - break; + if (externalModuleDriver) { + externalModuleDriver->sendPulses(externalModuleContext); + return; } -} -bool setupPulsesInternalModule(uint8_t protocol) -{ - int16_t* channels = - &channelOutputs[g_model.moduleData[INTERNAL_MODULE].channelsStart]; - uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart + switch (moduleState[EXTERNAL_MODULE].protocol) { - switch (protocol) { -#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_PULSES: - intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE); - return true; -#endif - -#if defined(PXX1) && defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_SERIAL: - intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE); - return true; -#endif - -#if defined(PXX2) - case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: - Pxx2ModuleDriver.setupPulses((void*)INTERNAL_MODULE, channels, nChannels); - return true; -#endif - -#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) - case PROTOCOL_CHANNELS_PPM: - setupPulsesPPMInternalModule(); - return true; -#endif - -#if defined(INTERNAL_MODULE_CRSF) - case PROTOCOL_CHANNELS_CROSSFIRE: - if (CrossfireModuleDriver.setupPulses) { - int16_t* channels = - &channelOutputs[g_model.moduleData[INTERNAL_MODULE].channelsStart]; - uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart - CrossfireModuleDriver.setupPulses((void*)INTERNAL_MODULE, channels, - nChannels); - } - return true; -#endif - -#if defined(INTERNAL_MODULE_MULTI) - case PROTOCOL_CHANNELS_MULTIMODULE: - setupPulsesMultiInternalModule(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD); - return true; -#endif - -#if defined(AFHDS2) - case PROTOCOL_CHANNELS_AFHDS2A: - { - ModuleSyncStatus& status = getModuleSyncStatus(INTERNAL_MODULE); - mixerSchedulerSetPeriod( - INTERNAL_MODULE, - status.isValid() ? status.getAdjustedRefreshRate() : AFHDS2_PERIOD); - status.invalidate(); - setupPulsesAFHDS2(); - return true; - } -#endif - - default: - return false; - } -} - -void stopPulsesInternalModule() -{ - if (moduleState[INTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) { - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); - intmoduleStop(); - moduleState[INTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE; - } -} - -void intmoduleSendNextFrame() -{ - switch (moduleState[INTERNAL_MODULE].protocol) { -#if defined(PXX2) - case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: - Pxx2ModuleDriver.sendPulses((void*)INTERNAL_MODULE); - break; -#endif - -#if defined(INTERNAL_MODULE_PPM) - case PROTOCOL_CHANNELS_PPM: - intmoduleSendNextFramePPM( - intmodulePulsesData.ppm.pulses, - intmodulePulsesData.ppm.ptr - intmodulePulsesData.ppm.pulses); - break; -#endif + // 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; #if defined(PXX1) -#if defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_SERIAL: - IntmoduleSerialDriver.sendBuffer(intmodulePulsesData.pxx_uart.getData(), - intmodulePulsesData.pxx_uart.getSize()); - break; -#else case PROTOCOL_CHANNELS_PXX1_PULSES: - intmoduleSendNextFramePxx1(intmodulePulsesData.pxx.getData(), - intmodulePulsesData.pxx.getSize()); + extmoduleSendNextFramePxx1(extmodulePulsesData.pxx.getData(), + extmodulePulsesData.pxx.getSize()); break; #endif + +#if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) + case PROTOCOL_CHANNELS_PXX1_SERIAL: + extmoduleSendBuffer(extmodulePulsesData.pxx_uart.getData(), + extmodulePulsesData.pxx_uart.getSize()); + break; #endif -#if defined(INTERNAL_MODULE_MULTI) +#if defined(AFHDS3) + case PROTOCOL_CHANNELS_AFHDS3: +#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO) + extmoduleSendBuffer(extmodulePulsesData.afhds3.getData(), + extmodulePulsesData.afhds3.getSize()); +#else + extmoduleSendNextFrameAFHDS3(extmodulePulsesData.afhds3.getData(), + extmodulePulsesData.afhds3.getSize()); +#endif + break; +#endif + +#if defined(DSM2) + case PROTOCOL_CHANNELS_SBUS: + case PROTOCOL_CHANNELS_DSM2_LP45: + case PROTOCOL_CHANNELS_DSM2_DSM2: + case PROTOCOL_CHANNELS_DSM2_DSMX: case PROTOCOL_CHANNELS_MULTIMODULE: - IntmoduleSerialDriver.sendBuffer(intmodulePulsesData.multi.getData(), - intmodulePulsesData.multi.getSize()); + extmoduleSendNextFrameSoftSerial100kbit( + extmodulePulsesData.dsm2.pulses, + extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses); break; #endif -#if defined(INTERNAL_MODULE_CRSF) - case PROTOCOL_CHANNELS_CROSSFIRE: - if (CrossfireModuleDriver.sendPulses) { - CrossfireModuleDriver.sendPulses((void*)INTERNAL_MODULE); - } +#if defined(GHOST) + case PROTOCOL_CHANNELS_GHOST: + sportSendBuffer(extmodulePulsesData.ghost.pulses, + extmodulePulsesData.ghost.length); break; #endif - -#if defined(AFHDS2) - case PROTOCOL_CHANNELS_AFHDS2A: { - uint8_t* data = (uint8_t*)intmodulePulsesData.flysky.pulses; - uint16_t size = intmodulePulsesData.flysky.ptr - data; - intmoduleSendBuffer(data, size); - } break; -#endif } } -bool setupPulsesInternalModule() -{ - uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE); - - heartbeat |= (HEART_TIMER_PULSES << INTERNAL_MODULE); - - if (moduleState[INTERNAL_MODULE].protocol != protocol) { - intmoduleStop(); - enablePulsesInternalModule(protocol); - moduleState[INTERNAL_MODULE].protocol = protocol; - return false; - } - else { - return setupPulsesInternalModule(protocol); - } -} -#endif - -#if defined(HARDWARE_EXTERNAL_MODULE) void stopPulsesExternalModule() { - if (moduleState[EXTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) { - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - extmoduleStop(); + if (moduleState[EXTERNAL_MODULE].protocol != + PROTOCOL_CHANNELS_UNINITIALIZED) { + if (externalModuleDriver) { + externalModuleDriver->deinit(externalModuleContext); + externalModuleDriver = nullptr; + externalModuleContext = nullptr; + } else { + mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); + extmoduleStop(); + } moduleState[EXTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE; } } @@ -726,7 +807,6 @@ bool setupPulsesExternalModule() heartbeat |= (HEART_TIMER_PULSES << EXTERNAL_MODULE); if (moduleState[EXTERNAL_MODULE].protocol != protocol) { - extmoduleStop(); enablePulsesExternalModule(protocol); moduleState[EXTERNAL_MODULE].protocol = protocol; return false; diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index 518b268b6..0b3542934 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -231,6 +231,7 @@ void intmoduleSendNextFrame(); #if defined(HARDWARE_EXTERNAL_MODULE) bool setupPulsesExternalModule(); void stopPulsesExternalModule(); +void extmoduleSendNextFrame(); #endif void setupPulsesDSM2(); void setupPulsesCrossfire(uint8_t idx); diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index 75aa32694..83a331c19 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -647,50 +647,87 @@ void Pxx2OtaUpdate::flashFirmware(const char * filename, ProgressHandler progres resumePulses(); } -static void* pxx2Init(uint8_t module) +static void* pxx2InitInternal(uint8_t moduleType) { - if (module == INTERNAL_MODULE) { - intmoduleFifo.clear(); - IntmoduleSerialDriver.init(&pxx2SerialInitParams); - resetAccessAuthenticationCount(); + intmoduleFifo.clear(); + IntmoduleSerialDriver.init(&pxx2SerialInitParams); + resetAccessAuthenticationCount(); #if defined(INTMODULE_HEARTBEAT) - // use backup trigger (1 ms later) - init_intmodule_heartbeat(); + // use backup trigger (1 ms later) + init_intmodule_heartbeat(); #endif + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD); + + return nullptr; +} + +static void pxx2DeInitInternal(void* context) +{ + IntmoduleSerialDriver.deinit(); +#if defined(INTMODULE_HEARTBEAT) + stop_intmodule_heartbeat(); +#endif + mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); +} + +static bool pxx2InternalSendNextFrame = true; + +static void pxx2SetupPulsesInternal(void* context, int16_t* channels, uint8_t nChannels) +{ + (void)context; + + pxx2InternalSendNextFrame = + intmodulePulsesData.pxx2.setupFrame(INTERNAL_MODULE, channels, nChannels); + + if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER || + moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) { + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_TOOLS_PERIOD); + } else { mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD); - } else { -#if defined(EXTMODULE_USART) - extmoduleInvertedSerialStart(PXX2_HIGHSPEED_BAUDRATE); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD); -#else - return nullptr; -#endif } - - return (void*)(uint32_t)module; } -static void pxx2DeInit(void* context) +static void pxx2SendPulsesInternal(void* context) { - uint32_t module = (uint32_t)context; + (void)context; - if (module == INTERNAL_MODULE) { - IntmoduleSerialDriver.deinit(); -#if defined(INTMODULE_HEARTBEAT) - stop_intmodule_heartbeat(); -#endif - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); - } else { - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - extmoduleStop(); + if (pxx2InternalSendNextFrame) { + IntmoduleSerialDriver.sendBuffer(intmodulePulsesData.pxx2.getData(), + intmodulePulsesData.pxx2.getSize()); } } +#include "hal/module_driver.h" + +const etx_module_driver_t Pxx2InternalDriver = { + .protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED, + .init = pxx2InitInternal, + .deinit = pxx2DeInitInternal, + .setupPulses = pxx2SetupPulsesInternal, + .sendPulses = pxx2SendPulsesInternal, +}; + +#if defined(EXTMODULE_USART) +#include "extmodule_serial_driver.h" + +static const etx_serial_init pxx2ExtSerialInitParams = { + .baudrate = 0, + .parity = ETX_Parity_None, + .stop_bits = ETX_StopBits_One, + .word_length = ETX_WordLength_8, + .rx_enable = true, + .on_receive = extmoduleFifoReceive, + .on_error = extmoduleFifoError, +}; + static void* pxx2InitLowSpeed(uint8_t module) { if (module == EXTERNAL_MODULE) { - extmoduleInvertedSerialStart(PXX2_LOWSPEED_BAUDRATE); + etx_serial_init params(pxx2ExtSerialInitParams); + params.baudrate = PXX2_LOWSPEED_BAUDRATE; + ExtmoduleSerialDriver.init(¶ms); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD); return (void*)EXTERNAL_MODULE; } @@ -698,59 +735,50 @@ static void* pxx2InitLowSpeed(uint8_t module) return nullptr; } -static bool pxx2InternalSendNextFrame = true; - -static void pxx2SetupPulses(void* context, int16_t* channels, uint8_t nChannels) +static void* pxx2InitExternal(uint8_t moduleType) { - uint32_t module = (uint32_t)context; + etx_serial_init params(pxx2ExtSerialInitParams); + params.baudrate = PXX2_HIGHSPEED_BAUDRATE; + ExtmoduleSerialDriver.init(¶ms); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD); - if (module == INTERNAL_MODULE) { - - pxx2InternalSendNextFrame = intmodulePulsesData.pxx2.setupFrame( - INTERNAL_MODULE, channels, nChannels); - - if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER || - moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) { - mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_TOOLS_PERIOD); - } else { - mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD); - } - } else { - extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE, channels, nChannels); - } + return nullptr; } -static void pxx2SendPulses(void* context) +static void pxx2DeInitExternal(void* context) { - uint32_t module = (uint32_t)context; + (void)context; - if (module == INTERNAL_MODULE) { - if (pxx2InternalSendNextFrame) { - IntmoduleSerialDriver.sendBuffer(intmodulePulsesData.pxx2.getData(), - intmodulePulsesData.pxx2.getSize()); - } - } else { -#if defined(EXTMODULE_USART) - extmoduleSendBuffer(extmodulePulsesData.pxx2.getData(), - extmodulePulsesData.pxx2.getSize()); -#endif - } + mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); + extmoduleStop(); } -#include "hal/module_driver.h" +static void pxx2SetupPulsesExternal(void* context, int16_t* channels, uint8_t nChannels) +{ + (void)context; + extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE, channels, nChannels); +} -const etx_module_driver_t Pxx2ModuleDriver = { +static void pxx2SendPulsesExternal(void* context) +{ + (void)context; + ExtmoduleSerialDriver.sendBuffer(extmodulePulsesData.pxx2.getData(), + extmodulePulsesData.pxx2.getSize()); +} + +const etx_module_driver_t Pxx2ExternalDriver = { .protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED, - .init = pxx2Init, - .deinit = pxx2DeInit, - .setupPulses = pxx2SetupPulses, - .sendPulses = pxx2SendPulses, + .init = pxx2InitExternal, + .deinit = pxx2DeInitExternal, + .setupPulses = pxx2SetupPulsesExternal, + .sendPulses = pxx2SendPulsesExternal, }; -const etx_module_driver_t Pxx2LowSpeedModuleDriver = { +const etx_module_driver_t Pxx2LowSpeedExternalDriver = { .protocol = PROTOCOL_CHANNELS_PXX2_LOWSPEED, .init = pxx2InitLowSpeed, - .deinit = pxx2DeInit, - .setupPulses = pxx2SetupPulses, - .sendPulses = pxx2SendPulses, + .deinit = pxx2DeInitExternal, + .setupPulses = pxx2SetupPulsesExternal, + .sendPulses = pxx2SendPulsesExternal, }; +#endif diff --git a/radio/src/pulses/pxx2.h b/radio/src/pulses/pxx2.h index 65b30ff76..be832e510 100644 --- a/radio/src/pulses/pxx2.h +++ b/radio/src/pulses/pxx2.h @@ -579,7 +579,9 @@ class Pxx2OtaUpdate { }; extern const etx_serial_init pxx2SerialInitParams; -extern const etx_module_driver_t Pxx2ModuleDriver; -extern const etx_module_driver_t Pxx2LowSpeedModuleDriver; + +extern const etx_module_driver_t Pxx2InternalDriver; +extern const etx_module_driver_t Pxx2ExternalDriver; +extern const etx_module_driver_t Pxx2LowSpeedExternalDriver; #endif diff --git a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp new file mode 100644 index 000000000..a36d47fb2 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp @@ -0,0 +1,194 @@ +/* + * 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 "hal/serial_driver.h" +#include "board.h" + +#if defined(EXTMODULE_USART) +#include "stm32_usart_driver.h" + +#include "io/frsky_pxx2.h" +ModuleFifo extmoduleFifo; + +struct etx_serial_callbacks_t { + void (*on_receive)(uint8_t data); + void (*on_error)(); +}; + +static etx_serial_callbacks_t extmodule_driver = { nullptr, nullptr }; + +void extmoduleFifoReceive(uint8_t data) +{ + extmoduleFifo.push(data); +} + +void extmoduleFifoError() +{ + extmoduleFifo.errors++; +} + +static const etx_serial_init extmoduleSerialParams = { + .baudrate = 0, + .parity = ETX_Parity_None, + .stop_bits = ETX_StopBits_One, + .word_length = ETX_WordLength_8, + .rx_enable = true, + .on_receive = extmoduleFifoReceive, + .on_error = extmoduleFifoError, +}; + +static void extmoduleSerialStart(const etx_serial_init* params) +{ + if (!params) return; + + extmodule_driver.on_receive = params->on_receive; + extmodule_driver.on_error = params->on_error; + + // TX + RX Pins + GPIO_PinAFConfig(EXTMODULE_USART_GPIO, EXTMODULE_TX_GPIO_PinSource, + EXTMODULE_USART_GPIO_AF); + GPIO_PinAFConfig(EXTMODULE_USART_GPIO, EXTMODULE_RX_GPIO_PinSource, + EXTMODULE_USART_GPIO_AF); + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(EXTMODULE_USART_GPIO, &GPIO_InitStructure); + + // UART config + stm32_usart_init(EXTMODULE_USART, params); + extmoduleFifo.clear(); + + USART_ITConfig(EXTMODULE_USART, USART_IT_RXNE, ENABLE); + NVIC_SetPriority(EXTMODULE_USART_IRQn, 6); + NVIC_EnableIRQ(EXTMODULE_USART_IRQn); +} + +void extmoduleInvertedSerialStart(uint32_t baudrate) +{ + EXTERNAL_MODULE_ON(); + etx_serial_init params(extmoduleSerialParams); + params.baudrate = baudrate; + extmoduleSerialStart(¶ms); +} + +void extmoduleSerialStop() +{ + DMA_DeInit(EXTMODULE_USART_TX_DMA_STREAM); + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_Init(EXTMODULE_USART_GPIO, &GPIO_InitStructure); + + USART_DeInit(EXTMODULE_USART); + + GPIO_ResetBits(EXTMODULE_USART_GPIO, EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN); + + // reset callbacks + extmodule_driver.on_receive = nullptr; + extmodule_driver.on_error = nullptr; +} + +static void extmoduleSendByte(uint8_t byte) +{ + while (!(EXTMODULE_USART->SR & USART_SR_TXE)); + USART_SendData(EXTMODULE_USART, byte); +} + +static void extmoduleSendBuffer(const uint8_t * data, uint8_t size) +{ + if (size == 0) + return; + + DMA_InitTypeDef DMA_InitStructure; + DMA_DeInit(EXTMODULE_USART_TX_DMA_STREAM); + DMA_InitStructure.DMA_Channel = EXTMODULE_USART_TX_DMA_CHANNEL; + DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&EXTMODULE_USART->DR); + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(data); + DMA_InitStructure.DMA_BufferSize = size; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(EXTMODULE_USART_TX_DMA_STREAM, &DMA_InitStructure); + DMA_Cmd(EXTMODULE_USART_TX_DMA_STREAM, ENABLE); + USART_DMACmd(EXTMODULE_USART, USART_DMAReq_Tx, ENABLE); +} + +#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) +extern "C" void EXTMODULE_USART_IRQHandler(void) +{ + // No ISR based send loop: DMA only + + // Receive + uint32_t status = EXTMODULE_USART->SR; + while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { + uint8_t data = EXTMODULE_USART->DR; + if (status & USART_FLAG_ERRORS) { + if (extmodule_driver.on_error) + extmodule_driver.on_error(); + } + else { + if (extmodule_driver.on_receive) + extmodule_driver.on_receive(data); + } + status = EXTMODULE_USART->SR; + } +} + +static void extmoduleWaitForTxCompleted() +{ +#if !defined(SIMU) + // TODO: check if everything is properly initialised, this seems to block when + // the port has been initialised with a zero baudrate + if (DMA_GetCmdStatus(EXTMODULE_USART_TX_DMA_STREAM) == ENABLE) { + while (DMA_GetFlagStatus(EXTMODULE_USART_TX_DMA_STREAM, + EXTMODULE_USART_TX_DMA_FLAG_TC) == RESET) + ; + DMA_ClearFlag(EXTMODULE_USART_TX_DMA_STREAM, + EXTMODULE_USART_TX_DMA_FLAG_TC); + } +#endif +} + +etx_serial_driver_t ExtmoduleSerialDriver = { + .init = extmoduleSerialStart, + .deinit = extmoduleSerialStop, + .sendByte = extmoduleSendByte, + .sendBuffer = extmoduleSendBuffer, + .waitForTxCompleted = extmoduleWaitForTxCompleted, +}; + +#endif // defined(EXTMODULE_USART) diff --git a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.h b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.h new file mode 100644 index 000000000..48a887216 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.h @@ -0,0 +1,36 @@ +/* + * 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 "hal/serial_driver.h" + +// Callbacks using intmoduleFifo +void extmoduleFifoReceive(uint8_t data); +void extmoduleFifoError(); + +// void extmoduleSerialStart(); +// void extmoduleInvertedSerialStart(uint32_t baudrate); +// void extmoduleSendBuffer(const uint8_t * data, uint8_t size); +// void extmoduleSendNextFrame(); + +extern etx_serial_driver_t ExtmoduleSerialDriver; diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp index 83fc38aa9..05342e6c3 100755 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp @@ -24,17 +24,18 @@ #include "stm32_usart_driver.h" ModuleFifo intmoduleFifo; + #if !defined(INTMODULE_DMA_STREAM) uint8_t * intmoduleTxBufferData; volatile uint8_t intmoduleTxBufferRemaining; #endif -struct etx_serial_driver { +struct etx_serial_callbacks_t { void (*on_receive)(uint8_t data); void (*on_error)(); }; -static etx_serial_driver intmodule_driver = { nullptr, nullptr }; +static etx_serial_callbacks_t intmodule_driver = { nullptr, nullptr }; // TODO: move this somewhere else void intmoduleFifoReceive(uint8_t data) @@ -47,18 +48,6 @@ void intmoduleFifoError() intmoduleFifo.errors++; } -// etx_serial_init::etx_serial_init(): -// baudrate(0), -// parity(USART_Parity_No), -// stop_bits(USART_StopBits_1), -// word_length(USART_WordLength_8b), -// rx_enable(false), -// // TODO: this should not be needed -// on_receive(intmoduleFifoReceive), -// on_error(intmoduleFifoError) -// { -// } - void intmoduleStop() { #if defined(INTMODULE_DMA_STREAM) @@ -238,7 +227,7 @@ void intmoduleWaitForTxCompleted() #endif } -etx_hal_serial_driver_t IntmoduleSerialDriver = { +etx_serial_driver_t IntmoduleSerialDriver = { .init = intmoduleSerialStart, .deinit = intmoduleStop, .sendByte = intmoduleSendByte, diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.h b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.h index b0e643828..52f4e9f1e 100644 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.h +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.h @@ -28,4 +28,4 @@ void intmoduleFifoReceive(uint8_t data); void intmoduleFifoError(); -extern etx_hal_serial_driver_t IntmoduleSerialDriver; +extern etx_serial_driver_t IntmoduleSerialDriver; diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 65327b29a..eaac55e49 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -242,6 +242,7 @@ set(TARGET_SRC ../common/arm/stm32/mixer_scheduler_driver.cpp ../common/arm/stm32/timers_driver.cpp ../common/arm/stm32/intmodule_serial_driver.cpp + ../common/arm/stm32/extmodule_serial_driver.cpp ../common/arm/stm32/stm32_usart_driver.cpp ../common/arm/stm32/rotary_encoder_driver.cpp ) diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index a9f40e99e..08c458263 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -194,12 +194,6 @@ void SDRAM_Init(); #define IS_PXX1_INTERNAL_ENABLED() (true) #endif -void extmoduleSerialStart(); -void extmoduleInvertedSerialStart(uint32_t baudrate); -void extmoduleSendBuffer(const uint8_t * data, uint8_t size); -void extmoduleSendNextFrame(); -void extmoduleSendInvertedByte(uint8_t byte); - // Trainer driver void init_trainer_ppm(); void stop_trainer_ppm(); diff --git a/radio/src/targets/horus/extmodule_driver.cpp b/radio/src/targets/horus/extmodule_driver.cpp index 38581f661..5d88cefa6 100644 --- a/radio/src/targets/horus/extmodule_driver.cpp +++ b/radio/src/targets/horus/extmodule_driver.cpp @@ -20,6 +20,7 @@ */ #include "opentx.h" +#include "extmodule_driver.h" #if defined(CROSSFIRE) #include "pulses/crossfire.h" @@ -207,232 +208,114 @@ void extmoduleSerialStart() NVIC_SetPriority(EXTMODULE_TIMER_DMA_STREAM_IRQn, 7); } -#if defined(EXTMODULE_USART) -ModuleFifo extmoduleFifo; - -void extmoduleInvertedSerialStart(uint32_t baudrate) +static void extmoduleSendNextFramePpm(uint32_t* pulses, uint16_t length, + uint16_t trailing_pulse) { - EXTERNAL_MODULE_ON(); - - // TX + RX Pins - GPIO_PinAFConfig(EXTMODULE_USART_GPIO, EXTMODULE_TX_GPIO_PinSource, EXTMODULE_USART_GPIO_AF); - GPIO_PinAFConfig(EXTMODULE_USART_GPIO, EXTMODULE_RX_GPIO_PinSource, EXTMODULE_USART_GPIO_AF); - - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(EXTMODULE_USART_GPIO, &GPIO_InitStructure); - - // UART config - USART_DeInit(EXTMODULE_USART); - USART_InitTypeDef USART_InitStructure; - USART_InitStructure.USART_BaudRate = baudrate; - USART_InitStructure.USART_Parity = USART_Parity_No; - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; - USART_Init(EXTMODULE_USART, &USART_InitStructure); - USART_Cmd(EXTMODULE_USART, ENABLE); - - extmoduleFifo.clear(); - - USART_ITConfig(EXTMODULE_USART, USART_IT_RXNE, ENABLE); - NVIC_SetPriority(EXTMODULE_USART_IRQn, 6); - NVIC_EnableIRQ(EXTMODULE_USART_IRQn); -} - -void extmoduleSendBuffer(const uint8_t * data, uint8_t size) -{ - DMA_InitTypeDef DMA_InitStructure; - DMA_DeInit(EXTMODULE_USART_TX_DMA_STREAM); - DMA_InitStructure.DMA_Channel = EXTMODULE_USART_TX_DMA_CHANNEL; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&EXTMODULE_USART->DR); - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(data); - DMA_InitStructure.DMA_BufferSize = size; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(EXTMODULE_USART_TX_DMA_STREAM, &DMA_InitStructure); - DMA_Cmd(EXTMODULE_USART_TX_DMA_STREAM, ENABLE); - USART_DMACmd(EXTMODULE_USART, USART_DMAReq_Tx, ENABLE); -} - -#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) -extern "C" void EXTMODULE_USART_IRQHandler(void) -{ - uint32_t status = EXTMODULE_USART->SR; - - while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { - uint8_t data = EXTMODULE_USART->DR; - if (status & USART_FLAG_ERRORS) { - extmoduleFifo.errors++; - } - else { - extmoduleFifo.push(data); - } - status = EXTMODULE_USART->SR; - } -} -#endif - -void extmoduleSendNextFrame() -{ - switch (moduleState[EXTERNAL_MODULE].protocol) { - case PROTOCOL_CHANNELS_PPM: #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->CCR2 = *(extmodulePulsesData.ppm.ptr - 1) - 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 | EXTMODULE_TIMER_DMA_SIZE | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; + // Using timer channel 3 + 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); #else - EXTMODULE_TIMER->CCR1 = GET_MODULE_PPM_DELAY(EXTERNAL_MODULE)*2; - EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | - (GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE) ? + // 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) ? #if defined(PCBNV14) - 0 : TIM_CCER_CC1P + 0 + : TIM_CCER_CC1P #else - TIM_CCER_CC1P : 0 + TIM_CCER_CC1P + : 0 #endif - ); - EXTMODULE_TIMER->CCR2 = *(extmodulePulsesData.ppm.ptr - 1) - 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 | EXTMODULE_TIMER_DMA_SIZE | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; + ); #endif - EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); - EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(extmodulePulsesData.ppm.pulses); - EXTMODULE_TIMER_DMA_STREAM->NDTR = extmodulePulsesData.ppm.ptr - extmodulePulsesData.ppm.pulses; - EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA - break; + 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 | + EXTMODULE_TIMER_DMA_SIZE | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; + EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); + 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 +} #if defined(PXX1) - case PROTOCOL_CHANNELS_PXX1_PULSES: - if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) - return; +void extmoduleSendNextFramePxx1(const uint32_t* pulses, uint16_t length) +{ + if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) return; - // disable timer - EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; - EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | EXTMODULE_TIMER_DMA_SIZE | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; - EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); - EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(extmodulePulsesData.pxx.getData()); - EXTMODULE_TIMER_DMA_STREAM->NDTR = extmodulePulsesData.pxx.getSize(); - EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA + // disable timer + EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; + EXTMODULE_TIMER_DMA_STREAM->CR |= + EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | + EXTMODULE_TIMER_DMA_SIZE | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; + EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); + 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; - break; + // re-init timer + EXTMODULE_TIMER->EGR = 1; + EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; +} #endif -#if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) - case PROTOCOL_CHANNELS_PXX1_SERIAL: - extmoduleSendBuffer(extmodulePulsesData.pxx_uart.getData(), extmodulePulsesData.pxx_uart.getSize()); - break; +#if defined(AFHDS3) && !(defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)) +void extmoduleSendNextFrameAFHDS3(const uint16_t* dataPtr, uint16_t dataSize) +{ + if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) return; + + 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 | + DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; + EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); + EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(dataPtr); + EXTMODULE_TIMER_DMA_STREAM->NDTR = dataSize; + EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA + + // re-init timer + EXTMODULE_TIMER->EGR = TIM_PSCReloadMode_Immediate; + EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; +} #endif -#if defined(PXX2) && defined(EXTMODULE_USART) - case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: - case PROTOCOL_CHANNELS_PXX2_LOWSPEED: - Pxx2ModuleDriver.sendPulses((void*)EXTERNAL_MODULE); - break; -#endif +void extmoduleSendNextFrameSoftSerial100kbit(const uint32_t* pulses, uint16_t length) +{ + if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) return; -#if defined(AFHDS3) - case PROTOCOL_CHANNELS_AFHDS3: - { -#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO) - extmoduleSendBuffer(extmodulePulsesData.afhds3.getData(), extmodulePulsesData.afhds3.getSize()); -#else - if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) - return; - - const uint16_t* dataPtr = extmodulePulsesData.afhds3.getData(); - uint32_t dataSize = extmodulePulsesData.afhds3.getSize(); - 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 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; - EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); - EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(dataPtr); - EXTMODULE_TIMER_DMA_STREAM->NDTR = dataSize; - EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA - - // re-init timer - EXTMODULE_TIMER->EGR = TIM_PSCReloadMode_Immediate; - EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; -#endif - } - break; -#endif - -#if defined(DSM2) - case PROTOCOL_CHANNELS_SBUS: - case PROTOCOL_CHANNELS_DSM2_LP45: - case PROTOCOL_CHANNELS_DSM2_DSM2: - case PROTOCOL_CHANNELS_DSM2_DSMX: - case PROTOCOL_CHANNELS_MULTIMODULE: - - if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) - return; - - if (PROTOCOL_CHANNELS_SBUS == moduleState[EXTERNAL_MODULE].protocol) { - // reverse polarity for Sbus if needed - EXTMODULE_TIMER->CCER = + 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 | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0) #elif defined(PCBNV14) - TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? 0 : TIM_CCER_CC1P) + TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? 0 : TIM_CCER_CC1P) #else - TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0) + TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0) #endif - ; // - } - - // disable timer - EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; - - // send DMA request - 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 | EXTMODULE_TIMER_DMA_SIZE | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; - EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); - EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(extmodulePulsesData.dsm2.pulses); - EXTMODULE_TIMER_DMA_STREAM->NDTR = extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses; - 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; - break; -#endif - -#if defined(CROSSFIRE) - case PROTOCOL_CHANNELS_CROSSFIRE: - if (CrossfireModuleDriver.sendPulses) { - CrossfireModuleDriver.sendPulses((void*)EXTERNAL_MODULE); - } - break; -#endif - -#if defined(GHOST) - case PROTOCOL_CHANNELS_GHOST: - sportSendBuffer(extmodulePulsesData.ghost.pulses, extmodulePulsesData.ghost.length); - break; -#endif - - default: - EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; - break; + ; // } + + // disable timer + EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; + + // send DMA request + 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 | + EXTMODULE_TIMER_DMA_SIZE | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; + EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); + 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; } void extmoduleSendInvertedByte(uint8_t byte) @@ -487,6 +370,9 @@ extern "C" void EXTMODULE_TIMER_IRQHandler() EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; - if (setupPulsesExternalModule()) - extmoduleSendNextFrame(); + setupPulsesPPMExternalModule(); + 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 new file mode 100644 index 000000000..6739c51fa --- /dev/null +++ b/radio/src/targets/horus/extmodule_driver.h @@ -0,0 +1,44 @@ +/* + * 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 + +void extmoduleStop(); +void extmodulePpmStart(); + +#if defined(PXX1) +void extmodulePxx1PulsesStart(); +void extmoduleSendNextFramePxx1(const uint32_t* pulses, uint16_t length); +#endif + +// Soft serial on PPM pin +void extmoduleSerialStart(); + +#if defined(AFHDS3) && !(defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)) +void extmoduleSendNextFrameAFHDS3(const uint16_t* dataPtr, uint16_t dataSize); +#endif + +void extmoduleSendNextFrameSoftSerial100kbit(const uint32_t* pulses, uint16_t length); + +// Bitbang serial +void extmoduleSendInvertedByte(uint8_t byte); diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 2ad32f759..54e5b0c39 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -862,6 +862,7 @@ #define EXTMODULE_USART_IRQHandler USART3_IRQHandler #define EXTMODULE_USART_TX_DMA_CHANNEL DMA_Channel_4 #define EXTMODULE_USART_TX_DMA_STREAM DMA1_Stream3 + #define EXTMODULE_USART_TX_DMA_FLAG_TC DMA_FLAG_TCIF3 #define EXTMODULE_USART_RX_DMA_CHANNEL DMA_Channel_4 #define EXTMODULE_USART_RX_DMA_STREAM DMA1_Stream1 #elif defined(PCBX10) || PCBREV >= 13