2025-10-21 5:33 AM
Hello,
I'm using STM32G474QET6 with HSI (16Mhz).
When not using DMA - the UART is working.
With DMA I'm having 2 issues:
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.
}
2025-10-21 6:01 AM
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.
2025-10-21 6:04 AM
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
2025-10-21 6:21 AM
Hey,
I'm not using IOC for configuration.
2025-10-21 6:22 AM - edited 2025-10-21 6:30 AM
Registers value, after config, before sending/receiving anything at all.
USART1:
DMAMUX:
All other regs under DMAMUX are 0x0.
DMA1:
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;
}
2025-10-21 8:31 AM
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
2025-10-21 8:39 AM
Thanks for the replay.
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);
2025-10-21 10:30 AM
What happens if you try to transmit more than 3 bytes - say, the whole alphabet?
JW