Skip to main content
Associate
September 3, 2026
Solved

Unable to dynamically change baudrate on STM32F405

  • September 3, 2026
  • 17 replies
  • 218 views

I am using STM32CubeIde, No RTOS, USART1, RX DMA (Circular), TX DMA in normal mode with DMA_IT_HT disabled.

I’ve got main loop periodically outputting a simple message on the USART. System appears to hang when commanded to change baud. 

I’ve tried perhaps dozens of variations that have been recommended by “STM32 Sidekick” and Google AI.  Most work with the debugger connected.  None work without the debugger which is making this difficult to troubleshoot.  Sidekick example shown below. 

			// 1. Wait for any ongoing transmissions to finish safely
// This prevents splitting a character mid-air.
while (__HAL_UART_GET_FLAG(huart, UART_FLAG_TC) == RESET)
{
// Optional: Implement a timeout mechanism here
}

// 2. Temporarily de-initialize the UART peripheral
// This turns off the UART but keeps your GPIO and DMA settings intact.
if (HAL_UART_DeInit(huart) != HAL_OK)
{
return; //HAL_ERROR;
}

// 3. Update the baud rate in the configuration structure
huart->Init.BaudRate = new_baudrate;

// 4. Re-initialize the peripheral with the new configuration
// HAL automatically calculates the correct BRR value using PCLK1/PCLK2 internal maps.
if (HAL_UART_Init(huart) != HAL_OK)
{
return; // HAL_ERROR;
}

// apparently not necessary: SET_BIT(huart->Instance->CR1, (USART_CR1_TE | USART_CR1_RE));

// Restart DMA reception (using Receive-to-Idle for variable length message)
HAL_UARTEx_ReceiveToIdle_DMA(saUartControl[id].pHuart,
saUartControl[id].rx_dma_buffer,
sizeof(saUartControl[id].rx_dma_buffer));

return; // HAL_OK;

 

 
Best answer by DownInFront

@Bob S ​@waclawek.jan ​@Andrew Neil ​@Saket_Om ​@LCE 

Thank you all for your time and input here!  I have found and ‘fixed’ the issue.

I found that only during power-up initialization USART6 was throwing a DMA Rx error and my handler was disabling everything instead of trying to recover. 

Still don’t know why the error occurs only during power-up, but the new handler now rides through it and everything keeps on running after that.

17 replies

Bob S
Super User
September 3, 2026

SideKick is incorrect.  Calling HAL_UART_DeInit() will indeed also de-initialize the DMA and GPIO settings.  Also, when using the HAL UART functions, checking the TC bit does not necessarily mean that the HAL layer is done.  Use the TX complete callback for this.

We need more information.  When running with the debugger, do you have any breakpoints set or single stepping? Or do you just load the program and run?  Find some way to indicate what you code is doing without the debugger connected.  Maybe add some GPIO pins that you can toggle.

Not that the program starts differently when running from the debugger.  When debugging (presumably from CubeIDE), the debugger bypasses the startup vector/stack pointer in the interrupt vector table and forces the PC/SP to the initial values in the ELF file.  The debugger also bypasses the built-in bootloader.

Associate
September 3, 2026

Hi Bob,

Thanks for the quick reply and your insights

No breakpoints are set.  I just load and run.  I issue my command from this point and it works.  Cycle power, issue command again and it ‘hangs’.

I just changed my code to wait for HAL_UART_TxCpltCallback() which sets a ‘done’ flag for me.  Issue remains.

Adding GPIO is not possible because of the custom board I’m using.  Starting to think that I need to buy an eval board to troubleshoot this one.

Bob S
Super User
September 3, 2026

>  No breakpoints are set.  I just load and run.  I issue my command from this point and it works.  Cycle power, issue command again and it ‘hangs’.

Well there you go - look at power-on reset events.  Double-check power pins and NRST circuit.  Look at the power rails (including VDDA) when NRST goes high and see if they sag.  As I mentioned earlier, the startup sequence is different with the debugger.  There MAY also be some register that the debugger is touching that your code doesn’t correctly configure.

>  Adding GPIO is not possible because of the custom board I’m using.

If all your GPIO are used (or unused ones are inaccessible), can you temporarily re-purpose existing signals?

> Starting to think that I need to buy an eval board to troubleshoot this one.

The Nucleo boards are pretty inexpensive

[EDIT] And you never answered if the “boot loader” was your own custom one (I suspect yes) or the built-in bootloader.

[EDIT #2] And if your custom bootloader, are you going through your bootloader when using the debugger?  Or just starting with your main app?

Associate
September 3, 2026

HI Jasoncarter32,

Thanks for the response.

HAL_UART_AbortReceive(huart) was recommended by AI for use when using ReceiveToIdle_DMA.  I added it before the HAL TX-complete as you suggested.  Didn’t help.  I then tried HAL_UART_DMAStop(huart) with the same results.

Adding GPIO is not possible because of the custom board I’m using.  Starting to think that I need to buy an eval board to troubleshoot this one.

MM..1
Super User
September 4, 2026

Try dont complicate simple thinks. Use one line LL func to change speed on right place.

LCE
Principal II
September 4, 2026

Anything preventing you from reading and writing registers directly?

If yes, skip this post - and re-think your approach to life… ;-)

I actually don’t know the F4, but I use the UART a lot on G4, L0, H7, so I guess the following might also work for the F4.

  1. Make sure that all transfers are finished (I check register SR and bits TXE, and TC if DMA is used (check both, DMA might be finished before the last byte was actually sent) ).
  2. Disable UART in CR1 by resetting the UE bit.
  3. Calculate baud rate and set register BRR.
  4. Enable UART in CR1.

Sorry if this is BS for F4, that’s how it works for the types I’m using.

 

Associate
September 4, 2026

@LCE 

Thanks for the suggestion.  I had to add the ReceiveToIdle call at the end to get it to work in the debugger.  Unfortunately, this attempt didn’t change the behavior of problem (e.g. works in debugger, doesn’t work without debugger).  See my comments elsewhere for a fuller description of ‘not working’

        // Make sure that all transfers are finished (I check register SR and bits TXE, and TC if DMA is used (check both, DMA might be finished before the last byte was actually sent) ).
while (__HAL_UART_GET_FLAG(huart, UART_FLAG_TC | UART_FLAG_TXE) == RESET) {

}

// Disable UART in CR1 by resetting the UE bit.
CLEAR_BIT(huart->Instance->CR1, USART_CR1_UE);

// Calculate baud rate and set register BRR.
uint32_t pclk;
uint32_t brr_value;

// 4. Calculate the peripheral bus split values for the STM32F405
if ((huart->Instance == USART1) || (huart->Instance == USART6))
{
pclk = HAL_RCC_GetPCLK2Freq(); // APB2
}
else
{
pclk = HAL_RCC_GetPCLK1Freq(); // APB1
}

// 5. Calculate and apply the register configurations safely
if ((huart->Instance->CR1 & USART_CR1_OVER8) == USART_CR1_OVER8)
{
brr_value = UART_BRR_SAMPLING8(pclk, new_baudrate);
}
else
{
brr_value = UART_BRR_SAMPLING16(pclk, new_baudrate);
}
huart->Instance->BRR = brr_value;

// Enable UART in CR1.
SET_BIT(huart->Instance->CR1, USART_CR1_UE);

// Restart DMA reception (Example using Receive-to-Idle for variable length)
HAL_UARTEx_ReceiveToIdle_DMA(saUartControl[id].pHuart,
saUartControl[id].rx_dma_buffer,
sizeof(saUartControl[id].rx_dma_buffer));

 

waclawek.jan
Super User
September 4, 2026

> System appears to hang when commanded to change baud. 

What does this exactly mean?

JW

ST Technical Moderator
September 4, 2026

Hello ​@DownInFront 

System appears to hang when commanded to change baud. 

Could you explain with more details please?

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
Andrew Neil
Super User
September 4, 2026

System appears to hang when commanded to change baud. 

As ​@waclawek.jan and ​@Saket_Om said, please give more detail on this.

 

Note that you can connect the debugger to a “hung” system without doing a download or reset:

 

USART1, RX DMA (Circular), TX DMA in normal mode with DMA_IT_HT disabled

Does it work without DMA ?

 

Starting to think that I need to buy an eval board to troubleshoot this one.

Yes, that would definitely be a good move!

 

What’s the full part number of the chip you’re using?

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.
Associate
September 4, 2026

@waclawek.jan ​@Saket_Om  ​@Andrew Neil

Thanks for the tip about hot connecting the debugger.  That was helpful

Using the debugger in the error state, my code is still running but I am no longer reaching HAL_UARTEx_RxEventCallback() for any of the 3 USARTS I’m running even though I’m only trying to change USART1 here.

I’ve spent the morning reviewing register settings in and out of the error state.  I don’t see a problem (yet, still fishing around.)

SR->TXE and TC are SET

CR1->UE, IDLEIE, TE, and RE are all SET

CR3->DMAR and EIE are SET

USART1 Rx uses DMA2 Stream 2.  All settings match  what is set by HAL_DMA_Start_IT().

waclawek.jan
Super User
September 4, 2026

I am no longer reaching HAL_UARTEx_RxEventCallback() for any of the 3 USARTS I’m running even though I’m only trying to change USART1 here

Well, this sounds that something went wrong in the Cube/HAL harness, then, UART itself is probably OK. But I personally don’t use Cube/HAL so can’t help you here, sorry. But it’s open source so you can debug it yourself.

JW

Bob S
Super User
September 4, 2026

Yeah - something is REALLY wrong to affect OTHER UARTs.  

I noticed in your original code, you use “huart” for most operations, but the final HAL_UARTEx_ReceiveToIdle_DMA() call uses “saUartControl[id].pHuart”.  Any chance those point to 2 different things?

DownInFrontAuthorBest answer
Associate
September 4, 2026

@Bob S ​@waclawek.jan ​@Andrew Neil ​@Saket_Om ​@LCE 

Thank you all for your time and input here!  I have found and ‘fixed’ the issue.

I found that only during power-up initialization USART6 was throwing a DMA Rx error and my handler was disabling everything instead of trying to recover. 

Still don’t know why the error occurs only during power-up, but the new handler now rides through it and everything keeps on running after that.