Getting Started with STM32G0 and STM32CubeIDE: UART Full Duplex DMA

In the previous guide (here), we took a look how to receive data over UART using interrupt.

Now, we shall see how to send and receive data over UART using DMA.

In this guide, we shall cover the following:

  • Adding the DMA capability.
  • Developing the code.
  • Results.

1. Adding The DMA Capability:

By continue from the previous guide, open UART.ioc (depending on the name of the project name), Connectivity, then USART2, DMA Settings, add USART2_TX and USART2_RX.

For the USART2_RX, make sure to enable Circular mode as shown below:

Save the code and this will generate the code.

2. Developing The Code:

In main.c file.

At user code begin 0:

Declare two buffers to hold the transmission and reception data as following:

uint8_t RxData[5];

uint8_t TxData[40];

In this guide, we shall use buffer of 5 characters for the reception and 40 for the transmission.

Also, declare two volatile variables to indicate the end of transmit and receive as following:

volatile uint8_t TxFinished, RxFinished;

In STM32G0xx_hal_uart.c, we can find two functions shown below:

First function is:

/**
  * @brief Tx Transfer completed callback.
  * @param huart UART handle.
  * @retval None
  */
__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);

  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_UART_TxCpltCallback can be implemented in the user file.
   */
}

This function is called when the UART has finished transmitting all the data.

The other function:

/**
  * @brief  Rx Transfer completed callback.
  * @param  huart UART handle.
  * @retval None
  */
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);

  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_UART_RxCpltCallback can be implemented in the user file.
   */
}

This function will be called when the number of characters has been received.

These two functions are declared as weak which can be overwritten by the user.

After the volatile variable, we shall implement the functions as following:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	RxFinished=1;


}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	TxFinished=1;

}

In the Rx function, set RxFinished to 1 and same thing for Tx function by setting the TxFinished to 1.

In user code begin 2:

Start the UART receive in DMA mode as following:

HAL_UART_Receive_DMA(&huart2, RxData, 5);

In user code 3 in while 1 loop:

First, check if the UART has receive all the characters as following:

if(RxFinished==1)

If there is new data,

We shall echo back the characters to be received as following:

uint32_t len=sprintf((char*)TxData,"Received Data are %c %c %c %c %c \r\n",
				  RxData[0],RxData[1],RxData[2],RxData[3],RxData[4]);

Since sprintf return the number of characters , we shall use it when transmit the data.

Next, send the data over UART using DMA as following:

HAL_UART_Transmit_DMA(&huart2, TxData, len);

Set the RxFinished back to 0.

RxFinished=0;

Wait until the TxFinished is set (This part is depending on your application)

while(TxFinished==0);

Set back the TxFinish back to 0:

TxFinished=0;

Thats all for the code.

3. Results:

Using any serial port program, set the baud rate of 115200, send any 5 characters without \r\n and see the echoed characters.

Happy coding 🙂

Add Comment

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