cancel
Showing results for 
Search instead for 
Did you mean: 

Bug in uart init function when setting baudrate register (BRR). In file /Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_uart.c at line 3201, it calculates usartdiv casting it to uint16_t and then checks if it is less than 0xffff.

Lmoio.1
Senior

In this way, error never occurs leading to wrong baudrates.

    if (pclk != 0U)
    {
      /* USARTDIV must be greater than or equal to 0d16 */
      usartdiv = (uint16_t)(UART_DIV_SAMPLING16(pclk, huart->Init.BaudRate, huart->Init.ClockPrescaler));
      if ((usartdiv >= UART_BRR_MIN) && (usartdiv <= UART_BRR_MAX))
      {
        huart->Instance->BRR = usartdiv;
      }
      else
      {
        ret = HAL_ERROR;
      }
    }

Cast to (uint16_t) should be removed.

1 ACCEPTED SOLUTION

Accepted Solutions

Hi @Lmoio.1​ ,

The cast on (uint16_t) is causing issues in some use cases.

For that, the cast won't be deleted but modified to be (uint32_t) instead of (uint16_t).

- usartdiv = (uint16_t)(UART_DIV_SAMPLING16(pclk, huart->Init.BaudRate, huart->Init.ClockPrescaler));
+ usartdiv = (uint32_t)(UART_DIV_SAMPLING16(pclk, huart->Init.BaudRate, huart->Init.ClockPrescaler));

When your question is answered, please close this topic by choosing Select as Best. So that more Community members can benefit from this discussion.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

View solution in original post

6 REPLIES 6
Imen.D
ST Employee

Hello @Lmoio.1​ ,

Please clarify the case where the uint16_t cast is a problem!

BRR register in UART IP is only 16 bit wide.

If clock, baudrate and prescaler values are correct, casting the value computed by calling UART_DIV_SAMPLING16 or UART_DIV_SAMPLING8 macros should not affect the result.

If cast alters the result (result > 0xFFFF), then the combination is not possible anyway (next check against UART_BRR_MAX will fail).

Can you please provide your clock/baudrate/prescaler value, and indicate how the BRR setting is wrongly computed due to the uint16 cast ?

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Lmoio.1
Senior

Hi @Imen DAHMEN​ ,

this was my configuration:

Clock 170MHz,

Prescaler UART_PRESCALER_DIV1 so 0,

Oversampling UART_OVERSAMPLING_16,

Baudrate expected 2400.

The BRR register for oversampling 16 is computed as follows: BRR = (Clock/prescaler)/baudrate rounded up. So (170000000/1)/2400 = 70834.

Obviously 70834 is greater than 0xFFFF and the check should fail, going in the return HAL_ERROR; branch.

However with the cast uint16_t, 70834 becomes 5298 that is lower than 0xFFFF, thus the initialization of uart completes, without giving any error.

The problem was discovered by looking at the signals with an oscilloscope.

Lidia

> If cast alters the result (result > 0xFFFF), then the combination is not possible anyway (next check against UART_BRR_MAX will fail).

That's the thing - the cast already limits the usartdiv value to a max of 0xFFFF and the test against the UART_BRR_MAX will never fail. Lidia is right on this! Also the line 3160 has the same problem and at line 3118 the cast is useless because it casts to the same type of usartdiv variable.

Hi @Lmoio.1​ ,

The cast on (uint16_t) is causing issues in some use cases.

For that, the cast won't be deleted but modified to be (uint32_t) instead of (uint16_t).

- usartdiv = (uint16_t)(UART_DIV_SAMPLING16(pclk, huart->Init.BaudRate, huart->Init.ClockPrescaler));
+ usartdiv = (uint32_t)(UART_DIV_SAMPLING16(pclk, huart->Init.BaudRate, huart->Init.ClockPrescaler));

When your question is answered, please close this topic by choosing Select as Best. So that more Community members can benefit from this discussion.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Lmoio.1
Senior

Thank you!

Lidia

You are welcome :)

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen