Skip to content

Commit

Permalink
Fix STM32H7 LPUART clock source being incorrect for higher baudrates (#…
Browse files Browse the repository at this point in the history
…263)

* Fix STM32H7 LPUART clock source incorrect for higher baudrates

* Add comment
  • Loading branch information
multiplemonomials authored Apr 5, 2024
1 parent 8926deb commit fbaec0c
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 37 deletions.
73 changes: 44 additions & 29 deletions targets/TARGET_STM/serial_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#define USE_LPUART_CLK_LSE 0x01
#define USE_LPUART_CLK_PCLK1 0x02
#define USE_LPUART_CLK_HSI 0x04
#define USE_LPUART_CLK_PCLK3 0x08
#define USE_LPUART_CLK_SYSCLK 0x10

int stdio_uart_inited = 0; // used in platform/mbed_board.c and platform/mbed_retarget.cpp
serial_t stdio_uart;
Expand Down Expand Up @@ -376,8 +378,8 @@ void serial_baud(serial_t *obj, int baudrate)
if (obj_s->uart == LPUART_1) {
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPUART1;
#if ((MBED_CONF_TARGET_LPUART_CLOCK_SOURCE) & USE_LPUART_CLK_LSE)
if (baudrate <= 9600) {
#if ((MBED_CONF_TARGET_LPUART_CLOCK_SOURCE) & USE_LPUART_CLK_LSE) && MBED_CONF_TARGET_LSE_AVAILABLE
if (baudrate <= (int)(LSE_VALUE / 3)) {
// Enable LSE in case it is not already done
if (!__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY)) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
Expand Down Expand Up @@ -417,46 +419,50 @@ void serial_baud(serial_t *obj, int baudrate)
return;
}
#endif
#if ((MBED_CONF_TARGET_LPUART_CLOCK_SOURCE) & USE_LPUART_CLK_PCLK3)
#if ((MBED_CONF_TARGET_LPUART_CLOCK_SOURCE) & USE_LPUART_CLK_PCLK3) && defined(RCC_LPUART1CLKSOURCE_PCLK3)
PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK3;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
if (init_uart(obj) == HAL_OK) {
return;
}
#endif
#if ((MBED_CONF_TARGET_LPUART_CLOCK_SOURCE) & USE_LPUART_CLK_HSI)
// Enable HSI in case it is not already done
if (!__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY)) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_OFF;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
#if defined(DUAL_CORE) && (TARGET_STM32H7)
while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
if (baudrate <= (int)(HSI_VALUE / 3)) {
// Enable HSI in case it is not already done
if (!__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY)) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_OFF;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
#if defined(DUAL_CORE) && (TARGET_STM32H7)
while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
}
#endif /* DUAL_CORE */
HAL_RCC_OscConfig(&RCC_OscInitStruct);
#if defined(DUAL_CORE) && (TARGET_STM32H7)
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, HSEM_CR_COREID_CURRENT);
#endif /* DUAL_CORE */
}
#endif /* DUAL_CORE */
HAL_RCC_OscConfig(&RCC_OscInitStruct);
#if defined(DUAL_CORE) && (TARGET_STM32H7)
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, HSEM_CR_COREID_CURRENT);
#endif /* DUAL_CORE */
}
// Keep it to verify if HAL_RCC_OscConfig didn't exit with a timeout
if (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY)) {
PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_HSI;
// Keep it to verify if HAL_RCC_OscConfig didn't exit with a timeout
if (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY)) {
PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_HSI;
#if defined(DUAL_CORE) && (TARGET_STM32H7)
while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
}
while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
}
#endif /* DUAL_CORE */
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
#if defined(DUAL_CORE) && (TARGET_STM32H7)
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, HSEM_CR_COREID_CURRENT);
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, HSEM_CR_COREID_CURRENT);
#endif /* DUAL_CORE */
if (init_uart(obj) == HAL_OK) {
return;
if (init_uart(obj) == HAL_OK) {
return;
}
}
}
#endif

#if ((MBED_CONF_TARGET_LPUART_CLOCK_SOURCE) & USE_LPUART_CLK_SYSCLK)
// Last chance using SYSCLK
PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_SYSCLK;
#if defined(DUAL_CORE) && (TARGET_STM32H7)
Expand All @@ -467,6 +473,15 @@ void serial_baud(serial_t *obj, int baudrate)
#if defined(DUAL_CORE) && (TARGET_STM32H7)
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, HSEM_CR_COREID_CURRENT);
#endif /* DUAL_CORE */

if (init_uart(obj) == HAL_OK) {
return;
}
else
#endif
{
debug("Cannot initialize LPUART with baud rate %u using any enabled clock source\n", baudrate);
}
}
#endif /* LPUART1_BASE */

Expand Down Expand Up @@ -653,8 +668,8 @@ HAL_StatusTypeDef init_uart(serial_t *obj)

#if defined(LPUART1_BASE)
if (huart->Instance == LPUART1) {
if (obj_s->baudrate <= 9600) {
#if ((MBED_CONF_TARGET_LPUART_CLOCK_SOURCE) & USE_LPUART_CLK_LSE) && defined(USART_CR3_UCESM)
if (obj_s->baudrate <= (int)(LSE_VALUE / 3)) {
#if ((MBED_CONF_TARGET_LPUART_CLOCK_SOURCE) & USE_LPUART_CLK_LSE) && MBED_CONF_TARGET_LSE_AVAILABLE && defined(USART_CR3_UCESM)
HAL_UARTEx_EnableClockStopMode(huart);
#endif
HAL_UARTEx_EnableStopMode(huart);
Expand Down
18 changes: 10 additions & 8 deletions targets/targets.json5
Original file line number Diff line number Diff line change
Expand Up @@ -1203,8 +1203,8 @@
"value": "USE_RTC_CLK_LSE_OR_LSI"
},
"lpuart_clock_source": {
"help": "Define the LPUART clock source. Mask values: USE_LPUART_CLK_LSE, USE_LPUART_CLK_PCLK1, USE_LPUART_CLK_HSI",
"value": "USE_LPUART_CLK_LSE|USE_LPUART_CLK_PCLK1|USE_LPUART_CLK_PCLK3"
"help": "Define the LPUART clock source. LSE clock source will only be used when baudrate is slow (<= LSE freq / 3). Mask values: USE_LPUART_CLK_LSE, USE_LPUART_CLK_PCLK1, USE_LPUART_CLK_PCLK3, USE_LPUART_CLK_HSI, USE_LPUART_CLK_SYSCLK.",
"value": "USE_LPUART_CLK_LSE|USE_LPUART_CLK_PCLK1|USE_LPUART_CLK_PCLK3|USE_LPUART_CLK_SYSCLK"
},
"stdio_uart_tx": {
"help": "default TX STDIO pins is defined in PinNames.h file, but it can be overridden"
Expand Down Expand Up @@ -3186,7 +3186,9 @@
"MBED_TICKLESS"
],
"overrides": {
"lpticker_delay_ticks": 0
"lpticker_delay_ticks": 0,
// Mbed's clock code does not initialize PLL2, so we have to disable USE_LPUART_CLK_PCLK1 here.
"lpuart_clock_source": "USE_LPUART_CLK_LSE|USE_LPUART_CLK_HSI|USE_LPUART_CLK_SYSCLK"
},
"device_has_add": [
"ANALOGOUT",
Expand Down Expand Up @@ -4264,7 +4266,7 @@
"STM32L475xG"
],
"overrides": {
"lpuart_clock_source": "USE_LPUART_CLK_HSI"
"lpuart_clock_source": "USE_LPUART_CLK_HSI|USE_LPUART_CLK_SYSCLK"
},
"macros_add": [
"STM32L475xx",
Expand Down Expand Up @@ -4308,7 +4310,7 @@
"STM32L476xG"
],
"overrides": {
"lpuart_clock_source": "USE_LPUART_CLK_HSI"
"lpuart_clock_source": "USE_LPUART_CLK_HSI|USE_LPUART_CLK_SYSCLK"
},
"macros_add": [
"STM32L476xx",
Expand Down Expand Up @@ -4370,7 +4372,7 @@
"STM32L486xG"
],
"overrides": {
"lpuart_clock_source": "USE_LPUART_CLK_HSI"
"lpuart_clock_source": "USE_LPUART_CLK_HSI|USE_LPUART_CLK_SYSCLK"
},
"macros_add": [
"STM32L486xx",
Expand Down Expand Up @@ -4420,7 +4422,7 @@
"STM32L496xG"
],
"overrides": {
"lpuart_clock_source": "USE_LPUART_CLK_HSI"
"lpuart_clock_source": "USE_LPUART_CLK_HSI|USE_LPUART_CLK_SYSCLK"
},
"macros_add": [
"STM32L496xx"
Expand Down Expand Up @@ -4781,7 +4783,7 @@
},
"overrides": {
"lpticker_delay_ticks": 0,
"lpuart_clock_source": "USE_LPUART_CLK_HSI"
"lpuart_clock_source": "USE_LPUART_CLK_HSI|USE_LPUART_CLK_SYSCLK"
},
"device_has_add": [
"ANALOGOUT",
Expand Down

0 comments on commit fbaec0c

Please sign in to comment.