2025-01-28 03:57 PM
Hello,
I am implementing DMA transfers to USART1 peripheral configured as asynchronous UART. I am facing issue that the message transferred with DMA is transferred only once and freezes.
When set to transfer messages in blocking mode (without using DMA), it is transferred fine every time in a loop.
For reference I am attaching my initialization code for DMA and USART1:
Initialize USART1:
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
{
Error_Handler();
}
Initialize DMA:
handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
handle_GPDMA1_Channel0.Init.Request = GPDMA1_REQUEST_USART1_TX;
handle_GPDMA1_Channel0.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
handle_GPDMA1_Channel0.Init.Direction = DMA_MEMORY_TO_PERIPH;
handle_GPDMA1_Channel0.Init.SrcInc = DMA_SINC_INCREMENTED;
handle_GPDMA1_Channel0.Init.DestInc = DMA_DINC_FIXED;
handle_GPDMA1_Channel0.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
handle_GPDMA1_Channel0.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
handle_GPDMA1_Channel0.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
handle_GPDMA1_Channel0.Init.SrcBurstLength = 1;
handle_GPDMA1_Channel0.Init.DestBurstLength = 1;
handle_GPDMA1_Channel0.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
handle_GPDMA1_Channel0.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
handle_GPDMA1_Channel0.Init.Mode = DMA_NORMAL;
if (HAL_DMA_Init(&handle_GPDMA1_Channel0) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(huart, hdmatx, handle_GPDMA1_Channel0);
if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
{
Error_Handler();
}
and this is how I am sending UART messages:
while (1)
{
HAL_UART_Transmit_DMA(&huart1, (uint8_t*)"DMA Message\n", strlen("DMA Message"));
HAL_Delay(2000);
}
2025-01-28 09:31 PM
Make sure that both UART and DMA channel interrupts are enabled in CubeMX.
2025-01-29 12:04 AM
Hello@_AK
As mentioned by @gbm , for completion of a DMA transmission, initiated by HAL_UART_Transmit_DMA(), both interrupts of DMA channel and USART/UART instance, need to be enabled.
- DMA interrupt will occur once all data have been handled by DMA (i.e. copied from your buffer to USART Data Register, for being sent)
- Then USART Transmit Complete interrupt indicates that the transfer is actually complete (all data sent on the line).
So please enable both interrupts, and you could catch end of transfer in HAL_UART_TxCpltCallback() callback execution.
Regards
Guenael
2025-01-29 12:07 PM
Thanks. It worked. I had to provide C linkage for ISRs written in C++.