Receive UART data using POLL, INTERRUPT and DMA

As the title describes it, Today we will see how to Receive UART (SERIAL) data using POLL , INTERRUPT and DMA.

I am going to use all three methods and show you the difference between all three. There is a video attached at the end of this post. Do check it to see the working.

I will use all three methods to Receive serial data here i.e

  • using the poll —> HAL_UART_Receive
  • using the interrupt —> HAL_UART_Receive_IT
  • and using DMA —> HAL_UART_Receive_DMA

To transmit the Data using the UART, check out https://controllerstech.com/uart-transmit-in-stm32/

By using the POLLING

Let’s start with the simplest method i.e using the POLL method.

The data is Received in blocking mode i.e the CPU will block every other operation until the data Reception is complete. This method is good to use if you are only using UART and nothing else, otherwise all other operations will be affected.

The Setup for this par is fairly Simple. We just have to enable the UART and that’s it.
Below the the picture of the Default setup in the CubeMX


To Receive data using POLL method, simply use

....
uint8_t Rx_data[10];  //  creating a buffer of 10 bytes

while (1) 
{
HAL_UART_Receive (&huart2, Rx_data, 4, 100);  // receive 4 bytes of data

HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_5);  // toggle LED
HAL_Delay (250);
}
  • I am using toggle LED for you guys to better understand what happens when we try Receiving data. This is best explained in the video, Please check it out.
  • Also ‘100’ is the timeout for the UART Rx here.
  • You will notice that even after sending 4 bytes of data, UART only receives 1 byte. 
  • This is because the reception timed out after 100 ms. That’s why only 1 byte of data is received.
  • So what should we do if we want to receive all 4 bytes ?

Well we will increase the timeout. Now let’s set to 1 sec and see what happens.

....
uint8_t Rx_data[10];  //  creating a buffer of 10 bytes

while (1)
{
HAL_UART_Receive (&huart2, Rx_data, 4, 1000);  // receive 4 bytes of data

HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_5);  // toggle LED
HAL_Delay (250);
}
  • As I already mentioned above that in POLL method, data is  processed in blocking mode.
  • So all other executions are blocked until the data is received or the timeout happens.
  • That’s why the LED blink rate reduces here.

To overcome this, we will use INTERRUPT or DMA methods.




Using the INTERRUPT

In interrupt mode, Reception takes place in non-blocking mode or in the background.

So the rest of the processes works as they should and when the data Reception is complete, a Rx Complete Callback is called.

Here we can write instructions like “what to do after the Reception is complete?”.

In order to enable the Interrupt in CubeMX, we just need to modify our previous setup.

All we need to do is enable the interrupt in the Interrupt TAB under the UART. The Picture is shown below


To Receive data using the Interrupt, we will use

....
uint8_t Rx_data[10];  //  creating a buffer of 10 bytes

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{
  HAL_UART_Receive_IT(&huart2, Rx_data, 4); 
}

HAL_UART_Receive_IT (&huart2, Rx_data, 4);

while (1)
{
  HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_5);
  HAL_Delay (250);
}
  • In the above code, HAL_UART_RxCpltCallback will be called when the data reception is complete.
  • As you can see inside this function, I am again starting a new data reception.
  • This will result in continuous reception of data and the rate of blinking will also remain constant as the data transfer takes place in non-blocking mode or in the background.

Note that if you do not start the reception again (inside HAL_UART_RxCpltCallback function), the reception will only take place once.



Using the DMA

DMA also works somewhat same as interrupt, means that data transfer is in a non-blocking mode.

In DMA, when half the data gets Received, a HALF Received COMPLETE INTERRUPT gets triggered and HAL_UART_RxHalfCpltCallback is called and when the data transfer completes, HAL_UART_RxCpltCallback is called.

To Setup the DMA, we have to ADD the DMA in the DMA Tab under the UART.

  • Here We are doing the Reception, so UART1_Rx DMA is added.
  • In the Circular mode, the DMA will keep Receiving the data.
  • After Receiving all the Required data, it will start automatically from the beginning.
  • Data Width is selected as Byte, as we are receiving characters, which takes only 1 byte in the memory.

To Receive the Data using the DMA, we will do as follows

....
uint8_t Rx_data[10];  //  creating a buffer of 10 bytes

void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
  HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_0);  // toggle PA0
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{
  HAL_UART_Receive_DMA(&huart2, Rx_data, 4); 
}

int main ()
{
  ..........
  ..........

  HAL_UART_Receive_DMA (&huart2, Rx_data, 4);  // Receive 4 Bytes of data

  while (1)
  {
    HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_5);
    HAL_Delay (250);
  }
}
  • When the Half reception is complete, LED connected to A0 should toggle.
  • When all the data is received, RxCpltCallback will be called.
  • Here you can do the desired operation.
  • If you haven’t selected the Circular mode in DMA, you can start the DMA again.
  • If you have selected the circular mode, then no need to start the DMA, as it will start automatically.



Result

Check out the Video Below









11 Comments. Leave new

  • Hi ControllerTech, nice work! very comprehensive indeed. i m a student working on STM32H7A3 board and using USART to interface to ext. peripheral like dc motor etc. do you mind if you can share your Interrupt and DMA full code? i would like to implement something similar…

    Reply
    • DMA requires the knowledge of MPU in Cortex M7 series MCUs (check the MPU videos in cortex M7 playlist on YouTube) .. For the rest the code is same as what is mentioned in the tutorial. There are just one or two functions used, simply copy paste them

      Reply
  • Hi ControllerTech, nice work! very comprehensive indeed. i m a student working on STM32H7A3 board and using USART to interface to ext. peripheral like dc motor etc. do you mind if you can share your Interrupt and DMA full code? i would like to implement something similar…
    Irene
    MIT USA

    Reply
  • Hi,
    nice short description, but it lacks the IRQ and DMA configuration, or am I missing something?
    Thx in advance.

    Reply
  • Hi!!. Thanks for your time and effort.

    Reply
  • Do the above methods are applicable for any stm controller. Since I am using STM32 Nucleo F091RC and STM32 Nucleo L053R8 because transmitting is proper but receive methods are not working.
    For nucleo do I need to do some hardware changes like shorting solder bridges etc?
    Kindly help .your help will be valuable since i am stuck from past 3 days

    Reply
  • Hi,

    I’ve try it under ACR6 System workbench. With a few code modification, for include’s constants name or even struct for UART, it compile. But unfortunately the code end-up in an interrupt deadloop and the while(1) isn’t ran.
    I can trace it with the debugger, but I don’t have a clear idea of the typical path, so I can’t be sure of the part to fix.
    The code was ported to run on a STM32F0xx core. But I have a few STM32F1xx (Chinese bluepeal) on my hand too if you think it’s better for a first try.

    Would you please give me a little help on this port to system workbench ? I can upload my current source code if needed.

    Cheers,

    Phil

    Reply
  • Semachew Fasika Misrak
    August 31, 2018 6:12 PM

    Can I use the code for EWARM(IAR IDE) as it is?

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

keyboard_arrow_up

Adblocker detected! Please consider reading this notice.

We've detected that you are using AdBlock Plus or some other adblocking software which is preventing the page from fully loading.

We don't have any banner, Flash, animation, obnoxious sound, or popup ad. We do not implement these annoying types of ads!

We need money to operate the site, and almost all of it comes from our online advertising.

Please add controllerstech.com to your ad blocking whitelist or disable your adblocking software.

×