UART Baud Rate Calculator

Calculate USART_BRR and UBRR register values for STM32, nRF52, ESP32, AVR, and RP2040. Shows actual baud rate and error percentage for all standard baud rates.

Configuration

Oversampling
BRR = fCLK / (16 × baud)

Result

USART_BRR

0x005B

= 91 decimal

Actual baud

115,385

Error

0.16%

STM32F4 (168 MHz) reference manual →

Common baud rates — STM32F4 (168 MHz)

BaudUSART_BRRHexActualError
9,60010940x04469,5980.02%
19,2005470x022319,1960.02%
38,4002730x011138,4620.16%
57,6001820x00B657,6920.16%
115,200910x005B115,3850.16%
230,400460x002E228,2610.93%
460,800230x0017456,5220.93%
921,600110x000B954,5453.57%

How it works

UART clocks are derived from the peripheral clock by dividing it down to the target baud rate. The divisor is written to a register — USART_BRR on STM32, UBRR0 on AVR, UART_CLKDIV_REG on ESP32.

STM32 (USART_BRR)

// 16x oversampling (default)
USART1->BRR = SystemCoreClock / 115200;

// 8x oversampling (OVER8=1 in CR1) — use for higher baud rates
USART1->BRR = (2 * SystemCoreClock) / 115200;

The STM32 BRR register holds both the integer and fractional divider in a single 16-bit value. For 16x oversampling: BRR = fCLK / baud. The hardware rounds implicitly. Error below 2% is acceptable; below 0.5% is ideal.

AVR (UBRR0)

The AVR formula subtracts 1 because the counter counts from UBRR down to 0:

// Normal speed (U2X0 = 0)
UBRR0 = F_CPU / (16UL * 115200) - 1;

// Double speed (U2X0 = 1) — better accuracy at high baud rates
UBRR0 = F_CPU / (8UL * 115200) - 1;

At 16 MHz with 115200 baud: UBRR0 = 8 (0.2% error). At 8 MHz: UBRR0 = 3 (8.5% error — too high, use double speed mode or 57600 baud).

nRF52 (BAUDRATE register)

The nRF52 UARTE does not use a calculated divisor. The BAUDRATE register takes fixed magic constants:

NRF_UARTE0->BAUDRATE = UARTE_BAUDRATE_BAUDRATE_Baud115200; // 0x01D7E000

These values are defined in nrfx_uarte.h / nrf52840.h. The silicon generates the baud clock internally. You cannot use arbitrary baud rates — stick to the supported list in the datasheet (section 6.34).

ESP32 (UART_CLKDIV_REG)

ESP32 UART uses the APB clock (typically 80 MHz) divided directly:

// uart_ll.h internally does:
UART0.clk_div.div_int = APB_CLK_FREQ / baud_rate;

The ESP-IDF uart_set_baudrate() handles this. The register also has a 4-bit fractional field for sub-integer precision.

Common mistakes

Feeding the wrong clock frequency. On STM32, USART1 is typically on APB2 (can run at system clock), while USART2/USART3 are on APB1 (often half the system clock). Check your clock tree in CubeMX or the RCC registers.

Forgetting the -1 on AVR. The UBRR formula is fCPU / (16 × baud) - 1, not fCPU / (16 × baud). At low baud rates the difference is small; at 9600 baud and 8 MHz it’s the difference between register value 51 and 52.

Using 16x oversampling at high baud rates on low clock MCUs. At 16 MHz and 921600 baud, the divisor rounds to 1 — no room for precision. Switch to 8x oversampling or a faster clock.

Not accounting for clock accuracy. Internal RC oscillators drift with temperature (typically ±1–3%). If your UART runs at the edge of the 2% error budget, a cold bench start might pass but a –40 °C field deployment fails.

nRF52 using calculated values. The BAUDRATE register is not a clock divider — it is a lookup table entry. Writing a calculated value will produce the wrong baud rate or garbage.