Reputation: 418
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.
Upvotes: 8
Views: 19585
Reputation: 4169
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.
Upvotes: 0
Reputation: 51
You have to abort all running HAL_UART
funttions, then de-initialize the uart, change the baudrate init value and initialize it again:
HAL_UART_Abort_IT(&huart1);
HAL_UART_DeInit(&huart1);
huart1.Init.BaudRate = 57600;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
if (HAL_UART_Receive_IT(&huart1, BUFFER, YOUR_BUFFER_SIZE) != HAL_OK) {
Error_Handler();
}
Upvotes: 5
Reputation: 399
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.
Upvotes: 6
Reputation: 194
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
Upvotes: 0
Reputation: 67835
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;
Upvotes: 13