When working with STM32 projects, UART communication is often the first thing developers need. Whether it is sending debug logs, linking sensors, or building custom serial interfaces, UART makes it possible. But many new users struggle with STM32 UART HAL functions, transmit vs receive modes, interrupts, or advanced features like idle line detection. This guide will break it down step by step and show you exactly how to set up STM32 UART communication on boards like STM32F103 and STM32F4 Nucleo. By the end, you will have a clear understanding and working examples for UART transmit, UART receive, single-wire UART, and even LIN protocol support.
What is UART Communication?
UART (Universal Asynchronous Receiver Transmitter) is a serial protocol used to send and receive data between two devices. It works with just two main pins: TX (transmit) and RX (receive).
- Speed is set by baud rate, for example 9600 or 115200.
- Frame format includes start bit, data bits, parity (optional), and stop bit.
- Full-duplex mode uses separate TX and RX lines.
- Half-duplex mode uses a single line for both transmit and receive.
STM32 microcontrollers support UART as part of their peripheral set. With STM32 HAL (Hardware Abstraction Layer), setting up UART is much easier compared to writing low-level register code.
Why Use STM32 HAL for UART?
STM32 HAL drivers offer ready-made APIs to configure and use UART without deep register-level coding. Some reasons to use HAL for STM32 UART include:
- Fast setup for STM32F103, STM32F4, and Nucleo boards
- Support for transmit, receive, and interrupt-based communication
- Easy integration with FreeRTOS or bare-metal code
- Built-in support for idle line detection and DMA transfers
This is why most STM32 developers start with HAL when learning UART.
STM32 UART Initialization with HAL
The first step is initializing UART using STM32CubeMX or manually in code. CubeMX generates code with correct clock and pin configuration.
Example HAL initialization snippet:
UART_HandleTypeDef huart1;
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&huart1);
This configures USART1 at 115200 baud, 8 data bits, no parity, and 1 stop bit.
STM32 UART Transmit with HAL
The simplest way to send data over UART is with HAL_UART_Transmit()
.
uint8_t msg[] = "Hello STM32\r\n";
HAL_UART_Transmit(&huart1, msg, sizeof(msg)-1, HAL_MAX_DELAY);
Key points:
- Uses blocking mode until transmission completes
- Timeout can be set or replaced with
HAL_MAX_DELAY
- Good for debug logs or short data packets
For higher performance, use DMA mode to send large data buffers without blocking CPU.
STM32 UART Receive with HAL
To receive data, use HAL_UART_Receive()
.
uint8_t rx_data[10];
HAL_UART_Receive(&huart1, rx_data, 10, HAL_MAX_DELAY);
This function waits until 10 bytes are received. For streaming data or unknown packet length, interrupts or idle line detection are better choices.
STM32 UART Interrupts
Interrupt mode is more efficient for real-time applications. Instead of blocking, the CPU continues running and only handles UART when data is ready.
HAL_UART_Receive_IT(&huart1, rx_data, 1);
Inside the callback:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
// Process received byte
HAL_UART_Receive_IT(&huart1, rx_data, 1); // restart reception
}
}
This setup ensures UART is always ready for incoming bytes.
UART Idle Line Detection in STM32
Idle line detection is one of the most practical STM32 UART features. It helps detect the end of a message when packet size is unknown.
- Enable idle line interrupt:
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
- Handle it in IRQ:
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
// Process received buffer
}
}
This is very useful for protocols with variable-length frames.
Single-Wire UART and One-Wire Protocol
STM32 UART also supports half-duplex, also known as single-wire UART. In this mode, TX and RX share the same line.
huart1.Init.Mode = UART_MODE_TX_RX;
HAL_HalfDuplex_Init(&huart1);
This setup is used in One-Wire protocol for devices like DS18B20 temperature sensors.
LIN Protocol with STM32 UART
LIN (Local Interconnect Network) is a serial network protocol based on UART. STM32 supports LIN by enabling break detection and sync fields.
- LIN is often used in automotive applications
- Works at baud rates like 19200
- HAL supports LIN mode through
HAL_LIN_Init()
HAL_LIN_Init(&huart1, UART_LINBREAKDETECTLENGTH_10B);
This allows STM32 boards like STM32F103 or STM32F4 to act as LIN master or slave.
Example: STM32F103 UART with Nucleo Board
On STM32F103 Nucleo:
- USART1 pins: PA9 (TX), PA10 (RX)
- USART2 pins: PA2 (TX), PA3 (RX)
Steps:
- Configure USART1 in CubeMX at 115200 baud.
- Connect USB-to-UART converter.
- Use
HAL_UART_Transmit()
to send “Hello”. - Open serial monitor on PC.
You will see data from STM32 board.
Common Problems and Fixes in STM32 UART
- Nothing received → Check pin mapping in CubeMX
- Garbled text → Baud rate mismatch
- Only first byte received → Missing interrupt restart
- DMA not working → Ensure memory alignment and correct buffer size
These are typical issues faced by beginners.
Pros and Cons of STM32 HAL for UART
Pros:
- Fast development
- Easy integration with CubeMX
- Covers most UART use cases
Cons:
- Less control than direct register programming
- Slightly more overhead in performance-critical applications
For most applications, HAL is a perfect starting point.
Frequently Asked Questions
What is STM32 UART used for?
It is used to send and receive serial data between STM32 and other devices.
How do I transmit data over STM32 UART?
Use HAL_UART_Transmit()
with TX buffer and UART handle.
How do I receive UART data continuously?
Use interrupt mode with HAL_UART_Receive_IT()
or DMA with idle line detection.
Which STM32 boards support UART?
Almost all STM32 boards, including STM32F103, STM32F4, and Nucleo boards, support UART.
Can STM32 use single-wire UART?
Yes, STM32 supports half-duplex mode with HAL.
What is UART idle line detection?
It is a feature that detects when no data is being received on UART.
How to use UART with FreeRTOS?
Use UART with queues or DMA to avoid blocking tasks.
Is LIN protocol supported in STM32 UART?
Yes, STM32 HAL provides HAL_LIN_Init()
for LIN communication.
Can UART be used for debugging STM32?
Yes, UART is often used with printf
for debugging.
What is the difference between polling and interrupt in UART?
Polling waits for data actively, while interrupt notifies CPU only when data arrives.
Conclusion
STM32 UART communication with HAL is straightforward once you understand the basics. From simple transmit and receive to advanced features like interrupts, idle line detection, and LIN protocol, STM32 provides everything needed for serial communication. Whether you are working with STM32F103, STM32F4, or Nucleo boards, these examples and explanations should help you set up a reliable UART system.
If you found this guide useful, share it with other STM32 developers or drop a comment below about your project.