cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 UART DMA Receive unknown length of data.

MJ_1992
Associate II

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.

1 ACCEPTED SOLUTION

Accepted Solutions

@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

View solution in original post

13 REPLIES 13
gbm
Lead III

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
JMeye.2
Associate II

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.

@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.

RetroInTheShade
Associate III

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.

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

Piranha
Chief II

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

Thank you to all for replay

@JMeye.2​  AND @Piranha​  You mean I need to use Combinetion of 2 + 4. ?

Half and Full buffer interrupt and also give interrupt for Ideal ( i.e. HAL_UARTEx_ReceiveToIdle_DMA ).

I will check and inform.

But as my previous observation 4. ( Without Half and Full int. ). Whan function HAL_UARTEx_ReceiveToIdle_DMA call the variable "Size" upadted as per no. of bytes sent by PC. but I din't get any data in my buffer. This problem happens only some times. (May be same problem as NDTR and Data sync prblem in case 3).

@MJ_1992​  "Thank you to all for replay"

* reply

;)

@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