UART Transmit data using Poll Interrupt and DMA in STM32

Today in this tutorial we will cover how to Transmit data to UART in STM32.

We will use all three methods to transmit serial data here i.e

  • using the poll —> HAL_UART_Transmit
  • using the interrupt —> HAL_UART_Transmit_IT
  • and using DMA —> HAL_UART_Transmit_DMA

To Receive the data using UART, check out https://controllerstech.com/uart-receive-in-stm32/

Using the POLL method

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

  • The data is transmitted using blocking mode i.e the CPU will block every other operation until the data transfer 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 transmit data using POLL method, simply use

....
uint8_t data[] = "HELLO WORLD \r\n";

HAL_UART_Transmit (&huart2, data, sizeof (data), 10);

toggle LED 

HAL_Delay (250);  // 250 ms delay
  • I am using toggle LED for you guys to better understand what happens when we try transmitting large data.
  • This is best explained in the video, Please check it out.
  • Also ’10’ is the timeout for the UART Transmission.
  • At this point the data transmission is pretty quick and LED blinking rate is also constant.

Let’s try to transmit a large buffer now. I will keep the ‘timeout’ at ’10’ ms as it was before.

.....

uint8_t data[2000];

for (int i=0; i<2000; i++)
  {
    data[i] = 'x';
  }

toggle LED; 
HAL_Delay (250);
HAL_UART_Transmit (&huart2, data, sizeof (data), 10);

you will notice that LED blinking rate is constant but the complete data is not being transmitted.

This is because of the ‘timeout‘ we are using is 10 ms. Let’s increase the timeout now so that we can transfer the complete data.

.....

uint8_t data[2000];

for (int i=0; i<2000; i++)
  {
    data[i] = 'x';
  }

toggle LED; 
HAL_Delay (250);
HAL_UART_Transmit (&huart2, data, sizeof (data), 1000);  // timeout is 1sec
  • Now the complete data is being transmitted, but the LED blinking rate decreases.
  • This is because the UART is transmitting data in blocking mode and until the transfer completes, no other operation can take place.
  • To overcome this problem we can use either INTERRUPT or DMA to transmit data.





USING the INTERRUPT

In interrupt mode, Transmission takes place in non-blocking mode or in the background. So the rest of the processes works as they should.

When the data transmission is complete, a Tx Complete Callback is called where we can write instructions like “what to do after the transfer 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

You must watch the video if you want to see the working results. I can’t post them here. Check out the video at the end of the post.

..... 

uint8_t data[2000]; 

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
   HAL_UART_Transmit_IT(&huart2, data, sizeof (data));
}

main ()
{
for (int i=0; i<2000; i++) 
 { 
   data[i] = 'x'; 
 }

HAL_UART_Transmit_IT(&huart2, data, sizeof (data));

while (1)
{ 
  toggle LED;
  HAL_Delay (250);
}
}
  • In the above code, HAL_UART_TxCpltCallback will be called when the data transmission is complete and as you can see inside this function, I am again starting a new data transmission.
  • This will results in continuous transmission of data and the rate of blinking will also remain constant as the data transfer takes place in non-blocking mode.

Let’s transmit data after some delay so that we can check whether the data transmitting is complete data…


NOW let’s say that we want the data to be transmitted after every 20 blinks of LED so that we can get enough time to analyze previously transmitted data before the new one comes.

..... 

uint8_t data[2000]; 
uint8_t count =0;

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
   // do nothing here
}

main ()
{
for (int i=0; i<2000; i++) 
 { 
   data[i] = 'x'; 
 }

while (1)
{ 
  toggle LED;
  HAL_Delay (250);
  
  count++;

  if ((count%20) == 0)
   {
     HAL_UART_Transmit_IT(&huart2, data, sizeof (data));
   }
}
}

Notice that I am calling HAL_UART_Transmit_IT inside the if loop, so that when 20 blinks are complete, than only the data gets transmitted. You will see that the complete data transmits after every 20 blinks.



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 transferred, a HALF TRANSFER COMPLETE INTERRUPT gets triggered and HAL_UART_TxHalfCpltCallback is called and when the data transfer completes, HAL_UART_TxCpltCallback is called.

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

  • Here We are doing the Transmission, so UART1_Tx DMA is added.
  • In the Circular mode, the DMA will keep transmitting the data.
  • After Transmitting all the data, it will start automatically from the beginning.
  • Data Width is selected as Byte, as we are sending characters, which takes only 1 byte in the memory.

Basically the idea behind this is when the second half of the data is being transmitted, we can write new data in the first half and that’s how DMA works as a circular buffer.

..... 

uint8_t data[2000]; 
uint8_t count =0;

void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
  for (int i=0; i<1000; i++)
    {
	data[i] = 'z';
    }
}



void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    for (int i=0; i<1000; i++)
    {
	data[i] = 'y';
    }
}

main ()
{
for (int i=0; i<2000; i++) 
 { 
   data[i] = 'x'; 
 }

while (1)
{ 
  toggle LED;
  HAL_Delay (250);
  
  count++;

  if ((count%20) == 0)
   {
     HAL_UART_Transmit_DMA(&huart2, data, sizeof (data));
   }
}
}

As you can see above that when the control will enter the HAL_UART_TxHalfCpltCallback function the data in the first half of the buffer should change and this happens when the second half is being transmitted. You can see this in the images below

You can also use toggle to continuously monitor this change.


Check out the Video Below










8 Comments. Leave new

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.

×