STM32 UART Interrupt, DMA, Polling | UART Receive Examples

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. Without further ado, let’s get right into it!

Table of Contents

  1. STM32 UART Interrupt, DMA, Polling (Receive Modes)
  2. STM32 UART Receive (Rx) Examples Overview
  3. STM32 UART Receive (Rx) Polling Example
  4. STM32 UART Interrupt Example (Receive / Rx)
  5. STM32 UART DMA Example (Receive / Rx)
  6. Wrap Up

STM32 UART Interrupt, DMA, Polling (Receive Modes)

This tutorial is intended to be an example application for the DMA unit which we’ve discussed in the previous tutorial (DMA Tutorial). However, I’d like also to list down all the other possible ways in order to receive serial UART data with an STM32 microcontroller including the DMA method.

STM32 UART Polling

The polling method is essentially a blocking function being called from the main routine and it does block the CPU so it can’t proceed in the main task execution until a certain amount of UART data bytes are received. After receiving the required amount of data, the function ends and the CPU continues the main code execution.

Otherwise, and if the UART peripheral for some reason didn’t receive the expected amount of data, the function will keep blocking the CPU for a certain amount of time “time-out” after which it gets terminated and gives back control to the CPU to resume the main code.

This function for example

Receives 12 bytes to the buffer. if it does that in 100uSec, it’s ok and the CPU will resume main code execution. If it doesn’t receive that amount of data, the CPU will be kept blocked waiting for 5sec until this function returns to the main context. Obviously, it’s not an efficient way to receive serial data despite the fact that it does actually work.

STM32 UART Interrupt

Using interrupt signals is a convenient way to achieve serial UART data reception. The CPU initializes the UART receive hardware so that it fires an interrupt signal whenever a new byte of data is received. And in the ISR code, we save the received data in a buffer for further processing.

This way of handling the UART data reception is a non-blocking way. As the CPU initiates the receiving process and it resumes executing the main code. Until an interrupt is received, then it freezes the main context and switches to the ISR handler to save the received byte to a buffer and switches back to the main context, and resumes the main code.

The above function initializes the UART receive process in interrupt mode (non-blocking) and upon completion, a callback function is called to notify the application and the processor knows that the received data buffer is now ready.

This method is a non-blocking one, yet very efficient. However, if you’re receiving a continuous stream of serial data, an insane number of interrupts per second will have to be handled by the CPU which is a huge load and a waste of time for it. In this situation, even the interrupt method will be inefficient and unnecessarily load the CPU and consume too much of the CPU time. In the worst scenario, there might be some data packets lost or dropped in the way. Now, it comes the time to use the DMA method.

STM32 UART DMA

Using the DMA unit in order to direct the received serial UART data from the UART peripheral directly to the memory is considered to be the most efficient way to do such a task. It requires no CPU intervention at all, you’ll have only to set it up and execute the main application code. The DMA will notify back the CPU upon reception completion and the received data buffer will be in the pre-programmed location.

The DMA can prioritize the channels, decide on the data width, and also the amount of data to be transferred up to 65536 bytes. Which is amazing in fact, and all you’ve got to do is to initialize it like this.

In the following sections, we’ll create a simple STM32 UART receive examples using each of the 3 methods.

❕ Note

Make sure you’ve completed the STM32 UART Tutorial for more information about how it works in detail.


STM32 UART Receive (Rx) Examples Overview

In the next sections of this tutorial, we’ll implement the following 3 example projects:

  • Application1: Setup an STM32 UART Receive Example With Polling
  • Application2: Setup an STM32 UART Receive Example With Interrupt
  • Application3: Setup an STM32 UART Receive Example With DMA

Each application will have to receive 12 bytes of data from the PC terminal and echo back the received data buffer. So in the testing, we’ll expect to see back whatever data we send through the terminal.


STM32 UART Receive (Rx) Polling Example

Step #1

Start a New CubeMX Project & Set up The RCC Clock

Step #2

Setup The UART1 Peripheral in Async Mode @ 9600bps

STM32 UART Receive DMA Interrupt Polling Example Tutorial

Step #3

Generate Code & Open CubeIDE or Any Other IDE You’re Using

STM32 UART Polling Example Code (Receive) – main.c

STM32 UART Polling Example Testing (Receive)

STM32 UART Receive DMA Interrupt Polling Example


STM32 UART Interrupt Example (Receive / Rx)

Step #1

Start New CubeMX Project & Setup The RCC Clock

Step #2

Setup The UART1 Peripheral in Async Mode @ 9600bps

STM32 UART Receive DMA Interrupt Polling Example Tutorial

Step #3

Enable The UART1 Global Interrupt From NVIC Controller Tab

STM32 UART Receive DMA Interrupt Polling Example Tutorial With Code

Step #4

Generate Code & Open CubeIDE or Any Other IDE You’re Using

STM32 UART Interrupt Example Code (Receive) – main.c

STM32 UART Interrupt Example Testing (Receive)

STM32 UART Receive DMA Interrupt Polling Example Code


STM32 UART DMA Example (Receive / Rx)

Step #1

Start New CubeMX Project & Setup The RCC Clock

Step #2

Setup The UART1 Peripheral in Async Mode @ 9600bps

STM32 UART Receive DMA Interrupt Polling Example Tutorial

Step #3

Add A DMA Channel For UART RX From The DMA Tab

STM32 UART Receive DMA HAL Example With Code

Step #4

Generate Code & Open CubeIDE or Any Other IDE You’re Using

STM32 UART DMA Example Code (Receive) – main.c

STM32 UART DMA Example Testing (Receive)

STM32 UART Receive DMA HAL Example With Code CubeMX


Wrap Up

In conclusion, we’ve explored how to set up the STM32 UART Interrupt, DMA, and Polling-based Receiver applications. The STM32 UART Receiver examples we’ve created in this tutorial should help you get started with your STM32 UART-based projects.

You can build on top of the example provided in this tutorial and/or explore the other parts of this STM32 UART tutorial series linked below.

This Tutorial is Part of The Following Multi-Part Tutorial Series:

Share This Page With Your Network!
Join Our +25,000 Newsletter Subscribers!

Stay Updated With All New Content Releases. You Also Get Occasional FREE Coupon Codes For Courses & Other Stuff!

Photo of author
Author
Khaled Magdy
Embedded systems engineer with several years of experience in embedded software and hardware design. I work as an embedded SW engineer in the Automotive & e-Mobility industry. However, I still do Hardware design and SW development for DSP, Control Systems, Robotics, AI/ML, and other fields I'm passionate about.
I love reading, writing, creating projects, and teaching. A reader by day and a writer by night, it's my lifestyle. I believe that the combination of brilliant minds, bold ideas, and a complete disregard for what is possible, can and will change the world! I will be there when it happens, will you?

5 thoughts on “STM32 UART Interrupt, DMA, Polling | UART Receive Examples”

  1. Thanks a lot for this article.
    I usually use uart with interrupt on each byte, as the length of the data is unknown.
    Sometimes it is only 1 byte, and other times it can be 50 bytes.
    I know the end of the transmission ends with \n, as l usually design both sides..
    How can l use DMA with unknown data length?

    Thank again,
    Lior

    Reply
    • I’m really sorry for the late response. But what you’re talking about seems to be software defined thing which means we can use whatever hardware features available for us and implement this functionality.
      In the near future, I’ll be publishing an article called “BCM Communication”. Which is going to be something like what you’re asking about. It’s a software communication module that sends char-based messages of any length. Each data packet will have the info of the data bytes count, header, footer, and checksum for error detection.
      It’s a kind of basic software protocol that the user can include and use in his/her project.
      As usual, it’s going to be configurable to different data rates and hardware layer. the messages can be sent/received over UART or SPI. More features can be added in the future. We’ll see how this piece of software will turn out to be.

      Kind regards,

      Khaled M.

      Reply
  2. Your article helped me a lot. Thanks for that ????
    I had one doubt though, why you have used HAL_UART_Receive_IT()/_DMA() in the Interrupt Subroutine (ISR). Won’t the Transmit function be enough in the ISR, as we already have Receive function in the main().
    I am referring to the DMA and Interrupt codes.

    Reply
  3. Got UART DMA working with CubeIDE 1.7.0 and Nucleo-H723ZG with difficulty! At first the code echoed back zeros. The CubeMX code generator issues the UART init before the DMA init and I noticed your code did the reverse, so I changed the order and it worked! Why? Is this an MX error?

    Reply

Leave a Comment