Transmit UART data in STM32

I have already written a tutorial about How to use UART in STM32 but it wasn’t a very good detailed tutorial. So today I am writing this one here. It will only cover the transmission part of UART, Reception of data will be covered in next one. 
I 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

Using the POLL Method

Starting with the simplest one i.e using the POLL method. The data is transmitted in 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.
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 Tx here. 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<1998; i++)
  {
    data[i] = 'x';
  }
   
data[1998] = '\r';
data[1999] = '\n';

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<1998; i++)
  {
    data[i] = 'x';
  }
   
data[1998] = '\r';
data[1999] = '\n';

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 and 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?”.
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 result 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 transfered, a HALF TRANSFER COMPLETE INTERRUPT gets triggered and HAL_UART_TxHalfCpltCallback is called and when the data transfer completes, HAL_UART_TxCpltCallback is called.
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 that out in the video below.



Transmit UART data in STM32 Transmit UART data in STM32 Reviewed by Controllerstech on July 08, 2018 Rating: 5

No comments:

Powered by Blogger.