How to change the UART baud rate after running on STM32 board?
Asked Answered
I

5

8

I'm using STM32F746ZG and use five UARTs. All UARTs are working fine. Can someone tell me the procedure to change the baud rate on the USART once it has already been initialized? I'm using USART6 and initialized with 9600 baud rate. After booting, there is no any communication through USART. I want to change the baud rate from 9600 to 57600 or 115200. For this changing, I called HAL_UART_DeInit() and MX_USART6_UART_Init_57600() but it doesn't work. If I didn't change the baud rate, it works fine. But if I change the baud rate, I can't receive the data through USART. If somebody knows the solution, please let me know.

The followings are my code.

int main(void)
{
  HAL_Init();

  SystemClock_Config();


  MX_UART7_Init();
  MX_UART8_Init();
  MX_USART2_UART_Init();
  MX_USART3_UART_Init();
  MX_USART6_UART_Init();

}

void MX_USART6_UART_Init(void)
{
  huart6.Instance = USART6;
  huart6.Init.BaudRate = 9600;
  huart6.Init.WordLength = UART_WORDLENGTH_8B;
  huart6.Init.StopBits = UART_STOPBITS_1;
  huart6.Init.Parity = UART_PARITY_NONE;
  huart6.Init.Mode = UART_MODE_TX_RX;
  huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart6.Init.OverSampling = UART_OVERSAMPLING_16;
  huart6.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart6.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart6) != HAL_OK)
  {
    Error_Handler();
  }
}

void MX_USART6_UART_Init_57600(void)
{
  huart6.Instance = USART6;
  huart6.Init.BaudRate = 57600; // change from 9600 to 57600
  huart6.Init.WordLength = UART_WORDLENGTH_8B;
  huart6.Init.StopBits = UART_STOPBITS_1;
  huart6.Init.Parity = UART_PARITY_NONE;
  huart6.Init.Mode = UART_MODE_TX_RX;
  huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart6.Init.OverSampling = UART_OVERSAMPLING_16;
  huart6.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart6.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart6) != HAL_OK)
  {
    Error_Handler();
  }
}

int Change_UART(void)
{
  HAL_UART_DeInit(&huart6);
  MX_USART6_UART_Init_57600();

}

I called Change_UART() but it doesn't work.

Isotron answered 31/7, 2019 at 4:44 Comment(3)
What happens if you initialize it with 57600 baud directly? (without initializing it with 9600 baud first) Does it work?Bromine
Hi. I resolved this issue. The problem was I didn't call HAL_UART_Receive_IT() function again. If I call this function once again after change the parameters. It works fine. So I can change the baud rate, stop bit, parity bit any time. The following is finial solution. int Change_UART(void) { HAL_UART_DeInit(&huart6); MX_USART6_UART_Init_57600(); HAL_UART_Receive_IT(&huart6, (uint8_t*)uart_rx_data_6, 1); } The upper function is simple code. I made some complex code for five UARTs to change the baud rate, parity bit, stop bit, and so one. Thank you. Bye.~Isotron
@Isotron You can answer your own question. It will be available as an answered question as a future reference for other developers.Baskerville
A
13

Your question should be: how to change the bautrate using the bloatware HAL?

I do not know.

But it can be archived in 3 lines of the simple code.

USART6 -> CR1 &= ~(USART_CR1_UE);
USART6 -> BRR = NEWVALUE;
USART6 -> CR1 |= USART_CR1_UE;
Act answered 21/11, 2019 at 8:19 Comment(0)
M
6

For changing baudrate you don't need to reset UART peripheral, just stop any active transfers (polling/IT/DMA). I use a mix of both:

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

Where UART_BRR_SAMPLING8() is a macro from stm32f4xx_hal_uart.h and HAL_RCC_GetPCLK2Freq() function comes from _hal_rcc.c.

This way I don't have to calculate BRR values manually, nor execute the whole initialization procedure, which actually toggles GPIO states, thus generating noise on serial line for whatever is sitting on other end of it.

Madelle answered 14/7, 2020 at 11:51 Comment(0)
S
5

You have to abort all running HAL_UART funttions, then de-initialize the uart, change the baudrate init value and initialize it again:

  1. HAL_UART_Abort_IT(&huart1);
    
  2. HAL_UART_DeInit(&huart1);
    
  3. huart1.Init.BaudRate = 57600;
    
  4. if (HAL_UART_Init(&huart1) != HAL_OK) {
        Error_Handler();
    }
    
  5. if (HAL_UART_Receive_IT(&huart1, BUFFER, YOUR_BUFFER_SIZE) != HAL_OK) {
        Error_Handler();
    }
    
Stubborn answered 30/3, 2021 at 15:4 Comment(0)
D
0

Originally I was really excited by P__J__'s simple answer, but it turns out you can't just put the desired baud rate into BRR - it has to be a function of oversampling and the clock rate.

I used more or less the same method but with "LL_USART_SetBaudRate" to fill the register

Doug answered 14/3, 2020 at 22:9 Comment(0)
U
0

You don't need to de-init anything, but you do need to figure out the new value given the UART configuration.

This differs from family to family little, so here it is for the U5 family. Other families will be similar:

bool UART_change_baud(UART_HandleTypeDef* hUart, uint32_t newBaudRate)
{
  uint32_t clocksource;
  uint32_t pclk;
  uint32_t usartdiv;
  uint32_t minBRR, maxBRR;

  //Get the prescaler from where SetConfig puts it.
  uint32_t prescaler = READ_REG(hUart->Instance->PRESC) & USART_PRESC_PRESCALER;

  //Get pclk by doing as UART_SetConfig() does in stm32_u5xx_hal_uart.c does.
  UART_GETCLOCKSOURCE(hUart, clocksource);
  pclk = HAL_RCCEx_GetPeriphCLKFreq(clocksource);   /* Retrieve frequency clock */

  if(IS_LPUART_INSTANCE(hUart->Instance)) //equiv. to the private UART_INSTANCE_LOWPOWER(hUart))
  {
    //Unfortunately these are not public, so c&p.
    minBRR = 0x00000300U;  /* LPUART BRR minimum authorized value */
    maxBRR = 0x000FFFFFU;  /* LPUART BRR maximum authorized value */
    usartdiv = (uint32_t)(UART_DIV_LPUART(pclk, newBaudRate, prescaler));
  }
  else
  {
    minBRR = 0x10U;        /* UART BRR minimum authorized value */
    maxBRR = 0x0000FFFFU;  /* UART BRR maximum authorized value */

    if((READ_REG(hUart->Instance->CR1) & USART_CR1_OVER8) == USART_CR1_OVER8)
      usartdiv = (uint32_t)(UART_DIV_SAMPLING8(pclk, newBaudRate, prescaler));
    else
      usartdiv = (uint32_t)(UART_DIV_SAMPLING16(pclk, newBaudRate, prescaler));
  }

  if(usartdiv < minBRR || usartdiv > maxBRR)
    return false;

  //Finally, we have the register value. The only thing that needs to be does
  //is to clear the UE (uart enable) bit while you update the register.
  CLEAR_BIT(hUart->Instance->CR1, USART_CR1_UE);
  hUart->Instance->BRR = usartdiv;
  SET_BIT(hUart->Instance->CR1, USART_CR1_UE);

  return true;
}

Of course, any transaction in progress will be corrupted, but otherwise the UART will just pick up where it left off. No need to restart DMA, no need to enable transmission. Just go.

Undertook answered 3/9 at 5:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.