Getting Started with STM32H5 ARM Cortex M33: UART RX in DMA

In this guide on STM32H5, we shall configure the UART to receive data using DMA to offload the reception process to the DMA rather than receiving it byte by byte in interrupt mode or polling mode and echo back the received data using DMA.

In this guide, we shall cover the following:

  • STM32CubeMX configuration.
  • Firmware development.
  • Results.

1. STM32CubeMX Configuration:

Continuing from the previous guide here, open the ioc file as following:

Then from System Core, select GPDMA1 and enable Channel 1 in Standard Request Mode as following:

Note: You can use any channel you want in DMA1 or DMA2, it will work just fine.

Open CH1 tab and configure the DMA as following:

  • Circular Mode to Disabled.
  • Request USART3_RX.
  • Transaction mode to Normal.
  • Direction Peripheral to Memory.

Keep the source data setting as is.

In destination data settings:

  • Enable the address increment mode.

That all for the STM32CubeMX section.

Save the project and this will generate the code.

2. Firmware Development:

Once the project has been generated, main.c shall be open.

In user code begin PV (Private variable), declare the buffer to store the received data as following:

uint8_t RxBuffer[100];

Declare a variable to hold the amount of the received data as following:

uint16_t size=0;

volatile variable to flag the application that the UART received the data:

volatile uint8_t RxDone=0;

In user code begin 0:

Include the following function:

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance==USART3)
	{
		RxDone=1;
		size=Size;
	}
}

This function shall be called once either all the 100 characters has been received or IDLE line is detected.

The function shall first check if the source is USART3 (in case multiple UART in the application). If it is the USART3, set the RxDone to 1 and get the size of the received data.

In user code begin 2, we shall start the reception process using the DMA.

We have two options:

First:

HAL_UART_Receive_DMA(&huart3, RxBuffer, 100);

This will receive data using DMA until and notify the application once all the 100 characters has been received.

Second:

HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RxBuffer, 100);

This will receive data using DMA and notify the application in one of these two conditions:

  • All 100 characters have been received.
  • An IDLE line detected (No characters has been received after the last character).

In this guide, we are going to focus on the IDLE one.

Hence, in user code begin 2:

HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RxBuffer, 100);

In user code begin 3, first check if the RxDone is set to 1 as following:

if(RxDone==1)

If yes, transmit the received data using DMA as following:

HAL_UART_Transmit_DMA(&huart3, RxBuffer, size);

Wait until the transmission is completed:

while(done==0);

Reset both flags of the transmission and reception as following:

done=0;
RxDone=0;

Clear the received buffer:

for(int i=0;i<100;i++)
{
  RxBuffer[i]=0;
}

Start the transmission again using DMA:

HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RxBuffer, 100);

Hence, the while 1 loop as following:

	  if(RxDone==1)
	  {

		  HAL_UART_Transmit_DMA(&huart3, RxBuffer, size);
		  while(done==0);
		  done=0;
		  RxDone=0;
		  for(int i=0;i<100;i++)
		  {
			  RxBuffer[i]=0;
		  }
		  HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RxBuffer, 100);

	  }

Save the project, build it and run it on your STM32H563Zi board.

3. Results:

Happy coding 😉

Add Comment

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