cancel
Showing results for 
Search instead for 
Did you mean: 

G070KBT6 - HAL_UART_Receive function return HAL_TIMEOUT early.

jgwsjgsgs
Associate II

I called the "HAL_UART_Receive" function in my "at_send_cmd" function and set its timeout parameter to 30 seconds, but I observed that the function immediately returned HAL_TIMEOUT.
My SysTick should be working properly, and I can use the HAL_Delay function normally.

When I call the "at_send_cmd" function, it can send data normally, but cannot receive data normally because of timeout.

 

#include "atcmd.h"

uint8_t at_rx_buffer[512];

static void at_clean_buffer(UART_HandleTypeDef* usart){
	uint8_t buffer;

	while (HAL_UART_Receive(usart, &buffer, 1, 0) == HAL_OK);
}

uint16_t at_send_cmd(UART_HandleTypeDef* usart, const char* cmd, uint8_t offset, uint8_t rx_length, uint16_t timeout){
	uint8_t i = 3, result;
	uint16_t cmd_length = strlen(cmd);

	while (i > 0){
		at_clean_buffer(usart);
		HAL_UART_Transmit(usart, (const uint8_t*)cmd, cmd_length, 3000);

		if ((result = HAL_UART_Receive(usart, at_rx_buffer, cmd_length + offset + rx_length, timeout)) == HAL_OK){
			at_rx_buffer[cmd_length + offset + rx_length] = '\0';
			return cmd_length + offset;
		}else if (result == HAL_TIMEOUT){
			printf("Timeout.\r\n");
		}

		i--;
	}

	return 0;
}

 

 

uint8_t ec800m_mqtt_connect(){
	if (USART == NULL) return 0;

	uint16_t index;

	//Set MQTT Config
	at_send_cmd(USART, EC800M_CMD_CONFIG, 0, 2, AT_TIMEOUT);
	HAL_Delay(1000);

	//Open
	if ((index = at_send_cmd(USART, EC800M_CMD_OPEN, 0, 15, 30000)) != 0){
		printf("%s\r\n", at_rx_buffer + index);
	}else{
		printf("Error.\r\n", index);
	}
	HAL_Delay(1000);

	//Connect
	at_send_cmd(USART, EC800M_CMD_CONN, 0, 2, 30000);

	return 0;
}

 

 

 

/**
  * @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.
  * @note When FIFO mode is enabled, the RXFNE flag is set as long as the RXFIFO
  *       is not empty. Read operations from the RDR register are performed when
  *       RXFNE flag is set. From hardware perspective, RXFNE flag and
  *       RXNE are mapped on the same bit-field.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         address of user data buffer for storing data to be received, should be aligned on a half word frontier
  *         (16 bits) (as received data will be handled using u16 pointer cast). Depending on compilation chain,
  *         use of specific alignment compilation directives or pragmas might be required
  *         to ensure proper alignment for 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;
    }

    /* In case of 9bits/No Parity transfer, pData buffer provided as input parameter
       should be aligned on a u16 frontier, as data to be received from RDR will be
       handled through a u16 cast. */
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    {
      if ((((uint32_t)pData) & 1U) != 0U)
      {
        return  HAL_ERROR;
      }
    }

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;
    huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;

    /* Init tickstart for timeout management */
    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;
    }

    /* as long as data have to be received */
    while (huart->RxXferCount > 0U)
    {
      if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
      {
        huart->RxState = HAL_UART_STATE_READY;

        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;
  }
}

Hope someone can help me :(

1 ACCEPTED SOLUTION

Accepted Solutions
8 REPLIES 8
MM..1
Chief II

Why your clean buf receive ??

Mainly, I don't want the previous data to affect my program. Before sending the AT command, the buffer will be cleared first.

 

static void at_clean_buffer(UART_HandleTypeDef* usart){
	uint8_t buffer;

	while (HAL_UART_Receive(usart, &buffer, 1, 0) == HAL_OK);
}

 

use receive to clear buf is absurd or your mistake... simply memset buffer to zero, but no internal buffer variable, this is next absurd.

> called the "HAL_UART_Receive" function in my "at_send_cmd" function and set its timeout parameter to 30 seconds,

The first call to at_send_cmd() is with AT_TIMEOUT, what's that value?

Btw. Cube/HAL is open source so you can debug it as your own code.

JW

 

AT_TIMEOUT is 3000, but it also cannot block the specified time.

Now I use interrupts to receive data instead of blocking, so the problem has been solved. I should try this solution in the future. Anyway, thank you for your help.

Clearing the UART_FLAG_ORE is useful, although I don't quite understand how this issue occurs.