Skip to main content
Associate III
January 22, 2026
Solved

UART receive command with DMA

  • January 22, 2026
  • 3 replies
  • 344 views

Hello, I have a query about how HAL_UART_Receive_DMA and HAL_UARTEx_ReceiveToIdle_DMA work?

For my application there is a varying payload size, so I am wondering how would I trigger the HAL_UART_Receive_DMA(&huart3, rx_buffer, 4096, 0xFFFF); interupt? As from my understanding it would be waiting for all 4096 bytes of data which won't arrive unless a different frame was sent.

Whereas  HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx_buffer, 4096); triggers once the serial port stops communicating, however it stores the received data in 512 byte chunks, which has proven difficult to access when generating a LUT from the rx_buffer.

If anyone can shed some insight over how these interrupts work? And how to make them applicable for a variable payload would be great.

Best answer by Pincate

The issue was caused by the DMA being configured to normal mode, and my hardware had a 512 byte cache that was filling up before triggering the interrupt or populating the buffer.

This was fixed by switching to circular mode.

3 replies

TDK
Super User
January 22, 2026

HAL_UARTEx_ReceiveToIdle_DMA should be used if you want notified when the stream becomes idle. Data is processed within the HAL_UARTEx_RxEventCallback callback which gets called in three cases:

  • When the data buffer is half-full (process first half of buffer)
  • When the data is complete (process second half of buffer)
  • When the stream becomes idle (process characters received)
"If you feel a post has answered your question, please click ""Accept as Solution""."
PincateAuthor
Associate III
January 22, 2026

Thank you. Do you know how the data is stored for both of these cases if using a DMA?

TDK
Super User
January 22, 2026

Data is stored in the buffer you point to. DMA transfers data from the peripheral to memory.

"If you feel a post has answered your question, please click ""Accept as Solution""."
PincateAuthor
Associate III
January 22, 2026

Thank you, from my understanding receive_to_idle stores the data in 512 byte segments, however when trying to write from this memory I have been struggling to access any data beyond this, even if I edit the address in the linker code, and check my buffer is fully populated.
the writing to a look up table is conducted as below:

 for (uint16_t k = 0, i = 5; i < length + 5; ++k, i += 2){
 lut[k] = (rx_buffer[i+1] | rx_buffer[i] << 8);
 if (lut[k] >= 4095) {
 lut[k] = 4095;
 }
 }

 


Edited to apply proper source code formatting - please see How to insert source code for future reference.

TDK
Super User
January 22, 2026

There is no 512-byte restriction or limitation or feature within HAL_UARTEx_ReceiveToIdle_DMA. The length of data depends on the size of the buffer and how much data was received.

You can see a working example of HAL_UARTEx_ReceiveToIdle_DMA here:

STM32CubeF4/Projects/STM32446E-Nucleo/Examples/UART/UART_ReceptionToIdle_CircularDMA/Src/main.c at 7c6a0a09ecb81b360de396479e048907563f1d10 · STMicroelectronics/STM32CubeF4

Data available in buffer is passed as a parameter to HAL_UARTEx_RxEventCallback.

"If you feel a post has answered your question, please click ""Accept as Solution""."
PincateAuthorBest answer
Associate III
February 19, 2026

The issue was caused by the DMA being configured to normal mode, and my hardware had a 512 byte cache that was filling up before triggering the interrupt or populating the buffer.

This was fixed by switching to circular mode.