🌐
ST Wiki
wiki.st.com › stm32mcu › wiki › Getting_started_with_UART
Getting started with UART - stm32mcu - ST wiki
Open the UART.ioc file in the STM32CubeIDE project as shown in the figure below: Enable USART1 global interrupt.
🌐
DeepBlue
deepbluembedded.com › home › blog › stm32 uart interrupt, dma, polling | uart receive examples
STM32 UART Interrupt, DMA, Polling | UART Receive Examples
July 26, 2025 - In this tutorial, we’ll discuss the STM32 UART Interrupt DMA Polling methods using the HAL APIs. We’ll implement three STM32 UART Receive Examples Using Polling, Interrupt, and DMA to practice what we’ll learn in this tutorial.
Discussions

STM32 HAL USART receive by interrupt - Stack Overflow
Here is the full example that runs on the STM32F407 Discovery board. ... Save this answer. ... Show activity on this post. You can make it work using HAL! It may not be as elegant as other implementations but it is doable. You have to create an error handler function and then the function that calls the HAL_UART_RCV_IT must flush the UART RX whenever there is an overrun error. In addition, I work with two buffers. While the Interrupt ... More on stackoverflow.com
🌐 stackoverflow.com
microcontroller - Clearing USART (UART) interrupt flags in an STM32? - Electrical Engineering Stack Exchange
I am using an STM32F105 to communicate with a Linx GPS chip using a UART. If I don't use interrupts (if I just poll the RX flag) then it works just fine. But I'm getting unexpected results when t... More on electronics.stackexchange.com
🌐 electronics.stackexchange.com
How to properly handle 6-8 UART interrupts (STM32)
What baudrate is this at? If its really high you could look at DMA.. Otherwise, I would just have 8 handlers. A standard 115200 UART will only push 11-12kB/s. When in both directions, thats 24k interrupts/sec. So with 8 UARTs thats around 200k interrupts/sec. Sure thats a lot, but thats with all UARTs at max throughput both directions. Also, if you've something like a STM32F4 at 100+MHz, then each interrupt shouldn't take more than 1-2 us.. But again if you have anything that can be handled in "bulk" with DMA, then do it. However, I'm not 100% certain if the (older) STM32 parts can 'fit' all UART DMA requests with their mapping table.. so you may have to mix&match. Newer STM32s have a far more flexible DMAMUX peripheral. More on reddit.com
🌐 r/embedded
20
31
October 13, 2025
c - USART receive interrupt stm32 - Stack Overflow
0 Modify the example named UART_HyperTerminal_IT to enable UART reception interrupts on STM32F4? More on stackoverflow.com
🌐 stackoverflow.com
People also ask

Can I use this interrupt method for multiple UART peripherals?
Yes, each UART peripheral can have its own RXNE interrupt and buffer. You just need separate handlers and buffers for each UART instance.
🌐
controllerstech.com
controllerstech.com › home › stm32 tutorials › stm32 low level › stm32 uart using ll drivers (part 4): receive data in interrupt mode
STM32 UART using LL Drivers (Part 4): Receive Data in Interrupt Mode
Can UART interrupts and DMA be used together?
Yes, you can use DMA for bulk data transfer while using interrupts for smaller control messages or to signal transfer completion.
🌐
controllerstech.com
controllerstech.com › home › stm32 tutorials › stm32 low level › stm32 uart using ll drivers (part 2): transmit using interrupt & dma
STM32 UART using LL Drivers (Part 2): Transmit using Interrupt & DMA
How can I handle UART errors when using DMA or interrupt mode?
When using DMA or interrupt modes, it's important to handle UART errors such as framing errors, overrun errors, or noise errors. You can enable the appropriate error interrupts in STM32CubeMX and implement the HAL_UART_ErrorCallback() function in your code to manage these issues gracefully.
🌐
controllerstech.com
controllerstech.com › home › stm32 tutorials › stm32 uart series › stm32 uart part 2 – transmit using dma & interrupt
STM32 UART Interrupt & DMA Transmission → ControllersTech
🌐
Reddit
reddit.com › r/stm32 › uart rx interrupt best practises
r/stm32 on Reddit: UART RX Interrupt Best Practises
August 31, 2023 -

What are the best practices for handling received packets using UART in interrupt mode?

The way I am currently working, I have a global receive buffer and then perform all processing of this buffer inside my RxCpltCallback function and although it works, it doesn't seem right to me.

I can think of two ways I could improve on this but I would like it if someone could weigh in for me:

  1. Use a secondary processing buffer: I can create a secondary global "processing buffer" and copy the received data into this buffer in the interrupt callback function, and then process this second buffer in the main body of my code. This will allow me to begin receiving again immediately in the callback, but there is the obvious problem of the secondary buffer being overwritten in the middle of processing if more data comes in.

  2. Raise a flag upon completion: In the interrupt callback, I could raise a flag and then process the received packet inside the main body. After processing, I would then begin trying to receive data again. This eliminates the need for two buffers (I could even have a single local buffer but I would still require a global flag) and if I attempt to send data before I start trying to receive again, I believe it will just sit in a transmission buffer on the transmitting device until it can be received. Please correct me if my understanding here is wrong.

I appreciate any and all input or if you have ideas for better/nicer ways of handling things.

🌐
ControllersTech®
controllerstech.com › home › stm32 tutorials › stm32 uart series › stm32 uart part 2 – transmit using dma & interrupt
STM32 UART Interrupt & DMA Transmission → ControllersTech
February 22, 2026 - This can cause delays in other ... interrupt-based and DMA-based UART transmission, which allow the CPU to work on other tasks while data is being sent....
🌐
ControllersTech®
controllerstech.com › home › stm32 tutorials › stm32 uart series › stm32 uart part 3 – receive data in blocking & interrupt mode
STM32 UART Part 3 – Receive Data in Blocking & Interrupt mode
February 22, 2026 - When a byte or a set of bytes arrives, an interrupt triggers and HAL_UART_RxCpltCallback() handles the data. ... CPU is free between interrupts. Works well for real-time systems. Can handle variable-length data with proper buffer management.
🌐
DeepBlue
deepbluembedded.com › home › blog › stm32 uart (usart) tutorial + examples (dma, interrupt)
STM32 UART (USART) Tutorial + Examples (DMA, Interrupt)
June 12, 2024 - In this tutorial, we’ll discuss the STM32 UART Communication. You’ll learn how to use and configure the STM32 UART To Send/Receive Serial Data in polling, interrupt, and DMA modes. We’ll also implement a couple of STM32 UART Example Projects to practice what we’ll learn in this tutorial.
🌐
ControllersTech®
controllerstech.com › home › stm32 tutorials › stm32 low level › stm32 uart using ll drivers (part 2): transmit using interrupt & dma
STM32 UART using LL Drivers (Part 2): Transmit using Interrupt & DMA
March 25, 2026 - The image below shows the USART2 configuration in the CubeMX. ... Open Connectivity -> USART2. Set the Mode to Asynchronous. ... Keep the Baud Rate to a common value like 115200. Now enable the USART2 interrupt in the NVIC tab as shown in the ...
Find elsewhere
🌐
Embedded There
embeddedthere.com › stm32-uart-usart-with-hal-code-example
STM32 UART / USART tutorial with HAL code example – Embedded There
November 30, 2023 - In this tutorial, we will cover the STM32 USART peripheral. We will also cover how to handle UART protocol in STM32 and create an example project in interrupt mode using the STM32 NUCLEO-F446RE development board that will transmit and receive data between stm32 and the host computer via USB port.
🌐
STMicroelectronics Community
community.st.com › t5 › stm32-mcus › implementing-uart-receive-and-transmit-functions-on-an-stm32 › ta-p › 694926
Implementing UART receive and transmit functions on an STM32
November 26, 2025 - If you initialized your STM32CubeIDE project with the default settings, it will be 115200. Here you can enter a character from your keyboard to interface with UART. You can see that when you increase the size to 5, the interrupt callback isn’t reached until you enter 5 characters.
🌐
ControllersTech®
controllerstech.com › home › stm32 tutorials › stm32 low level › stm32 uart using ll drivers (part 4): receive data in interrupt mode
STM32 UART using LL Drivers (Part 4): Receive Data in Interrupt Mode
March 25, 2026 - The image below shows the USART2 configuration in the CubeMX. ... Open Connectivity -> USART2. Set the Mode to Asynchronous. ... Keep the Baud Rate to a common value like 115200. Now enable the USART2 interrupt in the NVIC tab as shown in the ...
🌐
STMicroelectronics Community
community.st.com › t5 › stm32-mcus-wireless › how-to-enable-uart-interrupt › td-p › 737338
Solved: how to enable uart interrupt - STMicroelectronics Community
October 30, 2024 - Hello, I want to activate UART1 interrupt directly through code in STM32CubeIDE, without using the .ioc file. UART1 is already active, so I just need to add the necessary lines to enable the interrupt. In the stm32wbxx_it.c file, I defined the interrupt handler as follows: void USART1_IRQHandler(voi...
🌐
Microcontrollers Lab
microcontrollerslab.com › home › stm32 blue pill › stm32 blue pill uart interrupt with cubeide and hal libraries
STM32 Blue Pill UART Interrupt with CubeIDE and HAL Libraries
December 2, 2025 - Now head over to Connectivity > USART2 and set the mode as ‘Asynchronous.’ Then head over to NVIC Settings under configuration and enable the USART2 global interrupt. This will enable UART global interrupt and also enables it in nested vectored ...
🌐
Microcontrollers Lab
microcontrollerslab.com › home › stm32 nucleo › stm32 nucleo uart interrupt with stm32cubeide and hal libraries
STM32 Nucleo UART Interrupt with STM32CubeIDE & HAL Libraries
September 15, 2024 - Now head over to Connectivity > USART2 and set the mode as ‘Asynchronous.’ Then head over to NVIC Settings under configuration and enable the USART2 global interrupt. This will enable UART global interrupt and also enables it in nested vectored ...
Top answer
1 of 5
7

HAL_UART_Receive_IT() is not meant to be called from an interrupt handler that way, but to initiate receiving a fixed number of bytes via interrupt.

A possible workaround is to check your input buffer after HAL_UART_IRQHandler() completes, i.e., in the /* USER CODE BEGIN USART1_IRQn 1 */ section. When a command is processed, you can reset pRxBuffPtr and RxXferCount in the handle structure to their original values to start from the start of the buffer again.

Another horrible possible workaround would be to call HAL_UART_Receive_IT() with a buffer size of 1, and set up a HAL_UART_RxCpltCallback() handler that checks the received byte each time, and calls HAL_UART_Receive_IT() again when necessary.

Of course you could do it without HAL, as PeterJ and others (always) suggest.

  • You've already implemented pin and interrupt setup. Leave them unchanged at first.
  • Calculate the UART->BRR value according to the reference manual, or copy the relevant code from HAL.
  • set UART->CR1 = USART_CR1_RE | USART_CR1_TE | USART_CR1_UE |USART_CR1_RXNEIE; Now, you are getting interrupts.
  • In the interrupt function, read UART->SR into a temporary variable, and examine it.
  • Read UART->DR when there is a received byte waiting, and do the error handling otherwise (later).
  • Get rid of the rest of the HAL calls when the above is working.

Interrupt response and processing time is often critical in embedded applications, and the HAL just wastes a lot of that.

2 of 5
6

The normal HAL library is not useful for continuous reception or commands with different length.

If you have the complete HAL package installed, you could look at the examples for the Low-Layer (LL) interface.

Projects\STM32F411RE-Nucleo\Examples_LL\USART\USART_Communication_Rx_IT_Continuous

The main thing is to set your USART to continuous reception:

    void Configure_USART(void) {
        /* (1) Enable GPIO clock and configures the USART pins *********************/

        /* Enable the peripheral clock of GPIO Port */
        USARTx_GPIO_CLK_ENABLE();

        /* Configure Tx Pin as: Alternate function, High Speed, Push pull, Pull up */
        LL_GPIO_SetPinMode(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_MODE_ALTERNATE);
        USARTx_SET_TX_GPIO_AF();
        LL_GPIO_SetPinSpeed(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
        LL_GPIO_SetPinOutputType(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
        LL_GPIO_SetPinPull(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_PULL_UP);

        /* Configure Rx Pin as: Alternate function, High Speed, Push pull, Pull up */
        LL_GPIO_SetPinMode(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_MODE_ALTERNATE);
        USARTx_SET_RX_GPIO_AF();
        LL_GPIO_SetPinSpeed(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
        LL_GPIO_SetPinOutputType(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
        LL_GPIO_SetPinPull(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_PULL_UP);

        /* (2) NVIC Configuration for USART interrupts */
        /*  - Set priority for USARTx_IRQn */
        /*  - Enable USARTx_IRQn */
        NVIC_SetPriority(USARTx_IRQn, 0);
        NVIC_EnableIRQ(USARTx_IRQn);

        /* (3) Enable USART peripheral clock and clock source ***********************/
        USARTx_CLK_ENABLE();

        /* (4) Configure USART functional parameters ********************************/
        /* TX/RX direction */
        LL_USART_SetTransferDirection(USARTx_INSTANCE, LL_USART_DIRECTION_TX_RX);

        /* 8 data bit, 1 start bit, 1 stop bit, no parity */
        LL_USART_ConfigCharacter(USARTx_INSTANCE, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);

        /* No Hardware Flow control */
        /* Reset value is LL_USART_HWCONTROL_NONE */
        // LL_USART_SetHWFlowCtrl(USARTx_INSTANCE, LL_USART_HWCONTROL_NONE);

        /* Oversampling by 16 */
        /* Reset value is LL_USART_OVERSAMPLING_16 */
        // LL_USART_SetOverSampling(USARTx_INSTANCE, LL_USART_OVERSAMPLING_16);

        /* Set baud rate to 115200 using APB frequency set to 100000000/APB_Div Hz */
        /* Frequency available for USART peripheral can also be calculated through LL RCC macro */
        /* Example:
            Periphclk = LL_RCC_GetUSARTClockFreq(Instance); or
            LL_RCC_GetUARTClockFreq(Instance); depending on USART/UART instance

            In this example, Peripheral Clock is expected to be equal to
            100000000/APB_Div Hz => equal to SystemCoreClock/APB_Div
        */
        LL_USART_SetBaudRate(USARTx_INSTANCE, SystemCoreClock/APB_Div, LL_USART_OVERSAMPLING_16, 115200);

        /* (5) Enable USART *********************************************************/
        LL_USART_Enable(USARTx_INSTANCE);
    }

The USART IT Handler should look like

    void USARTx_IRQHandler(void)
    {
      /* Check RXNE flag value in SR register */
      if(LL_USART_IsActiveFlag_RXNE(USARTx_INSTANCE) && LL_USART_IsEnabledIT_RXNE(USARTx_INSTANCE))
      {
        /* RXNE flag will be cleared by reading of DR register (done in call) */
        /* Call function in charge of handling Character reception */
        USART_CharReception_Callback();
      }
      else
      {
        /* Call Error function */
        Error_Callback();
      }
    }

The last thing to set up is the Callback

void USART_CharReception_Callback(void);

Where you could put the bytes into an buffer and handle it in the main loop or where you want.

Top answer
1 of 4
24

Generally, you only need to handle the interrupt flags which you have specifically enabled with USART_ITConfig().

However, if you enable the RXNE interrupt (USART_ITConfig(USARTx, USART_IT_RXNE)) then this also enables the Overrun interrupt! So you must handle both of those.

The USART flags can be confusing. There are separate status flags and interrupt flags and they share similar names. For example: USART_IT_RXNE and USART_FLAG_RXNE.

In addition, there are various methods to clear these flags. For example, the USART_ClearITPendingBit() function only works for four (of the ten) possible flags.

Here is a summary of the interrupt flags and how to use them. These are specific for the STM32F105, but are representative:


USART_IT_TXE - "Transmit Data register empty"

  • It is cleared automatically when calling USART_SendData()

USART_IT_RXNE - "Receive Data register not empty"

  • It is cleared automatically when calling USART_ReceiveData(USARTx)

  • It can be cleared manually by calling USART_ClearITPendingBit(USARTx, USART_IT_RXNE)


USART_IT_TC - "Transmission complete"

  • It is cleared automatically by:

    • USART_GetITStatus(USARTx, USART_IT_TC) followed by
    • USART_SendData()
  • It can be also be cleared manually by calling USART_ClearITPendingBit(USARTx, USART_IT_TC)


USART_IT_CTS - "CTS change"

  • Cleared by calling USART_ClearITPendingBit(USARTx, USART_IT_CTS)

USART_IT_LBD - "LIN Break detected"

  • Cleared by calling USART_ClearITPendingBit(USARTx, USART_IT_LBD)

USART_IT_PE - "Parity error"

  • Cleared by:
    • USART_GetITStatus(USARTx, USART_IT_PE) followed by
    • USART_ReceiveData(USARTx)

USART_IT_NE - "Noise error"

  • Cleared by:
    • USART_GetITStatus(USARTx, USART_IT_NE) followed by
    • USART_ReceiveData(USARTx)

USART_IT_ORE - "Overrun error"

  • Cleared by:
    • USART_GetITStatus(USARTx, USART_IT_ORE) followed by
    • USART_ReceiveData(USARTx)()

USART_IT_IDLE - "Idle line detected"

  • Cleared by:
    • USART_GetITStatus(USARTx, USART_IT_IDLE) followed by
    • USART_ReceiveData(USARTx)()
2 of 4
3

Just want to add some my experience on this problem, I follow the instructions:

USART_IT_ORE - "Overrun error"

Cleared by: USART_GetITStatus(USARTx, USART_IT_ORE) followed by USART_ReceiveData(USARTx)()

Is seems not work, and the following command work for me instead:

USART_GetFlagStatus(USARTx, USART_IT_ORE) followed by USART_ReceiveData(USARTx)

If you look into the functions:

USART_GetFlagStatus() and USART_ReceiveData()

You will find what exactly Bitsmack wrote before... "First read the USARTx_SR register, then read the USARTx_DR register."

Hopefully it work for you and save lot more time on this issue.=)

🌐
GitHub
github.com › Ltran0325 › STM32-UART-Communication
GitHub - Ltran0325/STM32-UART-Communication: Communicate between microcontroller and PC using UART polling, interrupt, and DMA. · GitHub
Communicate between microcontroller and PC using UART polling, interrupt, and DMA. - Ltran0325/STM32-UART-Communication
Author   Ltran0325
Top answer
1 of 5
11

Such a question is difficult to answer without knowing which specific processor you are using, which board you are using, and/or which compiler you are using. But in an attempt to be helpful, here's my code.

Here's my GPIO and NVIC initialization code using Sourcery CodeBench Lite with an STM32F4 processor mounted on a custom board.

GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_Init(GPIOB, &GPIO_InitStructure);

// Enable the USART RX Interrupt 
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

Of course your settings will vary depending on your processor, board and interrupt priority.

Here's my interrupt handler code. In my development environment, this handler is declared in my startup assembly file as a weak reference to Default_Handler...

Default_Handler:
b .  

/* ... */

.word     USART3_IRQHandler

/* ... */

.weak      USART3_IRQHandler      
.thumb_set USART3_IRQHandler,Default_Handler

... so as long as I provide a new declaration and implementation of this interrupt handler, the weak reference will be replaced. Here's what my code looks like.

//Interrupt handler declaration
void USART3_IRQHandler();

If you are using C++ you will need to declare it as follows:

//Interrupt handler declaration in C/C++
#ifdef __cplusplus
 extern "C" {
#endif
void USART3_IRQHandler();
#ifdef __cplusplus
 }
#endif

And here's the interrupt handler implemenation.

//Interrupt handler implementation
void USART3_IRQHandler()
{
    //handle interrupt
}
2 of 5
4

Here's short and simple code to configure STM32 USART (USART3) and Interrupt Handler.

Configure and Init

    void Init_USART3()
   {
     // PB.11 = RX    Floating Input
     // PB.10 = TX    Alternate function output Push-pull 50 MHz
     RCC->APB2ENR = RCC->APB2ENR | (RCC_APB2ENR_IOPBEN);
     RCC->APB1ENR |= RCC_APB1ENR_USART3EN;      // enable clock for  USART3.

     GPIOB->CRH = GPIOB->CRH & 0xFFFF00FF;
     GPIOB->CRH = GPIOB->CRH | 0x00004B00;

     USART3->BRR  =72000000/9600;                    // set baudrate. 
     USART3->CR1  |= (USART_CR1_RE | USART_CR1_TE);  // RX, TX enable. 
     USART3->CR1  |= USART_CR1_UE;                   // USART3 enable.  
     USART3->CR1  |= USART_CR1_RXNEIE;    // UART3 Receive Interrupt Enable.
     // Enable interrupt fromUSART1(NVIC level) 
     NVIC_EnableIRQ(USART3_IRQn);   
   }

Handle Receive Interrupt

void USART3_IRQHandler()
{
  if(USART3->SR & USART_SR_RXNE)
  {
    // Do Something
  }
}
🌐
Keil
keil.com › download › docs › 359.asp
STM32 USART (interrupt mode) Example
The STM32 USART_Irq example program shows how to configure and use the USART1 of STMicroelectronics STM32F103xx microcontroller in interrupt driven mode. The configuration of USART1 is 9600 Baud, 8 data bits, 1 stop bit, no parity and no flow control. Retargetting is used to read a charac...