Skip to main content
Associate
October 21, 2025
Solved

STM32G474 DMA with UART

  • October 21, 2025
  • 5 replies
  • 526 views

Hello,

I'm using STM32G474QET6 with HSI (16Mhz).

When not using DMA - the UART is working.

With DMA I'm having 2 issues:

  1. When sending 3 bytes, only 2 bytes sends.
  2. DMA is not receiving anything (UART Rx) - CNDTR remains 3 and not data is written to the buffer (data.bytes[1]).

The 2nd issue is the main issue.

 

That is my UART init func:

	LL_USART_InitTypeDef usart_init_struct;

	USART1->CR1 &= ~USART_CR1_UE;	//	Disable USART 1.

	//	USART 1 clock enable.
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);

	usart_init_struct.BaudRate 				= 19200;
	usart_init_struct.DataWidth 			= LL_USART_DATAWIDTH_8B;
	usart_init_struct.HardwareFlowControl 	= LL_USART_HWCONTROL_NONE;
	usart_init_struct.OverSampling 			= LL_USART_OVERSAMPLING_16;
	usart_init_struct.Parity 				= LL_USART_PARITY_EVEN;
	usart_init_struct.PrescalerValue 		= LL_USART_PRESCALER_DIV1;
	usart_init_struct.StopBits 				= LL_USART_STOPBITS_1;
	usart_init_struct.TransferDirection 	= LL_USART_DIRECTION_TX_RX;

	LL_USART_Init(USART1, &usart_init_struct);

	USART1->CR3 |= USART_CR3_OVRDIS;			//	Disable Overrun error.

	//	Config DMA1_Ch4 for USART1 Rx, & DMA1_Ch_5 for USART1 Tx.
	DmaConfig();

	NVIC_EnableIRQ(USART1_IRQn);

	USART1->CR1 |= USART_CR1_UE;				//	Enable USART 1.

 

And that is DmaConfig():

void DmaConfig(void)
{
	LL_DMA_InitTypeDef dma_init_struc;

	//	DMA 1 & DMAMUX clock enable.
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1 | LL_AHB1_GRP1_PERIPH_DMAMUX1);

	/************************************
	 * Configuration for USART 1 Tx DMA *
	 ************************************/
	dma_init_struc.Direction 		= LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
	dma_init_struc.Mode 	 		= LL_DMA_MODE_NORMAL;
	dma_init_struc.NbData 			= 0;
	dma_init_struc.PeriphRequest 	= LL_DMAMUX_REQ_USART1_TX;
	dma_init_struc.Priority 		= LL_DMA_PRIORITY_MEDIUM;

	//	Source.
	dma_init_struc.MemoryOrM2MDstAddress 	= 0;
	dma_init_struc.MemoryOrM2MDstDataSize 	= LL_DMA_MDATAALIGN_BYTE;
	dma_init_struc.MemoryOrM2MDstIncMode 	= LL_DMA_MEMORY_INCREMENT;

	//	Destination.
	dma_init_struc.PeriphOrM2MSrcAddress 	= (uint32_t)&USART1->TDR;
	dma_init_struc.PeriphOrM2MSrcDataSize 	= LL_DMA_PDATAALIGN_BYTE;
	dma_init_struc.PeriphOrM2MSrcIncMode 	= LL_DMA_PERIPH_NOINCREMENT;

	DMA1_Channel5->CCR &= ~DMA_CCR_EN;	//	DMA disable.
	LL_DMA_Init(DMA1, LL_DMA_CHANNEL_5, &dma_init_struc);

	/*
	 * Enable USART_Tx DMA Transmit request.
	 * Enable DMA transmit complete interrupt.
	 * Clear DMA1 Ch5 ALL interrupt flags.
	 */
	USART1->CR3 |= USART_CR3_DMAT;
	DMA1_Channel5->CCR |= DMA_CCR_TCIE;
	DMA1->IFCR = DMA_IFCR_CGIF5;

	NVIC_EnableIRQ(DMA1_Channel5_IRQn);


	/************************************
	 * Configuration for USART 1 Rx DMA *
	 ************************************/
	dma_init_struc.Direction 		= LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
	dma_init_struc.Mode 	 		= LL_DMA_MODE_NORMAL;
	dma_init_struc.NbData 			= 3;
	dma_init_struc.PeriphRequest 	= LL_DMAMUX_REQ_USART1_RX;
	dma_init_struc.Priority 		= LL_DMA_PRIORITY_MEDIUM;

	//	Source.
	dma_init_struc.PeriphOrM2MSrcAddress 	= (uint32_t)&USART1->RDR;
	dma_init_struc.PeriphOrM2MSrcDataSize 	= LL_DMA_PDATAALIGN_BYTE;
	dma_init_struc.PeriphOrM2MSrcIncMode 	= LL_DMA_PERIPH_NOINCREMENT;

	//	Destination.
	dma_init_struc.MemoryOrM2MDstAddress 	= (uint32_t)&data.bytes[1];
	dma_init_struc.MemoryOrM2MDstDataSize 	= LL_DMA_MDATAALIGN_BYTE;
	dma_init_struc.MemoryOrM2MDstIncMode 	= LL_DMA_MEMORY_INCREMENT;

	DMA1_Channel1->CCR &= ~DMA_CCR_EN;	//	DMA disable.
	LL_DMA_Init(DMA1, LL_DMA_CHANNEL_4, &dma_init_struc);

	/*
	 * Enable USART_Rx DMA Receiver request.
	 * Enable DMA transmit complete interrupt.
	 * Clear DMA1 Ch4 ALL interrupt flags.
	 */
	USART1->CR3 |= USART_CR3_DMAR;
	DMA1_Channel4->CCR |= DMA_CCR_TCIE;
	DMA1->IFCR = DMA_IFCR_CGIF4;
//
	NVIC_EnableIRQ(DMA1_Channel4_IRQn);

	DMA1_Channel4->CCR |= DMA_CCR_EN;	//	DMA enable.
}

 

Best answer by AM12

Working! What i did?

 

In all tests below, I was sending 'A' (0x41) at 115,200

Sending 8N1 - everything works fine:

AM12_0-1761128166607.png

AM12_1-1761128184606.png

AM12_3-1761128245771.png

 

Sending 8E1 - NOT working:

AM12_4-1761128481642.png

AM12_5-1761128494540.png

AM12_6-1761128515936.png

AM12_7-1761128530413.png

Data is indeed corrupted.

I changed the Scope settings to None and the data was parsed in the scope OK

AM12_8-1761128611161.png

 

So I sent only 1 byte:

Sending 1E8

Both regular sending & DMA received wrong - Parity is missing!

AM12_9-1761129848679.png

 

So I changed data length to 9bits - It's working!

AM12_10-1761130064345.png

 

 

5 replies

Technical Moderator
October 21, 2025

Hello @AM12 ,

 

Le me thank you for posting and welcome to the ST Community.

For more investigation, could you provide your Ioc.File.

 

Thanks.

Mahmoud

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
AM12Author
Associate
October 21, 2025

Hey,

I'm not using IOC for configuration.

waclawek.jan
Super User
October 21, 2025

Read out and check/post content of UART and relevant DMA and DMAMUX registers.

> When sending 3 bytes, only 2 bytes sends.

How do you send those 3 bytes?

JW

AM12Author
Associate
October 21, 2025

Registers value, after config, before sending/receiving anything at all.

USART1:

AM12_0-1761053168732.png

DMAMUX:

AM12_1-1761053232928.png

All other regs under DMAMUX are 0x0.

DMA1:

AM12_2-1761053294531.pngAM12_3-1761053311224.png

AM12_4-1761053324403.png

All other regs under DMA1 are 0x0.

CMAR4 is indeed the address of my rx_buffer.

 

2 bytes instead of 3:

dataxxx is global.

uint8_t dataxx[3] = {'A', 'B', 'C'};

UsartSend(dataxx, 3);

void UsartSend(uint8_t *data_buffer ,uint8_t len)
{
	//	Set length and enable DMA1 channel 5 (USART1 Tx).
	DMA1_Channel5->CCR 	&= ~DMA_CCR_EN;
	DMA1_Channel5->CMAR = (uint32_t)data_buffer;
	DMA1_Channel5->CNDTR = len;
	DMA1_Channel5->CCR 	|= DMA_CCR_EN;
}

 

waclawek.jan
Super User
October 21, 2025

Registers look good at this point, as well as the Tx code.

You may want to have a look at them and compare after UartSend.

How do you observe the Tx'd data, oscilloscop/logic analyzer, or something else? What's the source for Rx, is it a loopback from Tx?

Isn't there some other code which may interfere, e.g. some RTOS?

What hardware is this, a "known good" board like Nucleo, or your own? In the latter case, can't there be a problem in the hardware, e.g. the Tx pin getting active resulting in power supply dip and subsequent reset?

JW

AM12Author
Associate
October 21, 2025

Thanks for the replay.

 

  • I'm not using OS.
  • My own board.
  • I'm using Tera Term & Wire Shark to observe the data.

 

When sending w/o DMA - sending ok.

The problem is only when using DMA.

Same for receiving.

Dummy sending:

	USART1->TDR = dataxx[0];
	LL_mDelay(1000);
	USART1->TDR = dataxx[1];
	LL_mDelay(1000);
	USART1->TDR = dataxx[2];
	LL_mDelay(1000);

 

waclawek.jan
Super User
October 21, 2025

What happens if you try to transmit more than 3 bytes - say, the whole alphabet?

JW

 

AM12AuthorBest answer
Associate
October 22, 2025

Working! What i did?

 

In all tests below, I was sending 'A' (0x41) at 115,200

Sending 8N1 - everything works fine:

AM12_0-1761128166607.png

AM12_1-1761128184606.png

AM12_3-1761128245771.png

 

Sending 8E1 - NOT working:

AM12_4-1761128481642.png

AM12_5-1761128494540.png

AM12_6-1761128515936.png

AM12_7-1761128530413.png

Data is indeed corrupted.

I changed the Scope settings to None and the data was parsed in the scope OK

AM12_8-1761128611161.png

 

So I sent only 1 byte:

Sending 1E8

Both regular sending & DMA received wrong - Parity is missing!

AM12_9-1761129848679.png

 

So I changed data length to 9bits - It's working!

AM12_10-1761130064345.png

 

 

waclawek.jan
Super User
October 23, 2025

In the STM32 UART, contrary to the usual convention, parity bit counts towards the total bit number.

In other words, for 8E1, you need to set 9 bits in the STM32 UART.

And yes, I have forgotten about this, too...

JW

AM12Author
Associate
October 24, 2025

Yep, completely understood, and yet we all expect that the parity will be added by "itself".

Nice website, thanks!