diff --git a/radio/src/boards/generic_stm32/module_ports.cpp b/radio/src/boards/generic_stm32/module_ports.cpp index 4eca95a9c..f9a0acc69 100644 --- a/radio/src/boards/generic_stm32/module_ports.cpp +++ b/radio/src/boards/generic_stm32/module_ports.cpp @@ -293,9 +293,15 @@ static const stm32_usart_t sportUSART = { .txDMA = TELEMETRY_DMA, .txDMA_Stream = TELEMETRY_DMA_Stream_TX, .txDMA_Channel = TELEMETRY_DMA_Channel_TX, +#if defined(TELEMETRY_DMA_Stream_RX) + .rxDMA = TELEMETRY_DMA, + .rxDMA_Stream = TELEMETRY_DMA_Stream_RX, + .rxDMA_Channel = TELEMETRY_DMA_Channel_RX, +#else .rxDMA = nullptr, .rxDMA_Stream = 0, .rxDMA_Channel = 0, +#endif #if defined(STM32H7) || (STM32H7RS) .set_input = nullptr, #else diff --git a/radio/src/targets/common/arm/stm32/stm32_serial_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_serial_driver.cpp index 99050e8a6..d38575340 100644 --- a/radio/src/targets/common/arm/stm32/stm32_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_serial_driver.cpp @@ -337,7 +337,22 @@ static void stm32_serial_send_byte(void* ctx, uint8_t c) } } -#define IS_CCM_RAM(addr) (((uint32_t)(addr) & (uint32_t)0xFFF00000) == 0x10000000) +#if defined(STM32F4) +extern uint32_t _sram; +extern uint32_t _eram; +#define _IS_DMA_BUFFER(addr) \ + ((intptr_t)(addr) >= (intptr_t)&_sram && (intptr_t)(addr) <= (intptr_t)&_eram) +#elif defined(STM32H7) || defined(STM32H7RS) +extern uint32_t _s_dram; +extern uint32_t _e_dram; +#define _IS_DMA_BUFFER(addr) \ + ((intptr_t)(addr) >= (intptr_t)&_s_dram && \ + (intptr_t)(addr) <= (intptr_t)&_e_dram) +#else +#define _IS_DMA_BUFFER(addr) (true) +#endif + +#define _IS_ALIGNED(addr) (((intptr_t)(addr) & 3U) == 0U) static void stm32_serial_send_buffer(void* ctx, const uint8_t* data, uint32_t size) { @@ -347,10 +362,7 @@ static void stm32_serial_send_buffer(void* ctx, const uint8_t* data, uint32_t si // try TX DMA first auto sp = st->sp; auto usart = sp->usart; - if (usart->txDMA && !IS_CCM_RAM(data)) { -#if defined(STM32H7) || defined(STM32H7RS) - SCB_CleanDCache_by_Addr((void*)data, size); -#endif + if (usart->txDMA && _IS_DMA_BUFFER(data) && _IS_ALIGNED(data)) { stm32_usart_send_buffer(usart, data, size); return; } 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 f5e287168..cae16721f 100644 --- a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp @@ -28,6 +28,12 @@ #include +#if defined(STM32H7) || defined(STM32H7RS) + #define IS_HALF_DUPLEX(usart) ((usart)->set_input || (usart)->rxGPIO == GPIO_UNDEF) +#else + #define IS_HALF_DUPLEX(usart) ((usart)->set_input) +#endif + // WARNING: // // NVIC_GetEnableIRQ is stolen from "${THIRDPARTY_DIR}/CMSIS/Include/core_cm4.h". @@ -66,19 +72,19 @@ static void _enable_tx_dma_irq(const stm32_usart_t* usart) static inline void _half_duplex_input(const stm32_usart_t* usart) { - if (usart->set_input) { - usart->set_input(true); + if (usart->set_input) usart->set_input(true); + + if (IS_HALF_DUPLEX(usart)) { LL_USART_EnableDirectionRx(usart->USARTx); - LL_USART_DisableDirectionTx(usart->USARTx); } } static inline void _half_duplex_output(const stm32_usart_t* usart) { - if (usart->set_input) { - usart->set_input(false); + if (usart->set_input) usart->set_input(false); + + if (IS_HALF_DUPLEX(usart)) { LL_USART_DisableDirectionRx(usart->USARTx); - LL_USART_EnableDirectionTx(usart->USARTx); } } @@ -370,27 +376,25 @@ void stm32_usart_deinit_rx_dma(const stm32_usart_t* usart) void stm32_usart_rx_inversion(const stm32_usart_t* usart, bool on) { bool enableUart = false; - if(LL_USART_IsEnabled(usart->USARTx)) - { + if (LL_USART_IsEnabled(usart->USARTx)) { LL_USART_Disable(usart->USARTx); enableUart = true; } - LL_USART_SetRXPinLevel(usart->USARTx, on?LL_USART_RXPIN_LEVEL_INVERTED:LL_USART_RXPIN_LEVEL_STANDARD); - if(enableUart) - LL_USART_Enable(usart->USARTx); + LL_USART_SetRXPinLevel(usart->USARTx, on ? LL_USART_RXPIN_LEVEL_INVERTED + : LL_USART_RXPIN_LEVEL_STANDARD); + if (enableUart) LL_USART_Enable(usart->USARTx); } void stm32_usart_tx_inversion(const stm32_usart_t* usart, bool on) { bool enableUart = false; - if(LL_USART_IsEnabled(usart->USARTx)) - { + if (LL_USART_IsEnabled(usart->USARTx)) { LL_USART_Disable(usart->USARTx); enableUart = true; } - LL_USART_SetTXPinLevel(usart->USARTx, on?LL_USART_TXPIN_LEVEL_INVERTED:LL_USART_TXPIN_LEVEL_STANDARD); - if(enableUart) - LL_USART_Enable(usart->USARTx); + LL_USART_SetTXPinLevel(usart->USARTx, on ? LL_USART_TXPIN_LEVEL_INVERTED + : LL_USART_TXPIN_LEVEL_STANDARD); + if (enableUart) LL_USART_Enable(usart->USARTx); } #endif @@ -424,6 +428,24 @@ bool stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params) gpio_init_af(usart->txGPIO, af, _get_pin_speed(params->baudrate)); } + bool half_duplex = usart->set_input; + +#if defined(STM32H7) || defined(STM32H7RS) + bool one_wire_half_duplex = + usart->rxGPIO == GPIO_UNDEF && (params->direction & ETX_Dir_RX); + + if (one_wire_half_duplex) { + if (params->direction & ETX_Dir_TX) { + LL_GPIO_SetPinPull( + gpio_get_port(usart->txGPIO), 1 << gpio_get_pin(usart->txGPIO), + params->polarity ? LL_GPIO_PULL_UP : LL_GPIO_PULL_DOWN); + } + LL_USART_ConfigHalfDuplexMode(usart->USARTx); + } + + half_duplex = half_duplex || one_wire_half_duplex; +#endif + LL_USART_InitTypeDef usartInit; LL_USART_StructInit(&usartInit); @@ -459,22 +481,15 @@ bool stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params) usartInit.TransferDirection |= LL_USART_DIRECTION_TX; LL_USART_Init(usart->USARTx, &usartInit); -#if defined(STM32H7) || defined (STM32H7RS) - if(usart->rxGPIO == GPIO_UNDEF) - { - LL_USART_EnableHalfDuplex(usart->USARTx); - } -#endif LL_USART_Enable(usart->USARTx); - if (params->direction & ETX_Dir_TX) { // Enable TX DMA request if (usart->txDMA) { LL_USART_EnableDMAReq_TX(usart->USARTx); // 2-wire half-duplex: setup TX DMA IRQ - if (usart->set_input && (int32_t)(usart->txDMA_IRQn) >= 0) { + if (half_duplex && (int32_t)(usart->txDMA_IRQn) >= 0) { _enable_tx_dma_irq(usart); } } @@ -487,8 +502,9 @@ bool stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params) } // half-duplex: start in input mode - if (usart->set_input) + if (half_duplex) { _half_duplex_input(usart); + } } if (((params->direction & ETX_Dir_TX) && !usart->txDMA) || @@ -528,7 +544,7 @@ void stm32_usart_send_byte(const stm32_usart_t* usart, uint8_t byte) // TODO: split into 2 steps to avoid blocking on send while (!LL_USART_IsActiveFlag_TXE(usart->USARTx)); - if (usart->set_input) { + if (IS_HALF_DUPLEX(usart)) { _half_duplex_output(usart); // switch back to input after TC @@ -573,8 +589,9 @@ void stm32_usart_send_buffer(const stm32_usart_t* usart, const uint8_t * data, u LL_DMA_Init(usart->txDMA, usart->txDMA_Stream, &dmaInit); - if (usart->set_input && (int32_t)(usart->txDMA_IRQn) >= 0) { + if (IS_HALF_DUPLEX(usart) && (int32_t)(usart->txDMA_IRQn) >= 0) { LL_DMA_EnableIT_TC(usart->txDMA, usart->txDMA_Stream); + LL_USART_ClearFlag_TC(usart->USARTx); } LL_DMA_EnableStream(usart->txDMA, usart->txDMA_Stream); #endif // !STM32H7RS @@ -779,13 +796,5 @@ void stm32_usart_tx_dma_isr(const stm32_usart_t* usart) return; auto USARTx = usart->USARTx; - - // clear TC flag before enabling USART TC interrupt: - // -> TC flag will be re-triggered once the last byte which has - // just been transfered from DMA to USART will be transmitted, - // thus triggering TELEMETRY_USART_IRQHandler(), which will - // switch from output to input mode. - // - LL_USART_ClearFlag_TC(USARTx); LL_USART_EnableIT_TC(USARTx); }