diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index e740be7d1ec..3cb6bfec2b3 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -238,6 +238,7 @@ enum UartModes { UART_MODE_GPS, UART_MODE_DEBUG, UART_MODE_SPACEMOUSE, + UART_MODE_EXT_MODULE, UART_MODE_COUNT SKIP, UART_MODE_MAX SKIP = UART_MODE_COUNT-1 }; diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 18de0210268..988c4d4e4ab 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -21,6 +21,10 @@ #include "opentx.h" +#if defined(PXX2) + #include "extmodule_serial_driver.h" +#endif + #if defined(PCBFRSKY) || defined(PCBFLYSKY) uint8_t switchToMix(uint8_t source) { @@ -431,6 +435,15 @@ bool isSerialModeAvailable(uint8_t port_nr, int mode) return false; #endif +#if !defined(AUX_SERIAL_DMA_TX) || defined(EXTMODULE_USART) + if (mode == UART_MODE_EXT_MODULE) + return false; +#else // defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART) + // UART_MODE_EXT_MODULE is only supported on AUX1, as AUX2 has no TX DMA + if (mode == UART_MODE_EXT_MODULE && port_nr != SP_AUX1) + return false; +#endif + #if !defined(LUA) if (mode == UART_MODE_LUA) return false; @@ -803,6 +816,7 @@ bool isInternalModuleAvailable(int moduleType) } #endif +#if defined(HARDWARE_EXTERNAL_MODULE) bool isExternalModuleAvailable(int moduleType) { @@ -835,11 +849,17 @@ bool isExternalModuleAvailable(int moduleType) return false; // doesn't exist for now -#if !defined(PXX2) || !defined(EXTMODULE_USART) - if (moduleType == MODULE_TYPE_XJT_LITE_PXX2 || moduleType == MODULE_TYPE_R9M_PXX2 || moduleType == MODULE_TYPE_R9M_LITE_PXX2 || moduleType == MODULE_TYPE_R9M_LITE_PRO_PXX2) { + if (moduleType == MODULE_TYPE_XJT_LITE_PXX2 || + moduleType == MODULE_TYPE_R9M_PXX2 || + moduleType == MODULE_TYPE_R9M_LITE_PXX2 || + moduleType == MODULE_TYPE_R9M_LITE_PRO_PXX2) { + +#if defined(PXX2) + return extmoduleGetSerialPort() != nullptr; +#else return false; - } #endif + } #if !defined(CROSSFIRE) if (moduleType == MODULE_TYPE_CROSSFIRE) @@ -887,6 +907,14 @@ bool isExternalModuleAvailable(int moduleType) return true; } +#else // !defined(HARDWARE_EXTERNAL_MODULE) + +bool isExternalModuleAvailable(int moduleType) +{ + return false; +} +#endif + bool isRfProtocolAvailable(int protocol) { #if defined(CROSSFIRE) diff --git a/radio/src/pulses/afhds3.cpp b/radio/src/pulses/afhds3.cpp index 701a0311e1c..00bc56a3988 100644 --- a/radio/src/pulses/afhds3.cpp +++ b/radio/src/pulses/afhds3.cpp @@ -864,7 +864,9 @@ void applyModelConfig(uint8_t module) static void* initExternal(uint8_t module) { #if defined(AFHDS3_EXT_UART) - const etx_serial_driver_t* drv = &ExtmoduleSerialDriver; + auto drv = extmoduleGetSerialPort(); + if (!drv) return nullptr; + uint16_t period = AFHDS3_UART_COMMAND_TIMEOUT * 1000 /* us */; #else const etx_serial_driver_t* drv = nullptr; diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index d6dc3b8d797..f30ace1b9e3 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -207,9 +207,11 @@ uint8_t getModuleType(uint8_t module) } #endif +#if defined(HARDWARE_EXTERNAL_MODULE) if (module == EXTERNAL_MODULE && isExternalModuleAvailable(type)) { return type; } +#endif return MODULE_TYPE_NONE; } @@ -579,7 +581,7 @@ void enablePulsesExternalModule(uint8_t protocol) break; #endif -#if defined(PXX2) && defined(EXTMODULE_USART) +#if defined(PXX2) case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: externalModuleContext = Pxx2ExternalDriver.init(EXTERNAL_MODULE); externalModuleDriver = &Pxx2ExternalDriver; diff --git a/radio/src/pulses/pxx1.cpp b/radio/src/pulses/pxx1.cpp index a4c7ec5f5a4..7b4450fb66d 100644 --- a/radio/src/pulses/pxx1.cpp +++ b/radio/src/pulses/pxx1.cpp @@ -295,7 +295,10 @@ static const etx_serial_init pxx1ExtSerialInit = { static void* pxx1InitExternal(uint8_t module) { - void* uart_ctx = ExtmoduleSerialDriver.init(&pxx1ExtSerialInit); + auto drv = extmoduleGetSerialPort(); + if (!drv) return nullptr; + + void* uart_ctx = drv->init(&pxx1ExtSerialInit); mixerSchedulerSetPeriod(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD); EXTERNAL_MODULE_ON(); @@ -307,7 +310,9 @@ static void pxx1DeInitExternal(void* context) { EXTERNAL_MODULE_OFF(); mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - ExtmoduleSerialDriver.deinit(context); + + auto drv = extmoduleGetSerialPort(); + if (drv) drv->deinit(context); } static void pxx1SetupPulsesExternal(void* context, int16_t* channels, uint8_t nChannels) @@ -323,8 +328,11 @@ static void pxx1SetupPulsesExternal(void* context, int16_t* channels, uint8_t nC static void pxx1SendPulsesExternal(void* context) { - ExtmoduleSerialDriver.sendBuffer(context, extmodulePulsesData.pxx_uart.getData(), - extmodulePulsesData.pxx_uart.getSize()); + auto drv = extmoduleGetSerialPort(); + if (!drv) return; + + drv->sendBuffer(context, extmodulePulsesData.pxx_uart.getData(), + extmodulePulsesData.pxx_uart.getSize()); } const etx_module_driver_t Pxx1ExternalSerialDriver = { diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index 91e9c816cb1..b6ca1572c4e 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -812,6 +812,7 @@ static void pxx2ProcessData(void* context, uint8_t data, uint8_t* buffer, uint8_ #include "hal/module_driver.h" +#include "extmodule_serial_driver.h" const etx_module_driver_t Pxx2InternalDriver = { .protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED, @@ -823,9 +824,6 @@ const etx_module_driver_t Pxx2InternalDriver = { .processData = pxx2ProcessData, }; -#if defined(EXTMODULE_USART) -#include "extmodule_serial_driver.h" - static void* pxx2InitExternal(uint8_t module, uint32_t baudrate) { etx_serial_init params(pxx2SerialInitParams); @@ -837,9 +835,10 @@ static void* pxx2InitExternal(uint8_t module, uint32_t baudrate) telemetryProtocol = PROTOCOL_TELEMETRY_FRSKY_SPORT; auto state = &pxx2State[module]; - state->init(module, &extmodulePulsesData.pxx2, &ExtmoduleSerialDriver, - ExtmoduleSerialDriver.init(¶ms)); - + auto drv = extmoduleGetSerialPort(); + if (!drv) return nullptr; + + state->init(module, &extmodulePulsesData.pxx2, drv, drv->init(¶ms)); return state; } @@ -855,9 +854,11 @@ static void* pxx2InitExtHighSpeed(uint8_t module) static void pxx2DeInitExternal(void* context) { + auto state = (PXX2State*)context; + if (state) state->deinit(); + EXTERNAL_MODULE_OFF(); mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - ExtmoduleSerialDriver.deinit(context); telemetryProtocol = 0xFF; } @@ -897,4 +898,3 @@ const etx_module_driver_t Pxx2LowSpeedExternalDriver = { .getByte = pxx2GetByte, .processData = pxx2ProcessData, }; -#endif diff --git a/radio/src/serial.cpp b/radio/src/serial.cpp index 61366f57199..5bee44630dd 100644 --- a/radio/src/serial.cpp +++ b/radio/src/serial.cpp @@ -41,6 +41,10 @@ #include "telemetry/crossfire.h" #endif +#if defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART) + #include "extmodule_serial_driver.h" +#endif + #define PRINTF_BUFFER_SIZE 128 static void (*dbg_serial_putc)(void*, uint8_t) = nullptr; @@ -212,11 +216,19 @@ static void serialSetCallBacks(int mode, void* ctx, const etx_serial_port_t* por gpsSetSerialDriver(ctx, drv); break; #endif + #if defined(SPACEMOUSE) case UART_MODE_SPACEMOUSE: spacemouseSetSerialDriver(ctx, drv); break; #endif + +#if defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART) + case UART_MODE_EXT_MODULE: + extmoduleSetSerialPort(drv); + break; +#endif + #endif } } @@ -279,6 +291,12 @@ static void serialSetupPort(int mode, etx_serial_init& params) params.rx_enable = true; break; #endif + +#if defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART) + case UART_MODE_EXT_MODULE: + params.rx_enable = true; + break; +#endif #endif } } @@ -330,10 +348,10 @@ void serialInit(uint8_t port_nr, int mode) if (state->port) { auto drv = state->port->uart; - if (drv && drv->deinit) { + if (drv && drv->deinit && state->usart_ctx) { drv->deinit(state->usart_ctx); } - if (state->mode != 0) { + if (state->mode != UART_MODE_NONE) { // Clear callbacks serialSetCallBacks(state->mode, nullptr, nullptr); } @@ -356,11 +374,12 @@ void serialInit(uint8_t port_nr, int mode) serialSetPowerState(port_nr); #endif - if (params.baudrate != 0) { - state->mode = mode; + state->mode = mode; + + if (mode != UART_MODE_NONE) { state->port = port; - if (port) { + if (port && params.baudrate != 0) { if (port->uart && port->uart->init) state->usart_ctx = port->uart->init(¶ms); } diff --git a/radio/src/storage/storage_common.cpp b/radio/src/storage/storage_common.cpp index 624eba48ebd..d3bb8f83477 100644 --- a/radio/src/storage/storage_common.cpp +++ b/radio/src/storage/storage_common.cpp @@ -114,15 +114,6 @@ void postModelLoad(bool alarms) } #endif -#if defined(HARDWARE_INTERNAL_MODULE) - if (!isInternalModuleAvailable(g_model.moduleData[INTERNAL_MODULE].type)) { - memclear(&g_model.moduleData[INTERNAL_MODULE], sizeof(ModuleData)); - } -#endif - - if (!isExternalModuleAvailable(g_model.moduleData[EXTERNAL_MODULE].type)) { - memclear(&g_model.moduleData[EXTERNAL_MODULE], sizeof(ModuleData)); - } #if defined(MULTIMODULE) && defined(MULTI_PROTOLIST) MultiRfProtocols::removeInstance(EXTERNAL_MODULE); #endif diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp index fb3e5b55dfe..bc9694c6872 100644 --- a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp @@ -1881,6 +1881,7 @@ static const struct YamlIdStr enum_UartModes[] = { { UART_MODE_GPS, "GPS" }, { UART_MODE_DEBUG, "DEBUG" }, { UART_MODE_SPACEMOUSE, "SPACEMOUSE" }, + { UART_MODE_EXT_MODULE, "EXT_MODULE" }, { 0, NULL } }; diff --git a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp index 07e8d2c3468..e42e941f566 100644 --- a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp @@ -32,7 +32,7 @@ #define AUX_SERIAL_TX_BUFFER 512 #if defined(SDRAM) - #define AUX_SERIAL_RX_BUFFER 128 + #define AUX_SERIAL_RX_BUFFER 512 #else #define AUX_SERIAL_RX_BUFFER 32 #endif @@ -53,8 +53,8 @@ static void* aux_serial_init(const SerialState* st, const etx_serial_init* param stm32_usart_init(st->usart, params); if (params->rx_enable && st->usart->rxDMA) { - st->rxFifo->clear(); stm32_usart_init_rx_dma(st->usart, st->rxFifo->buffer(), st->rxFifo->size()); + st->rxFifo->clear(); } return (void*)st; @@ -62,17 +62,25 @@ static void* aux_serial_init(const SerialState* st, const etx_serial_init* param static void aux_serial_putc(void* ctx, uint8_t c) { + // When sending single bytes, + // send is based on IRQ, so that this + // only enables the corresponding IRQ + auto st = (const SerialState*)ctx; if (st->txFifo->isFull()) return; st->txFifo->push(c); - // Send is based on IRQ, so that this - // only enables the corresponding IRQ - stm32_usart_send_buffer(st->usart, &c, 1); + stm32_usart_enable_tx_irq(st->usart); } static void aux_serial_send_buffer(void* ctx, const uint8_t* data, uint8_t size) { + auto st = (const SerialState*)ctx; + if (st->usart->txDMA) { + stm32_usart_send_buffer(st->usart, data, size); + return; + } + while(size > 0) { aux_serial_putc(ctx, *data++); size--; @@ -112,15 +120,22 @@ static const LL_GPIO_InitTypeDef auxUSARTPinInit = { .Alternate = AUX_SERIAL_GPIO_AF_LL, }; +#if !defined(AUX_SERIAL_DMA_TX) + #define AUX_SERIAL_DMA_TX nullptr + #define AUX_SERIAL_DMA_Stream_TX nullptr + #define AUX_SERIAL_DMA_Stream_TX_LL 0 + #define AUX_SERIAL_DMA_Channel_TX 0 +#endif + static const stm32_usart_t auxUSART = { .USARTx = AUX_SERIAL_USART, .GPIOx = AUX_SERIAL_GPIO, .pinInit = &auxUSARTPinInit, .IRQn = AUX_SERIAL_USART_IRQn, .IRQ_Prio = 7, // TODO: define constant - .txDMA = nullptr, - .txDMA_Stream = 0, - .txDMA_Channel = 0, + .txDMA = AUX_SERIAL_DMA_TX, + .txDMA_Stream = AUX_SERIAL_DMA_Stream_TX_LL, + .txDMA_Channel = AUX_SERIAL_DMA_Channel_TX, .rxDMA = AUX_SERIAL_DMA_RX, .rxDMA_Stream = AUX_SERIAL_DMA_Stream_RX_LL, .rxDMA_Channel = AUX_SERIAL_DMA_Channel_RX, diff --git a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp index e9045764c90..40d7354121c 100644 --- a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp @@ -20,38 +20,60 @@ */ #include "stm32_hal_ll.h" +#include "stm32_usart_driver.h" #include "extmodule_serial_driver.h" + #include "board.h" #if defined(EXTMODULE_USART) -#include "stm32_usart_driver.h" -#include "fifo.h" -typedef DMAFifo RxFifo; -static RxFifo extmoduleFifo __DMA (EXTMODULE_USART_RX_DMA_STREAM); +struct RxFifo { + uint8_t* buf; + uint16_t size; + uint16_t widx; + uint16_t ridx; +}; -struct ExtmoduleCtx -{ - RxFifo* rxFifo; +struct ExtmoduleCtx { + RxFifo rxFifo; const stm32_usart_t* usart; }; -static etx_serial_callbacks_t extmodule_driver = { +static etx_serial_callbacks_t extmodule_callbacks = { nullptr, nullptr, nullptr }; -void extmoduleFifoReceive(uint8_t data) +static void _fifo_clear(const stm32_usart_t* usart, RxFifo& fifo) { - extmoduleFifo.push(data); + if (usart->rxDMA) { + auto dma_len = LL_DMA_GetDataLength(usart->rxDMA, usart->rxDMA_Stream); + fifo.ridx = fifo.size - dma_len; + } else { + fifo.widx = fifo.ridx = 0; + } } -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, -}; +static int _fifo_get_byte(const stm32_usart_t* usart, RxFifo& fifo, uint8_t* data) +{ + if (usart->rxDMA) { + auto DMAx = usart->rxDMA; + auto stream = usart->rxDMA_Stream; + + // DMA stream enabled? + if (!LL_DMA_IsEnabledStream(DMAx, stream)) return 0; + + // Anything to read? + auto dma_len = LL_DMA_GetDataLength(DMAx, stream); + if (fifo.size - dma_len == fifo.ridx) return 0; + } else { + if (fifo.ridx == fifo.widx) return 0; + } + + *data = fifo.buf[fifo.ridx]; + fifo.ridx = (fifo.ridx + 1) & (fifo.size - 1); + + return 1; +} static const LL_GPIO_InitTypeDef extmoduleUSART_PinDef = { .Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN, @@ -76,91 +98,113 @@ static const stm32_usart_t extmoduleUSART = { .rxDMA_Channel = EXTMODULE_USART_RX_DMA_CHANNEL, }; -static const ExtmoduleCtx extmoduleCtx = { - .rxFifo = &extmoduleFifo, +static uint8_t _rx_buffer[INTMODULE_FIFO_SIZE] __DMA; + +static ExtmoduleCtx extmoduleCtx = { + .rxFifo = { _rx_buffer, sizeof(_rx_buffer), 0, 0 }, .usart = &extmoduleUSART, }; -static void* extmoduleSerialStart(const etx_serial_init* params) +static void* extmoduleSerialInit(const etx_serial_init* params) { if (!params) return nullptr; - extmodule_driver.on_receive = extmoduleFifoReceive; - extmodule_driver.on_error = nullptr; + extmodule_callbacks.on_receive = nullptr; + extmodule_callbacks.on_error = nullptr; // UART config - stm32_usart_init(&extmoduleUSART, params); - extmoduleCtx.rxFifo->clear(); + auto usart = extmoduleCtx.usart; + stm32_usart_init(usart, params); - return (void*)&extmoduleCtx; -} + auto& fifo = extmoduleCtx.rxFifo; + if (params->rx_enable && usart->rxDMA) { + stm32_usart_init_rx_dma(usart, fifo.buf, fifo.size); + } + _fifo_clear(usart, fifo); -void extmoduleInvertedSerialStart(uint32_t baudrate) -{ - EXTERNAL_MODULE_ON(); - etx_serial_init params(extmoduleSerialParams); - params.baudrate = baudrate; - extmoduleSerialStart(¶ms); + return (void*)&extmoduleCtx; } -void extmoduleSerialStop(void*) +void extmoduleSerialStop(void* ctx) { - stm32_usart_deinit(&extmoduleUSART); + auto modCtx = (ExtmoduleCtx*)ctx; + stm32_usart_deinit(modCtx->usart); // reset callbacks - extmodule_driver.on_receive = nullptr; - extmodule_driver.on_error = nullptr; + extmodule_callbacks.on_receive = nullptr; + extmodule_callbacks.on_error = nullptr; } -static void extmoduleSendByte(void* ctx, uint8_t byte) +static void extmoduleSerialSendByte(void* ctx, uint8_t byte) { auto modCtx = (ExtmoduleCtx*)ctx; stm32_usart_send_byte(modCtx->usart, byte); } -static void extmoduleSendBuffer(void* ctx, const uint8_t * data, uint8_t size) +static void extmoduleSerialSendBuffer(void* ctx, const uint8_t * data, uint8_t size) { auto modCtx = (ExtmoduleCtx*)ctx; if (size == 0) return; stm32_usart_send_buffer(modCtx->usart, data, size); } -static void extmoduleWaitForTxCompleted(void* ctx) +static void extmoduleSerialWaitForTxCompleted(void* ctx) { auto modCtx = (ExtmoduleCtx*)ctx; stm32_usart_wait_for_tx_dma(modCtx->usart); } -static int extmoduleGetByte(void* ctx, uint8_t* data) +static int extmoduleSerialGetByte(void* ctx, uint8_t* data) { auto modCtx = (ExtmoduleCtx*)ctx; - if (!modCtx->rxFifo) return -1; - return modCtx->rxFifo->pop(*data); + return _fifo_get_byte(modCtx->usart, modCtx->rxFifo, data); } -static void extmoduleClearRxBuffer(void* ctx) +static void extmoduleSerialClearRxBuffer(void* ctx) { auto modCtx = (ExtmoduleCtx*)ctx; - if (!modCtx->rxFifo) return; - modCtx->rxFifo->clear(); + _fifo_clear(modCtx->usart, modCtx->rxFifo); } -const etx_serial_driver_t ExtmoduleSerialDriver = { - .init = extmoduleSerialStart, +static const etx_serial_driver_t extmoduleSerialDriver = { + .init = extmoduleSerialInit, .deinit = extmoduleSerialStop, - .sendByte = extmoduleSendByte, - .sendBuffer = extmoduleSendBuffer, - .waitForTxCompleted = extmoduleWaitForTxCompleted, - .getByte = extmoduleGetByte, - .clearRxBuffer = extmoduleClearRxBuffer, + .sendByte = extmoduleSerialSendByte, + .sendBuffer = extmoduleSerialSendBuffer, + .waitForTxCompleted = extmoduleSerialWaitForTxCompleted, + .getByte = extmoduleSerialGetByte, + .clearRxBuffer = extmoduleSerialClearRxBuffer, .getBaudrate = nullptr, .setReceiveCb = nullptr, .setBaudrateCb = nullptr, }; +constexpr const etx_serial_driver_t* _default_driver = &extmoduleSerialDriver; + +// IRQ based RX/TX: probably obsolete now extern "C" void EXTMODULE_USART_IRQHandler(void) { - stm32_usart_isr(&extmoduleUSART, &extmodule_driver); + stm32_usart_isr(extmoduleCtx.usart, &extmodule_callbacks); } +#else + +constexpr const etx_serial_driver_t* _default_driver = nullptr; + #endif // defined(EXTMODULE_USART) + +const etx_serial_driver_t* _extmodule_driver = _default_driver; + +void extmoduleSetSerialPort(const etx_serial_driver_t* drv) +{ + if (drv) { + _extmodule_driver = drv; + } else { + _extmodule_driver = _default_driver; + } +} + +const etx_serial_driver_t* extmoduleGetSerialPort() +{ + return _extmodule_driver; +} diff --git a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.h b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.h index d38136e86fc..b4c29605a2f 100644 --- a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.h +++ b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.h @@ -26,8 +26,8 @@ #define EXTMODULE_USART_IRQ_PRIORITY 6 -// Callbacks using intmoduleFifo -void extmoduleFifoReceive(uint8_t data); -void extmoduleFifoError(); +// Use an alternative USART as external module +void extmoduleSetSerialPort(const etx_serial_driver_t* port); -extern const etx_serial_driver_t ExtmoduleSerialDriver; +// Return the serial driver to be used as external module +const etx_serial_driver_t* extmoduleGetSerialPort(); diff --git a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp index ae5829db939..d06bbc4effd 100644 --- a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp @@ -19,9 +19,52 @@ * GNU General Public License for more details. */ +#include "stm32_hal_ll.h" #include "stm32_usart_driver.h" #include +// WARNING: +// +// NVIC_GetEnableIRQ is stolen from "${THIRDPARTY_DIR}/CMSIS/Include/core_cm4.h". +// +// Until we can include the new CMSIS everywhere, this +// needs to be defined here, as the old CMSIS does not define it. +// +// The new CMSIS can be used when StdPeriph is gone, as it mandates +// the old version located in "${STM32LIB_DIR}/CMSIS/Include" +// +static inline uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) { + return ((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & + (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) + ? 1UL + : 0UL)); + } else { + return (0U); + } +} + +static void _enable_usart_irq(const stm32_usart_t* usart) +{ + NVIC_SetPriority(usart->IRQn, usart->IRQ_Prio); + NVIC_EnableIRQ(usart->IRQn); +} + +void stm32_usart_enable_tx_irq(const stm32_usart_t* usart) +{ + if (LL_USART_IsEnabledDMAReq_TX(usart->USARTx)) { + stm32_usart_wait_for_tx_dma(usart); + LL_USART_DisableDMAReq_TX(usart->USARTx); + } + + if (!NVIC_GetEnableIRQ(usart->IRQn)) { + _enable_usart_irq(usart); + } + + LL_USART_EnableIT_TXE(usart->USARTx); +} + void stm32_usart_init_rx_dma(const stm32_usart_t* usart, void* buffer, uint32_t length) { if (!usart->rxDMA) return; @@ -61,8 +104,7 @@ void stm32_usart_deinit_rx_dma(const stm32_usart_t* usart) // Enable IRQ based RX LL_USART_EnableIT_RXNE(usart->USARTx); - NVIC_SetPriority(usart->IRQn, usart->IRQ_Prio); - NVIC_EnableIRQ(usart->IRQn); + _enable_usart_irq(usart); } void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params) @@ -127,8 +169,7 @@ void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params) } if (!usart->txDMA || (params->rx_enable && !usart->rxDMA)) { - NVIC_SetPriority(usart->IRQn, usart->IRQ_Prio); - NVIC_EnableIRQ(usart->IRQn); + _enable_usart_irq(usart); } } diff --git a/radio/src/targets/common/arm/stm32/stm32_usart_driver.h b/radio/src/targets/common/arm/stm32/stm32_usart_driver.h index 17f0cc6e047..57970ca5294 100644 --- a/radio/src/targets/common/arm/stm32/stm32_usart_driver.h +++ b/radio/src/targets/common/arm/stm32/stm32_usart_driver.h @@ -49,6 +49,7 @@ struct stm32_usart_t { void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params); void stm32_usart_init_rx_dma(const stm32_usart_t* usart, void* buffer, uint32_t length); +void stm32_usart_enable_tx_irq(const stm32_usart_t* usart); void stm32_usart_deinit(const stm32_usart_t* usart); void stm32_usart_deinit_rx_dma(const stm32_usart_t* usart); void stm32_usart_send_byte(const stm32_usart_t* usart, uint8_t byte); diff --git a/radio/src/targets/simu/module_drivers.cpp b/radio/src/targets/simu/module_drivers.cpp index 9ebd13ecabb..fe72ff29335 100644 --- a/radio/src/targets/simu/module_drivers.cpp +++ b/radio/src/targets/simu/module_drivers.cpp @@ -80,7 +80,8 @@ const etx_serial_driver_t IntmoduleSerialDriver = { .setBaudrateCb = nullptr, }; -const etx_serial_driver_t ExtmoduleSerialDriver = { +#if defined(EXTMODULE_USART) +static const etx_serial_driver_t _extmoduleSerialDriver = { .init = init, .deinit = deinit, .sendByte = sendByte, @@ -92,3 +93,21 @@ const etx_serial_driver_t ExtmoduleSerialDriver = { .setReceiveCb = nullptr, .setBaudrateCb = nullptr, }; + +constexpr const etx_serial_driver_t* _ext_default_drv = &_extmoduleSerialDriver; +#else +constexpr const etx_serial_driver_t* _ext_default_drv = nullptr; +#endif + +const etx_serial_driver_t* _ext_drv = _ext_default_drv; + +void extmoduleSetSerialPort(const etx_serial_driver_t* drv) +{ + if (drv) _ext_drv = drv; + else _ext_drv = _ext_default_drv; +} + +const etx_serial_driver_t* extmoduleGetSerialPort() +{ + return _ext_drv; +} diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 1bca4a3e24c..f63805e987b 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -742,6 +742,26 @@ void rtcSetTime(const struct gtm * t) const etx_serial_port_t UsbSerialPort = { "USB-VCP", nullptr, nullptr }; #endif +#if defined(AUX_SERIAL) || defined(AUX2_SERIAL) +static void* _fake_drv_init(const etx_serial_init*) { return nullptr; } +static void _fake_drv_fct1(void*) {} +static void _fake_drv_send_byte(void*, uint8_t) {} +static void _fake_drv_send_buffer(void*, const uint8_t*, uint8_t) {} +static int _fake_drv_get_byte(void*, uint8_t*) { return 0; } +static const etx_serial_driver_t _fake_drv = { + .init = _fake_drv_init, + .deinit = _fake_drv_fct1, + .sendByte = _fake_drv_send_byte, + .sendBuffer = _fake_drv_send_buffer, + .waitForTxCompleted = _fake_drv_fct1, + .getByte = _fake_drv_get_byte, + .clearRxBuffer = nullptr, + .getBaudrate = nullptr, + .setReceiveCb = nullptr, + .setBaudrateCb = nullptr, +}; +#endif + #if defined(AUX_SERIAL) #if defined(AUX_SERIAL_PWR_GPIO) static void _fake_pwr_aux(uint8_t) {} @@ -749,7 +769,7 @@ const etx_serial_port_t UsbSerialPort = { "USB-VCP", nullptr, nullptr }; #else #define AUX_SERIAL_PWR nullptr #endif -const etx_serial_port_t auxSerialPort = { "AUX1", nullptr, AUX_SERIAL_PWR }; +static const etx_serial_port_t auxSerialPort = {"AUX1", &_fake_drv, AUX_SERIAL_PWR}; #define AUX_SERIAL_PORT &auxSerialPort #else #define AUX_SERIAL_PORT nullptr @@ -762,7 +782,7 @@ const etx_serial_port_t auxSerialPort = { "AUX1", nullptr, AUX_SERIAL_PWR }; #else #define AUX2_SERIAL_PWR nullptr #endif -const etx_serial_port_t aux2SerialPort = { "AUX2", nullptr, AUX2_SERIAL_PWR }; +static const etx_serial_port_t aux2SerialPort = {"AUX2", &_fake_drv, AUX2_SERIAL_PWR}; #define AUX2_SERIAL_PORT &aux2SerialPort #else #define AUX2_SERIAL_PORT nullptr diff --git a/radio/src/translations/en.h b/radio/src/translations/en.h index f0f6b113b10..36b44ab9cbf 100644 --- a/radio/src/translations/en.h +++ b/radio/src/translations/en.h @@ -37,7 +37,7 @@ #define TR_TRNMODE "OFF","+=",":=" #define TR_TRNCHN "CH1","CH2","CH3","CH4" -#define TR_AUX_SERIAL_MODES "OFF","Telem Mirror","Telemetry In","SBUS Trainer","LUA","CLI","GPS","Debug","SpaceMouse" +#define TR_AUX_SERIAL_MODES "OFF","Telem Mirror","Telemetry In","SBUS Trainer","LUA","CLI","GPS","Debug","SpaceMouse","External module" #define TR_SWTYPES "None","Toggle","2POS","3POS" #define TR_POTTYPES "None",TR("Pot w. det","Pot with detent"),TR("Multipos","Multipos Switch"),"Pot" #define TR_SLIDERTYPES "None","Slider"