cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H5 UART DMA Error Recovery

DPade.1
Associate III

Hello, I am working on a project using DMA and UART HD to communicate between multiple MCUs.  I have an issue where when one MCU starts up, it momentarily interrupts the UART HD bus and sometimes causes a UART and/or DMA error.

Since I am using the STM32CubeMX packages for the HAL libraries, I tried to recover from the issue by several means, but I noticed there seems to be no provided method in the stm32h5xx_hal to recover once hdmarx->State = HAL_DMA_STATE_ERROR.  Calling any of the UART or DMA abort functions (HAL_UART_Abort(), HAL_UART_AbortReceive(), HAL_UART_DMAStop()) does not reset the DMA State.  The call chain for HAL_UART_Receive_DMA() eventually checks the DMA State and just returns an error.

I have found 2 methods that manage to work around the issue, but I am not satisfied with them because they are not at all elegant:

Method 1: Call HAL_DMA_DeInit(), reset the Parent pointer back to huart, then call HAL_DMA_Init().  I feel like it might be missing some UART <-> DMA linkage that happens during the MX init functions...but I don't see a way to easily re-init the UART without copying/modifying the generated MX init functions.  But, this does eventually restore communications.  In this method, after the initial error, I get seven subsequent errors with the same code before the communication finally works again (below is an SWO dump, the Bus Error line is output from the UART_DMAAbortOnError() callback, the DMA reinit is performed in the Main Loop immediately before Rx is attempted again):

IPCC: Bus Error, UART ErrorCode = 0x00000004, DMA State = 0x00000003, DMA ErrorCode = 0x00000000
IPCC Deinit hdmarx
IPCC Reinit hdmarx
IPCC: Bus Error, UART ErrorCode = 0x00000004, DMA State = 0x00000003, DMA ErrorCode = 0x00000000
IPCC Deinit hdmarx
IPCC Reinit hdmarx
IPCC: Bus Error, UART ErrorCode = 0x00000004, DMA State = 0x00000003, DMA ErrorCode = 0x00000000
IPCC Deinit hdmarx
IPCC Reinit hdmarx
IPCC: Bus Error, UART ErrorCode = 0x00000004, DMA State = 0x00000003, DMA ErrorCode = 0x00000000
IPCC Deinit hdmarx
IPCC Reinit hdmarx
IPCC: Bus Error, UART ErrorCode = 0x00000004, DMA State = 0x00000003, DMA ErrorCode = 0x00000000
IPCC Deinit hdmarx
IPCC Reinit hdmarx
IPCC: Bus Error, UART ErrorCode = 0x00000004, DMA State = 0x00000003, DMA ErrorCode = 0x00000000
IPCC Deinit hdmarx
IPCC Reinit hdmarx
IPCC: Bus Error, UART ErrorCode = 0x00000004, DMA State = 0x00000003, DMA ErrorCode = 0x00000000
IPCC Deinit hdmarx
IPCC Reinit hdmarx

Methode 2:  Directly set uart->hdmarx->State = HAL_DMA_STATE_READY.  This does not re-init the DMA, but it does allow the UART to pass thru the DMA State check.  I only get 1 bus error and receive is immediately possible.

Method 2 seems much more stable, but I don't like manually changing the DMA state.  I think the DMA abort functions should be automatically clearing the HAL_DMA_State for us, or an API should be provided to properly reset it.  Is this an oversight in the ST HAL or is there some other intended way to recover from the DMA error?

2 REPLIES 2
Saket_Om
ST Employee

Hello @DPade.1 

 

An internal ticket with number 182303 has been submitted for this purpose.

Thank you for highlighting to us this issue.

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar

specifically regarding UART, DMA and H5 series, please check the following ERRATA:

https://www.st.com/resource/en/errata_sheet/es0621-stm32h523xx-and-stm32h533xx-device-errata-stmicroelectronics.pdf

Basicalliy: "USART does not generate DMA requests after setting/clearing DMAT bit"

A possible workaround is to don't clear this DMAT bit.

So look for any of: ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);

This is done, among other, in: static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)

 

So my guess is: if you are using UART+DMA and interrupts, I am quite sure that tha function "UART_DMATransmitCplt" is called and the DMA tx won't work anymore for the next transmission.

Maybe you have a chance if you are not using interrupt, but I am not sure.