From 56b3d5bbb1dc05b240d339e6e41615cc4fd7868c Mon Sep 17 00:00:00 2001 From: richardclli Date: Tue, 30 Jul 2024 09:47:50 +0800 Subject: [PATCH] fix: uart auto oversampling calculation (#5319) --- radio/src/hal/module_port.cpp | 4 - radio/src/hal/serial_driver.h | 1 - .../common/arm/stm32/stm32_usart_driver.cpp | 129 +++++++++--------- 3 files changed, 65 insertions(+), 69 deletions(-) diff --git a/radio/src/hal/module_port.cpp b/radio/src/hal/module_port.cpp index 839aa1ab8..948054c52 100644 --- a/radio/src/hal/module_port.cpp +++ b/radio/src/hal/module_port.cpp @@ -69,10 +69,6 @@ static bool _init_serial_driver(etx_module_driver_t* d, const etx_module_port_t* // S.PORT specific HW settings if (port->port == ETX_MOD_PORT_SPORT && params->baudrate >= 400000) { - - // enable over-sampling by 8 - if (drv->setHWOption) drv->setHWOption(d->ctx, ETX_HWOption_OVER8); - // one-bit if (g_eeGeneral.uartSampleMode == UART_SAMPLE_MODE_ONEBIT) { if (drv->setHWOption) drv->setHWOption(d->ctx, ETX_HWOption_ONEBIT); diff --git a/radio/src/hal/serial_driver.h b/radio/src/hal/serial_driver.h index da184547d..c91b09b74 100644 --- a/radio/src/hal/serial_driver.h +++ b/radio/src/hal/serial_driver.h @@ -61,7 +61,6 @@ struct etx_serial_callbacks_t { }; enum SerialHWOption { - ETX_HWOption_OVER8, // oversampling by 8 ETX_HWOption_ONEBIT, // one-bit sampling }; 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 315778e55..e79810e5d 100644 --- a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp @@ -185,6 +185,68 @@ static gpio_af_t _get_usart_af(USART_TypeDef* USARTx) return _AF7_USART(USARTx) ? GPIO_AF7 : GPIO_AF8; } +// from stm32f4xx_ll_usart.c +static uint32_t _get_usart_periph_clock(USART_TypeDef* USARTx) +{ + uint32_t periphclk = LL_RCC_PERIPH_FREQUENCY_NO; + LL_RCC_ClocksTypeDef rcc_clocks; + + LL_RCC_GetSystemClocksFreq(&rcc_clocks); + if (USARTx == USART1) { + periphclk = rcc_clocks.PCLK2_Frequency; + } else if (USARTx == USART2) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#if defined(USART3) + else if (USARTx == USART3) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* USART3 */ +#if defined(USART6) + else if (USARTx == USART6) { + periphclk = rcc_clocks.PCLK2_Frequency; + } +#endif /* USART6 */ +#if defined(UART4) + else if (USARTx == UART4) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* UART4 */ +#if defined(UART5) + else if (USARTx == UART5) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* UART5 */ +#if defined(UART7) + else if (USARTx == UART7) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* UART7 */ +#if defined(UART8) + else if (USARTx == UART8) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* UART8 */ +#if defined(UART9) + else if (USARTx == UART9) { + periphclk = rcc_clocks.PCLK2_Frequency; + } +#endif /* UART9 */ +#if defined(UART10) + else if (USARTx == UART10) { + periphclk = rcc_clocks.PCLK2_Frequency; + } +#endif /* UART10 */ + + return periphclk; +} + +static uint32_t _calc_best_oversampling(USART_TypeDef* USARTx, uint32_t baudrate) +{ + auto periphclk = _get_usart_periph_clock(USARTx); + return (periphclk < (baudrate << 4)) ? LL_USART_OVERSAMPLING_8 : LL_USART_OVERSAMPLING_16; +} + void stm32_usart_init_rx_dma(const stm32_usart_t* usart, const void* buffer, uint32_t length) { if (!usart->rxDMA) return; @@ -283,6 +345,7 @@ bool stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params) LL_USART_InitTypeDef usartInit; LL_USART_StructInit(&usartInit); + usartInit.OverSampling = _calc_best_oversampling(usart->USARTx, params->baudrate); usartInit.BaudRate = params->baudrate; usartInit.Parity = LL_USART_PARITY_NONE; usartInit.DataWidth = LL_USART_DATAWIDTH_8B; @@ -490,62 +553,6 @@ void stm32_usart_enable_rx(const stm32_usart_t* usart) _half_duplex_input(usart); } -// from stm32f4xx_ll_usart.c -static uint32_t _get_usart_periph_clock(USART_TypeDef* USARTx) -{ - uint32_t periphclk = LL_RCC_PERIPH_FREQUENCY_NO; - LL_RCC_ClocksTypeDef rcc_clocks; - - LL_RCC_GetSystemClocksFreq(&rcc_clocks); - if (USARTx == USART1) { - periphclk = rcc_clocks.PCLK2_Frequency; - } else if (USARTx == USART2) { - periphclk = rcc_clocks.PCLK1_Frequency; - } -#if defined(USART3) - else if (USARTx == USART3) { - periphclk = rcc_clocks.PCLK1_Frequency; - } -#endif /* USART3 */ -#if defined(USART6) - else if (USARTx == USART6) { - periphclk = rcc_clocks.PCLK2_Frequency; - } -#endif /* USART6 */ -#if defined(UART4) - else if (USARTx == UART4) { - periphclk = rcc_clocks.PCLK1_Frequency; - } -#endif /* UART4 */ -#if defined(UART5) - else if (USARTx == UART5) { - periphclk = rcc_clocks.PCLK1_Frequency; - } -#endif /* UART5 */ -#if defined(UART7) - else if (USARTx == UART7) { - periphclk = rcc_clocks.PCLK1_Frequency; - } -#endif /* UART7 */ -#if defined(UART8) - else if (USARTx == UART8) { - periphclk = rcc_clocks.PCLK1_Frequency; - } -#endif /* UART8 */ -#if defined(UART9) - else if (USARTx == UART9) { - periphclk = rcc_clocks.PCLK2_Frequency; - } -#endif /* UART9 */ -#if defined(UART10) - else if (USARTx == UART10) { - periphclk = rcc_clocks.PCLK2_Frequency; - } -#endif /* UART10 */ - - return periphclk; -} - uint32_t stm32_usart_get_baudrate(const stm32_usart_t* usart) { auto periphclk = _get_usart_periph_clock(usart->USARTx); @@ -560,7 +567,8 @@ uint32_t stm32_usart_get_baudrate(const stm32_usart_t* usart) void stm32_usart_set_baudrate(const stm32_usart_t* usart, uint32_t baudrate) { auto periphclk = _get_usart_periph_clock(usart->USARTx); - auto oversampling = LL_USART_GetOverSampling(usart->USARTx); + auto oversampling = _calc_best_oversampling(usart->USARTx, baudrate); + LL_USART_SetOverSampling(usart->USARTx, oversampling); #if defined(LL_USART_PRESCALER_DIV1) LL_USART_SetBaudRate(usart->USARTx, periphclk, LL_USART_PRESCALER_DIV1, oversampling, baudrate); #else @@ -571,13 +579,6 @@ void stm32_usart_set_baudrate(const stm32_usart_t* usart, uint32_t baudrate) void stm32_usart_set_hw_option(const stm32_usart_t* usart, uint32_t option) { switch(option) { - case ETX_HWOption_OVER8: { - // BRR depends on oversampling as well, so we must - // re-compute the baudrate as well. - auto baudrate = stm32_usart_get_baudrate(usart); - LL_USART_SetOverSampling(usart->USARTx, LL_USART_OVERSAMPLING_8); - stm32_usart_set_baudrate(usart, baudrate); - } break; case ETX_HWOption_ONEBIT: LL_USART_EnableOneBitSamp(usart->USARTx); break;