Skip to main content
C.East2
Associate III
May 24, 2022
Solved

How do I change the Baud rate of a UART/USART whilst running?

  • May 24, 2022
  • 6 replies
  • 12162 views

I've followed some answers from a post here:

https://stackoverflow.com/questions/57283327/how-to-change-the-uart-baud-rate-after-running-on-stm32-board

But still can't seem to get the baud rate to change. Has anyone had any luck trying to dynamically change the baud rate of the UART?

/****************************************************/

USART6 -> CR1 &= ~(USART_CR1_UE);

USART6 -> BRR = NEWVALUE;

USART6 -> CR1 |= USART_CR1_UE;

/****************************************************/

huart.Instance->BRR = UART_BRR_SAMPLING8(HAL_RCC_GetPCLK2Freq(), new_baudrate);

/****************************************************/

HAL_UART_DeInit(instance[bus].handle);

instance[bus].handle->Init.BaudRate = baud;

HAL_UART_Init(instance[bus].handle);

Best answer by C.East2

Here is a follow up and answer to the problem.

The issue was that The UART was part way through a interrupt transmission while I was changing the Baud rate. Having a static variable that keeps track of a message being sent has solved this issue.

6 replies

C.East2
C.East2Author
Associate III
May 24, 2022

I've also tried running the MX code again like below. The HAL_UART_Init doesn't show any errors, but the program seems to crash after this. 

huart4.Instance = UART4;

 huart4.Init.BaudRate = baud;

 huart4.Init.WordLength = UART_WORDLENGTH_8B;

 huart4.Init.StopBits = UART_STOPBITS_1;

 huart4.Init.Parity = UART_PARITY_NONE;

 huart4.Init.Mode = UART_MODE_TX_RX;

 huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;

 huart4.Init.OverSampling = UART_OVERSAMPLING_16;

 if (HAL_UART_Init(&huart4) != HAL_OK)

 {

  Error_Handler();

 }

Andrew Neil
Super User
May 24, 2022

@C.East2​  "the program seems to crash"

What, exactly, do you mean by that?

  • Hard Fault?
  • Stuck in a loop somewhere?
  • other?

as @Javier Muñoz​ suggests, if the instance[bus].handle is wrong, that could cause such issues...

0693W000008xsqBQAQ.png@C.East2

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
C.East2
C.East2Author
Associate III
May 24, 2022

Sorry about that.

It doesn't hard fault. I'm not sure if it's in a loop somewhere. It's not in syscalls.

Javier1
Principal
May 24, 2022

How sure are you that instance[bus].handle is what you want it to be?

hit me up in https://www.linkedin.com/in/javiermuñoz/
C.East2
C.East2Author
Associate III
May 24, 2022

Certain with the instance[bus].handle. This is correct.

Guenael Cadier
ST Employee
May 24, 2022

Hi @C.East2​ 

If your UART (example UART4), if working properly with baudrate X, you could change baudrate to Y by using the methods you mentioned, especially :

UART_HandleTypeDef huart4; 
...
huart4.Instance = UART4
huart4.Init.BaudRate = X;
HAL_UART_Init(&huart4);
...
HAL_UART_DeInit(&huart4);
huart4.Init.BaudRate = Y;
HAL_UART_Init(&huart4);
...

Please make sure that you provide required content for HAL_UART_MspInit() and HAL_UART_MspDeInit() functions to handle HW resources associated to this UART, as clock source, GPIOs, ...

By default, weak functions are defined with empty bodies for these HAL_UART_MspInit() and HAL_UART_MspDeInit() functions. Please define your owns (it is normally done if you are using STM32CubeMx).

Regards.

Pavel A.
May 24, 2022

@C.East2​ After write to the UART register : USART6 -> CR1 &= ~(USART_CR1_UE);

add read-back to let the write propagate all way to the device (TL;DR this is complicated).

Barrier instructions after write won't harm too :

USART6 -> CR1 &= ~(USART_CR1_UE);
__DSB(); // barrier
(void)(USART6 -> CR1); // read-back
__DMB(); 
 
USART6 -> BRR = NEWVALUE;
__DSB();
(void)(USART6 -> BRR);
__DMB(); 
 
USART6 -> CR1 |= USART_CR1_UE;
__DSB();

Tesla DeLorean
Guru
May 24, 2022

Yeah, I don't know it that's necessary

It's suppose to complete the reads/writes in order, and the read should force the pending writes to complete. The _IO (or volatile) nature of the registers means the compilers not going to fold things.

Where it becomes an issue is the clock cycles between enabling the peripheral (gating the synchronous clock into it), and it being functional. And secondarily when clearing an interrupt state at a peripheral level, and that completing, and then propagating thru the NVIC at the point where the tail-chaining do it or don't do it decision is made.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
C.East2
C.East2AuthorBest answer
Associate III
May 30, 2022

Here is a follow up and answer to the problem.

The issue was that The UART was part way through a interrupt transmission while I was changing the Baud rate. Having a static variable that keeps track of a message being sent has solved this issue.

Associate
June 4, 2024

Hi,

I meet the same problem as you, Have you change baud rate successful?

 

Thanks and brgs