Skip to main content
MJ_1992
Associate II
July 18, 2022
Solved

STM32H7 UART DMA Receive unknown length of data.

  • July 18, 2022
  • 5 replies
  • 14113 views

I use STM32H753 and USART1 with DMA to receive data of unknown length (Min: 8 bytes Max: 512 bytes) from PC. Data will be sent in burst after every one second. My baud rate is 9600. So approx 1ms per byte.

So, maximum, I'm going to get all the data in 512 ms and I'm free to analyze the data for another 488 ms.So, I want some algorithm so that I can parse all data (Min: 8 bytes Max: 512 Bytes) on DMA after all data received.

I am using follwoing methods.

1) Receiving without DMA and interrupt on every byte.

-> Working fine. But the more CPU interference required. 

2) Receiving with Half and Full transfer interrupt with DMA.

-> Working fine but sometime we need to wait for one second (or more than that, depending upon buffer size) till the filling the buffer (HALF or FULL). It makes the communication process slower.

3) Receiving with DMA_CIRCULAR with DMA and keep eye on NDTR of DMA Stream.

-> Working fine but sometime we get error because NDTR updates first after receiving data in UART peripheral. And then DMA will copy data into memory.

4) Receiving with DMA_NORMAL with DMA and using "HAL_UARTEx_ReceiveToIdle_DMA"

-> Working fine but some time call back calls (with "Size") before actual data received in memory. Same problem as point no 3.

So please suggest best method for my case.

This topic has been closed for replies.
Best answer by JMeye.2

@MJ_1992​ Maybe check out this page for implementing Idle detection and the correct way to use the variable "Size". Without source code its hard to judge why your code dosen't work.

Link 1: https://controllerstech.com/uart-dma-with-idle-line-detection/

Link 2: https://github.com/STMicroelectronics/STM32CubeF4/blob/52757b5e33259a088509a777a9e3a5b971194c7d/Projects/STM32446E-Nucleo/Examples/UART/UART_ReceptionToIdle_CircularDMA/Src/main.c#L345

5 replies

gbm
Lead III
July 18, 2022

Using DMA for UART reception is usually not a good idea. Not that it can't be done but the programming overhead is much higher than for simple UART interrupts.

My advice: don't use HAL for UART, write your own UART ISR for reception and initial interpretation of data (packet assembly).

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
Andrew Neil
Super User
July 18, 2022

@gbm​ "don't use HAL for UART"

Well, don't use it for the interrupt handling - which needs to be quick.

You could still use it for the setup - as that only happens at startup, so it doesn't need to be quick.

@MJ_1992​ "1) Receiving without DMA and interrupt on every byte -> Working fine. But the more CPU interference required"

It shouldn't take a lot of CPU effort - just get the received byte, and put it into a buffer (usually, a circular buffer).

Handling of the received data should be handled outside the ISR.

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
JMeye.2
Associate II
July 18, 2022

For 2. you could implement a timeout interrupt via a timer that processes the data earlier if data transmission is slow. Make sure to set the interrupt prioritys for dma and timer correct to avoid problems.

As your data rate is very slow I would just implement a interrupt for reception without the DMA as @gbm​ already mentions.

Piranha
Principal III
July 18, 2022

USART on the newer STM32 series have an IDLE and RTO features and interrupts, which solves this problem easily.

RetroInTheShade
Associate
July 18, 2022

Hi, I have found that ‘4’ works very well when data will be delivered in discrete bursts … but as others suggested, at 9600 it’s probably not necessary and interrupt based solution will suffice.

If you do head in in ‘4’ direction, there is a requirement to carefully discriminate between ‘Half Full’ and ’Idle’ when using HAL implementation (at least on F4).

Let me know if you need details on this.

Piranha
Principal III
July 18, 2022

The HAL/Cube developers are incapable of understanding that a typical USART is a stream interface, therefore they have not been capable of designing an appropriate API.

https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx

Piranha
Principal III
July 20, 2022
for (uint8_t i = 0; i < BufferNeedToparse->RcvdDataSize; i++)
{
	ParseReceivedByte(BufferNeedToparse->Data[i]); // <-- Final parsing for received data
	BufferNeedToparse->Data[i] = 0x00; // Erase data from which is used
}

Generally for loops, indexes and such uses on 32-bit CPUs one should use 32-bit variables. Native sizes perform better because smaller types can sometimes require additional instructions. The best standard integer type for these purposes is the size_t.