cancel
Showing results for 
Search instead for 
Did you mean: 

Restore circular DMA RX after UART error

romanovda
Associate
Posted on August 10, 2017 at 03:50

Hi!

On both STM32F405 and STM32F745:

We use circular mode DMA RX. It works fine until the first frame or hight noise error occurs (which rarely but happen).

After the error DMA stops working. Naive calling HAL_UART_Receive_DMA doesn't help.

How to re-enable circular DMA receive again using STM32 HAL drivers? Or how to make DMA ignore framing and noising errors?

Details:

1. When error occurs, UART_DMAAbortOnError is called from DMA IRQ and it triggers HAL_UART_ErrorCallback where we see frame or high noise error HAL_UART_GetError.

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
 if (huart == &huart6)
 {
 // How to restore dma work here????
 // Last try witch is definately an overkill but it doesn't work
 __HAL_UART_CLEAR_PEFLAG(&huart6);
 HAL_UART_DMAStop(&huart6);
 HAL_UART_MspDeInit(&huart6);
 HAL_UART_MspInit(&huart6);
 HAL_UART_Receive_DMA(&huart6, rxBuffer, DUD_RX_BUFFER_LEN);
 // Also tried like but didn't work
 // HAL_UART_DMAStop(&huart6);
 // HAL_UART_Receive_DMA(&huart6, rxBuffer, DUD_RX_BUFFER_LEN);
 // And tried some other combinations
 // Shows FRAMING or HIGH noise ERROR
 //sprintf(dbgSndBuff, 'UART6 error %i DMA error %i \r\n', HAL_UART_GetError(&huart6), HAL_DMA_GetError(&hdma_usart6_rx));
 }
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

2. We have 'standard' CubeMX initialization code:

/* USART6 init function */
void MX_USART6_UART_Init(void)
{
 huart6.Instance = USART6;
 huart6.Init.BaudRate = 1000000;
 huart6.Init.WordLength = UART_WORDLENGTH_8B;
 huart6.Init.StopBits = UART_STOPBITS_1;
 huart6.Init.Parity = UART_PARITY_NONE;
 huart6.Init.Mode = UART_MODE_TX_RX;
 huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
 huart6.Init.OverSampling = UART_OVERSAMPLING_16;
 if (HAL_UART_Init(&huart6) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
/* USART6_RX Init */
 hdma_usart6_rx.Instance = DMA2_Stream1;
 hdma_usart6_rx.Init.Channel = DMA_CHANNEL_5;
 hdma_usart6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
 hdma_usart6_rx.Init.PeriphInc = DMA_PINC_DISABLE;
 hdma_usart6_rx.Init.MemInc = DMA_MINC_ENABLE;
 hdma_usart6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
 hdma_usart6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
 hdma_usart6_rx.Init.Mode = DMA_CIRCULAR;
 hdma_usart6_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
 hdma_usart6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
 if (HAL_DMA_Init(&hdma_usart6_rx) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart6_rx);
 /* USART6_TX Init */
 hdma_usart6_tx.Instance = DMA2_Stream6;
 hdma_usart6_tx.Init.Channel = DMA_CHANNEL_5;
 hdma_usart6_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
 hdma_usart6_tx.Init.PeriphInc = DMA_PINC_DISABLE;
 hdma_usart6_tx.Init.MemInc = DMA_MINC_ENABLE;
 hdma_usart6_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
 hdma_usart6_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
 hdma_usart6_tx.Init.Mode = DMA_NORMAL;
 hdma_usart6_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
 hdma_usart6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
 if (HAL_DMA_Init(&hdma_usart6_tx) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart6_tx);
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

3. CubeMX version 4.22,

STM32CubeF7 Firmware Package V1.7.0, STM32CubeF4 Firmware Package V1.0

P.S. Our protocol has data consistency check, so in general we don't care about single UART errors, so if DMA would ignore errors should work for us fine too.

#error #stm32 #hal #dma #uart
3 REPLIES 3
Posted on August 11, 2017 at 01:36

Hello!

Calling HAL functions(not all functions)  inside a HAL callback in handler mode, is an known issue that causes HAL Lock !!

Find another way, at least , not to call theese functions from inside callback.

check theese  functions if fits to your needs.

UART_DMARxAbortCallback(...

UART_DMAAbortOnError(...

HAL_UART_AbortReceive_IT(

Inside  relevant .c files you will find a lot of explanation about the use of functions.

Regards.

Gianfranco Favier
Associate II
Posted on September 18, 2017 at 13:05

We have the same problem on a STM32F051 device. At the moment the only solution that seems working for us is to comment (into the original HAL_UART_IRQHandler routine) these lines :

   huart->ErrorCode |= HAL_UART_ERROR_FE;    //-> framing error is not longer visible

   huart->ErrorCode |= HAL_UART_ERROR_NE;   

// -> noise error is not longer visible

   huart->ErrorCode |= HAL_UART_ERROR_ORE; 

// -> 

overrun 

error is longer not visible

[Also in our case the protocol has data consisency check, so we can trap in a higher level bad frames]

Heath Raftery
Associate II
Posted on June 01, 2018 at 11:04

We also have a 'standard' CubeMX circular DMA UART setup, which stops on error. Caused us some headaches, but ultimately able to resolve it thusly:

In DMA mode, a comms error actually triggers a DMA end of transfer interrupt (not a UART error). The DMA HAL picks this up, aborts the DMA and then calls the registered

XferAbortCallback

(see 

stm32f4xx_hal_dma.c:883

) which is actually

UART_DMAAbortOnError

. That then calls 

HAL_UART_ErrorCallback

, so once that callback runs the DMA is already aborted. Further, it turns out only a deliberate call to

HAL_UART_Abort_IT

ends up calling 

HAL_UART_AbortCpltCallback

, so in DMA mode UART DMA restoration needs to happen in 

HAL_UART_ErrorCallback

.

In the end, all we did is call

HAL_UART_Receive_DMA()

from 

HAL_UART_ErrorCallback

(once the error is logged/otherwise dealt with). No init/de-init, flag clearing or error suppressing necessary.

To the OP: is it possible you missed the simplest one-statement option in your efforts?

Anyone else solved it otherwise?