Restore circular DMA RX after UART error
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