cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_UART_Receive Timeout

skon.1
Senior

Hello,

I'm trying to understand: When will the HAL_UART_Receive function return HAL_TIMEOUT ?

Will it happen only when the "Timeout" value has passed ?

/**
  * @brief Receive an amount of data in blocking mode.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         the received data is handled as a set of u16. In this case, Size must indicate the number
  *         of u16 available through pData.
  * @param huart   UART handle.
  * @param pData   Pointer to data buffer (u8 or u16 data elements).
  * @param Size    Amount of data elements (u8 or u16) to be received.
  * @param Timeout Timeout duration.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint8_t  *pdata8bits;
  uint16_t *pdata16bits;
  uint16_t uhMask;
  uint32_t tickstart;
 
  /* Check that a Rx process is not already ongoing */
  if (huart->RxState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return  HAL_ERROR;
    }
 
    __HAL_LOCK(huart);
 
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;
 
    /* Init tickstart for timeout managment*/
    tickstart = HAL_GetTick();
 
    huart->RxXferSize  = Size;
    huart->RxXferCount = Size;
 
    /* Computation of UART mask to apply to RDR register */
    UART_MASK_COMPUTATION(huart);
    uhMask = huart->Mask;
 
    /* In case of 9bits/No Parity transfer, pRxData needs to be handled as a uint16_t pointer */
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    {
      pdata8bits  = NULL;
      pdata16bits = (uint16_t *) pData;
    }
    else
    {
      pdata8bits  = pData;
      pdata16bits = NULL;
    }
 
    __HAL_UNLOCK(huart);
 
    /* as long as data have to be received */
    while (huart->RxXferCount > 0U)
    {
      if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }
      if (pdata8bits == NULL)
      {
        *pdata16bits = (uint16_t)(huart->Instance->RDR & uhMask);
        pdata16bits++;
      }
      else
      {
        *pdata8bits = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
        pdata8bits++;
      }
      huart->RxXferCount--;
    }
 
    /* At end of Rx process, restore huart->RxState to Ready */
    huart->RxState = HAL_UART_STATE_READY;
 
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

5 REPLIES 5
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }

> Will it happen only when the "Timeout" value has passed ?

 

It will happen when time from the last received byte is longer than Timeout.

JW

Actually it will happen when the time from when the function was called is longer than the timeout, not time between bytes. "tickstart" is only set once, near the top of the function.

I stand corrected

JW

If it gets data you can use it will return HAL_OK.

If you get HAL_TIMEOUT you'll need to resubmit your request.

I would generally recommend NOT using blocking functions, as it precludes the MCU doing other useful work, or sleeping.

You often want to be receiving data concurrently on multiple interfaces, and this is best handled with interrupts and buffering.

Frankly not something HAL does particularly elegantly either.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Piranha
Chief II

Also, if that function receives data, but the size of the data is less than the size of the given buffer, it will return HAL_TIMEOUT and user even hasn't an API for retrieving the size of actually received data. One can deduce it from RxXferCount, but that's a workaround.

HAL is designed and implemented by brainless code monkeys and therefore is almost useless. In a long term it's easier to implement your own drivers and interfaces.