Skip to content

fix(uart): HardwareSerial begin() causes Infinite Loop #2785

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions libraries/SrcWrapper/inc/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,12 @@ void uart_enable_rx(serial_t *obj);

size_t uart_debug_write(uint8_t *data, uint32_t size);

#if defined(UART_PRESCALER_DIV1)
uint32_t calculatePresc(uint32_t pclk, uint32_t baudrate, uint32_t oversampling);
#endif

uint32_t uart_getPCLK(UART_HandleTypeDef *huart);

#endif /* HAL_UART_MODULE_ENABLED && !HAL_UART_MODULE_ONLY */
#ifdef __cplusplus
}
Expand Down
168 changes: 168 additions & 0 deletions libraries/SrcWrapper/src/stm32/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,17 @@ bool uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t par
huart->Init.Mode = UART_MODE_TX_RX;
huart->Init.HwFlowCtl = flow_control;
huart->Init.OverSampling = UART_OVERSAMPLING_16;

/* Configure UART Clock Prescaler */
#if defined(UART_PRESCALER_DIV1)
// Default Value
uint32_t clock_prescaler = UART_PRESCALER_DIV1;

uint32_t pclk = uart_getPCLK(huart);
clock_prescaler = calculatePresc(pclk, baudrate, huart->Init.OverSampling);
huart->Init.ClockPrescaler = clock_prescaler;
#endif

#if defined(UART_ADVFEATURE_NO_INIT)
// Default value
huart->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
Expand Down Expand Up @@ -1415,6 +1426,163 @@ void HAL_UARTEx_WakeupCallback(UART_HandleTypeDef *huart)
serial_t *obj = get_serial_obj(huart);
HAL_UART_Receive_IT(huart, &(obj->recv), 1);
}

/**
* @brief Function called to set the uart clock prescaler
* @param pclk : supplied clock rate to related uart
* @retval uint32_t clock prescaler
*/
#if defined(UART_PRESCALER_DIV1)
uint32_t calculatePresc(uint32_t pclk, uint32_t baudrate, uint32_t oversampling)
{
static const uint16_t presc_div[12] = {1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256};

uint32_t condition = 0;
if (oversampling == UART_OVERSAMPLING_16) {
condition = 16U;
} else {
condition = 8U;
}

for (uint32_t idx = 0; idx < 8; idx++) {
uint32_t uartclk = pclk / presc_div[idx];
uint32_t brr = 0;
if (oversampling == UART_OVERSAMPLING_16) {
brr = (uartclk + (baudrate / 2U)) / baudrate;
} else {
brr = ((2U * uartclk) + (baudrate / 2U)) / baudrate;
}

if (brr >= condition && brr <= 0xFFFU) {
return UART_PRESCALER_DIV1 + idx;
}
}
return UART_PRESCALER_DIV1;
}
#endif

/**
* @brief Function called to get the clock source frequency of the uart
* @param huart : uart handle structure
* @retval uint32_t clock source frequency
*/
uint32_t uart_getPCLK(UART_HandleTypeDef *huart)
{
#if defined(LPUART1)
if (huart->Instance == LPUART1) {
#if defined(STM32H5) || defined(STM32U3) || defined(STM32U5)
return HAL_RCC_GetPCLK3Freq();
#elif defined(STM32H7)
uint32_t sysclk = HAL_RCC_GetSysClockFreq();
#if defined(STM32H7A3xx) || defined (STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) || defined(STM32H7B0xx) || defined(STM32H7B0xxQ)
uint32_t prescaler = (RCC->SRDCFGR & RCC_SRDCFGR_SRDPPRE) >> RCC_SRDCFGR_SRDPPRE_Pos;
#else
uint32_t prescaler = (RCC->D3CFGR & RCC_D3CFGR_D3PPRE) >> RCC_D3CFGR_D3PPRE_Pos;
#endif

uint32_t apb4 = 1;

switch (prescaler) {
case 0b000: prescaler = 1; break;
case 0b100: prescaler = 2; break;
case 0b101: prescaler = 4; break;
case 0b110: prescaler = 8; break;
case 0b111: prescaler = 16; break;
default: break;
}

return (sysclk / prescaler);
#elif defined(STM32G4) || defined(STM32L4) || defined(STM32L5) || defined(STM32WB)
return HAL_RCC_GetPCLK1Freq();
#elif defined(STM32WL)
return HAL_RCC_GetPCLK2Freq();
#elif defined(STM32WBA)
return HAL_RCC_GetPCLK7Freq();
#endif
}
#endif

#if defined(LPUART2)
if (huart->Instance == LPUART2) {
return HAL_RCC_GetPCLK1Freq();
}
#endif

#if defined(LPUART3)
if (huart->Instance == LPUART3) {
return HAL_RCC_GetPCLK1Freq();
}
#endif

#if defined(STM32F0) || defined(STM32G0) || defined(STM32L0) || defined(STM32C0) \
|| defined(STM32WB)
return HAL_RCC_GetPCLK1Freq();
#endif

#if defined(STM32WB0)
uint32_t sysclk = HAL_RCC_GetSysClockFreq();
uint32_t ppre2 = (RCC->CFGR & RCC_CFGR_CLKSYSDIV) >> RCC_CFGR_CLKSYSDIV_Pos;
uint32_t apb2_div = 1;

switch (ppre2) {
case 0b000: apb2_div = 1; break;
case 0b100: apb2_div = 2; break;
case 0b101: apb2_div = 4; break;
case 0b110: apb2_div = 8; break;
case 0b111: apb2_div = 16; break;
default: break;
}
return (sysclk / apb2_div);
#endif

#if defined(STM32WL)
return HAL_RCC_GetPCLK2Freq();
#endif

#if defined(STM32H7)
if (huart->Instance == USART1
#if defined(USART10)
|| huart->Instance == USART10
#endif
#if defined(USART6)
|| huart->Instance == USART6
#endif
#if defined(UART9)
|| huart->Instance == UART9
#endif
) {
return HAL_RCC_GetPCLK2Freq();
}
return HAL_RCC_GetPCLK1Freq();
#endif

#if defined(STM32MP1)
if (huart->Instance == USART1) {
return HAL_RCC_GetPCLK5Freq();
} else if (huart->Instance == USART6) {
return HAL_RCC_GetPCLK2Freq();
} else {
return HAL_RCC_GetPCLK1Freq();
}
#endif

#if defined(STM32F7) || defined(STM32F2) || defined(STM32F4) || defined(STM32F1) \
|| defined(STM32U3) || defined(STM32F3) || defined(STM32H5) || defined(STM32G4) \
|| defined(STM32L4) || defined(STM32L5) || defined(STM32WBA) || defined(STM32U5) \
|| defined(STM32L1)
if (huart->Instance == USART1
#if defined(USART6) && !defined(STM32H5) && !defined(STM32U5)
|| huart->Instance == USART6
#endif
) {
return HAL_RCC_GetPCLK2Freq();
}
return HAL_RCC_GetPCLK1Freq();
#endif

return 0;
}

#endif /* HAL_UART_MODULE_ENABLED && !HAL_UART_MODULE_ONLY */

#ifdef __cplusplus
Expand Down