cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_UARTEx_ReceiveToIdle_DMA gives HAL_ERROR when already receiving

sdtbb
Associate III

Split from: HAL_UARTEx_ReceiveToIdle_DMA return HAL_ERROR when stm32's partner restart.

That thread is solved; this is a new question.


I think I'm seeing a similar problem if I call `HAL_UARTEx_ReceiveToIdle_DMA()` when the UART receive line is actively receiving data (when the other end is transmitting). A good percentage of the time it returns HAL_ERROR.

I'm using STM32L4 HAL 1.13.6 (Cube 1.18.2).

The problem is that the UART generates an overrun error immediately when `UART_Start_Receive_DMA()` enables the overrun error. The overrun error overwrites `huart->ReceptionType = HAL_UART_RECEPTION_STANDARD` which causes `HAL_UARTEx_ReceiveToIdle_DMA()` to return HAL_ERROR as shown in the code snippet from `HAL_UARTEx_ReceiveToIdle_DMA()` below:

    /* Set Reception type to reception till IDLE Event*/
    huart->ReceptionType = HAL_UART_RECEPTION_TOIDLE;
    huart->RxEventType = HAL_UART_RXEVENT_TC;

    status =  UART_Start_Receive_DMA(huart, pData, Size);

    /* Check Rx process has been successfully started */
    if (status == HAL_OK)
    {
      if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE) <<<< this check fails
      {
        __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_IDLEF);
        ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
      }
      else
      {
        /* In case of errors already pending when reception is started,
           Interrupts may have already been raised and lead to reception abortion.
           (Overrun error for instance).
           In such case Reception Type has been reset to HAL_UART_RECEPTION_STANDARD. */
        status = HAL_ERROR;  <<<< takes this path
      }

 I verified the problem with a tracepoint on husart3.ReceptionType. This is the stack trace:

Thread #1 [main] 1 [core: 0] (Suspended : Signal : SIGTRAP:Trace/breakpoint trap)	
	UART_EndRxTransfer() at stm32l4xx_hal_uart.c:3,810 0x801d6d8	
	HAL_UART_IRQHandler() at stm32l4xx_hal_uart.c:2,407 0x801c478	
	USART3_IRQHandler() at stm32l4xx_it.c:384 0x800d99a	
	<signal handler called>() at 0xfffffffd	
	UART_Start_Receive_DMA() at stm32l4xx_hal_uart.c:3,752 0x801d584	
	HAL_UARTEx_ReceiveToIdle_DMA() at stm32l4xx_hal_uart_ex.c:961 0x801dc2a	
	StartUsart3Reception() at main.c:2,603 0x800a218	
	commandTaskMain() at main.c:3,385 0x800abe8	
	pxPortInitialiseStack() at port.c:222 0x8024c90	

This is where UART_Start_Receive_DMA() is interrupted (stm32l4xx_hal_uart.c:3,752):

3751  /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
3752  ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_EIE);

And here is where we are in HAL_UART_IRQHandler():

2401      if ((HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) ||
2402          ((errorcode & (HAL_UART_ERROR_RTO | HAL_UART_ERROR_ORE)) != 0U))
2403      {
2404        /* Blocking error : transfer is aborted
2405           Set the UART state ready to be able to start again the process,
2406           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
2407        UART_EndRxTransfer(huart); <<<<<< We are here

 

A dirty hack workaround is to loop on the UART initialization until it succeeds:

    bool success = false;
    for (int i = 0;i < 5; i ++) {
        MX_USART3_UART_Init();
		if (HAL_OK == HAL_UARTEx_ReceiveToIdle_DMA(&huart3, Usart3RxDMABuffer, sizeof(Usart3RxDMABuffer))){
            success = true;
            break;
	    }
	    MX_USART3_UART_DeInit();
	    vTaskDelay(100);
    }

This works for me - but I don't like it. I also considered de-initializing the UART receive GPIO prior to calling `HAL_UARTEx_ReceiveToIdle_DMA` and reinitializing immediately after - but that's not really any more palatable to me.

Either I'm doing something wrong with HAL, or there is a fundamental race condition in `HAL_UARTEx_ReceiveToIdle_DMA` if it is called while the UART receive line is seeing receive activity - which seems really fragile.

I would welcome any feedback - particularly if I'm doing something wrong that is creating this condition.  Thanks in advance.

1 REPLY 1
TDK
Super User

@sdtbb This thread has been solved. Create a new thread if you're having issues.

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