cancel
Showing results for 
Search instead for 
Did you mean: 

UART & DMA overrun error

zioMorgan
Associate II

Hi all.

I'm working on a project where my MCU (STM32H755) communicate with a device via UART at 921600 Bauds.

Here some details about the environment:

The device sends constantly, each second, a log at 921600 Bauds. 

The MCU sends at same speed some commands to the device, the device will answer after that the command is executed and continue to sends out log. There isn't any synchronization mechanism for communication (no clock signal or CTS/RTS is used), plus, there isn't any difference or special character that will allow me to differentiate between command answer and log, so I must take everything I receive in a window of time and parse it at upper level (not relevant for this question), and, finally, to manage the communication I tried with FIFO enabled and disabled (but result seems to not change)

What I do to manage the communication is the following:

1a: Flush Read data register (but is this sufficient in case of FIFO enabled?)

2a: Enable DMA via HAL_UART_RECEIVE_DMA API

3a: Enable UART peripheral setting the UE bit into CR1 register.

4a: transmit data in polling mode.

 

For reception, I set the Number of bytes to receive to 20KB but I will never receive this amount of data, I need this because the device constantly sends me log and when it will answer, the command answer will be sent between 2 logs.

After a certain time (timer interrupt), I do the following to manage the communication end.

1b: disable UART via UE bit.

2b: Abort DMA reception via UART_ABORT_DMA API.

3b: flush Read Data register.

What happens is that sometimes, after the step 2a (with FIFO enabled) or randomly during reception process (if FIFO disabled) an overrun error (ORE bit) fires and the DMA will abort. As result I will find only 1 character into my Rx buffer instead a log+command answer, or some garbage characters or no characters.

I tried to manage the error calling interrupt API, clearing error flag and resuming DMA but this seems to not work.

The DMA is serving requests coming from ADC1 and 2 too, but the priority of the UART request is set to Very high, meanwhile for the ADCs the priority is set to normal.

How can I properly manage this communication on a clean way?

4 REPLIES 4
AScha.3
Super User

Hi,

dont know how to find out, whats wrong on the rx data, maybe spike on the line ? try to find/reduce the disturbing source.

+

What i do, with a random error...just throw away and go on.

So need restart dma after error, this is my way:

(  = > you need to handle the error and restart, what it should do:)

here for spi->dma , just change to uart_xxx :    at main "setup" 

 HAL_SPI_RegisterCallback(&hspi4, HAL_SPI_RX_COMPLETE_CB_ID, HAL_SPI_RxCpltCallback);
 HAL_SPI_RegisterCallback(&hspi4, HAL_SPI_ERROR_CB_ID,  HAL_SPI_ErrorCallback );

....

	fresult = HAL_SPI_Receive_DMA(&hspi4, ...);   // start spi -> dma

...then in the error callback:

void  HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi4)
{
	fresult = HAL_SPI_Abort(hspi4);
	printf("SPI4: restart \n");   // show on SWO message
	fresult = HAL_SPI_Receive_DMA(hspi4, ESPinbuf , (sizeof(ESPinbuf)));	// input-loop start again
}

So on error ...it just goes on.

If you feel a post has answered your question, please click "Accept as Solution".
TDK
Super User

> How can I properly manage this communication on a clean way?

If characters are being received effectively continuously , definitely do not disable the peripheral.

When you receive characters and the peripheral is not ready to receive with DMA set up, this will trigger an ORE flag. This is entirely avoidable. There is nothing random about when ORE happens--it triggers on specific conditions.

Rather, keep the buffer receiving at all times and poll the available data continuously or use a callback.

One way to manage this is to set up the reception into a circular buffer and handle data in that buffer on the IDLE/HT/TC flags. See example usage of HAL_UARTEx_ReceiveToIdle_DMA. Here is an example for the F4 series. The interface is the same for the H7.

STM32CubeF4/Projects/STM32446E-Nucleo/Examples/UART/UART_ReceptionToIdle_CircularDMA/readme.txt at 9b91bb119728764cc0ed8f101f37aa465dd1f442 · STMicroelectronics/STM32CubeF4

Data should be processed within HAL_UARTEx_RxEventCallback which is called automatically when (a) the line goes idle or (b) the buffer reaches it half-full (HT) or (c) full (TC).

If you feel a post has answered your question, please click "Accept as Solution".
gbm
Principal

AFAIK, no chance for this to work reliably using HAL.

No problem without HAL - setup UART for reception with interrupts, call your function on every character received. 20 kHz interrupt frequency is not a big deal even on STM32F1 assuming you don't use HAL for this.

DMA could be used with double buffering or half transfer interrupt and continuous operation. I am not sure if such setup is possible with HAL - maybe it is.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Thank you, honestly if possible (just because I want to implement in the best way) I'll look for DMA working on continuous mode. When I must communicate with the device, I will first clean my buffer, set DMA and enable UART and let DMA take all the data it can, then, after the time window, I'll disable the UART and restart DMA to let it point to the start of my buffer.

Hoping this works