cancel
Showing results for 
Search instead for 
Did you mean: 

Sending Serial Data from one UART to another. HAL_UART_Receive not reading new bytes.

DWalt.1
Associate II

My Board is the STM32-G431KB Nucleo-32. I have a Mavlink Serial Tx/Rx (From a PX4 Autopilot) connected to PA10/PA9.

I am attempting to receive serial data at 115200 8N1 on UART1 and then send it at the same rate on UART2. I am just doing a basic polling implementation of HAL_UART_Receive() grabbing a single byte at a time.

Unfortunately, HAL_UART_Receive only gets the first byte and transmits it. After the first loop, HAL_UART_Receive doesn't get any new data from the serial line. I can see there is good data coming in on UART1 with a logic analyzer. If I don't set to 0 in the while loop, it just transmits out the last byte received over and over.

int main(void)
{
   /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
   /* Configure the system clock */
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
 
    /* Infinite loop */
  while (1)
  {
	  uint8_t c = 0;
	  HAL_UART_Receive(&huart1, &c, 1, 1);
	  HAL_UART_Transmit(&huart2, &c, sizeof(c), 0xFFFF);
   }
}

Can anyone point out where I'm going wrong? I expected HAL_UART_Receive to work like Arduino's 'serial->read'. Is there another step to force HAL_UART to grab a new byte?

Edit:

Using @KnarfB​ 's example below and the "uart forwarding" works fine. Incoming bytes on UART1 are transmitted out UART2 - as I intended.

while (1)
  {
	  if( USART1->ISR & USART_ISR_RXNE ) {
		  char c = USART1->RDR & 0xFF;
	      while( (USART2->ISR & USART_ISR_TXE) == 0 );
	          USART2->TDR = c;
	  }
 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
	  //HAL_Delay(20);
  }

Can anyone explain to me what I'm doing wrong with HAL_UART_Receive?

Edit: I believe I solved this by setting the parameter 'Fifo Mode' to 'Enable'

18 REPLIES 18

HAL_UART_Receive returns HAL_TIMEOUT whether I set the timeout to 1ms or 5000ms. Which is odd because I can see data on the line with a logic analyzer

It looks like HAL_UART_Receive is returning '3' (HAL_TIMEOUT) after the first byte.

Thanks, your above code works fantastic by changing the USART2 on lines 5 and 6 to USART1. STM32G431KB is streaming the mavlink from uart1 to uart2 and receiving fine on my desktop.

I can't figure out why this doesn't work with the HAL_UART_Receive.

Hi DWalt.1, good to hear that it works for you. Don't have a STM32G431KB but a STM32G431RB. If you send my the complete sources I will look at it.

KnarfB

DWalt.1
Associate II

I may have solved this by setting Fifo Mode to "Enable". By default, this Parameter is disabled.

@KnarfB​ does this sound right?

Luckily my final implementation is not serial forwarding, but this was an initial step to ensure I was getting the correct serial data.

I may have solved this by setting the 'Fifo Mode' to 'Enable' which was not the default value. Does this sound correct?

Well, I suggested to check if there was overflow in UART (UART_ISR.ORE), but if yes, FIFO might have solved it.

The fundamental difference between KnarfB's code and Cube/HAL is, that, as I've said above, Cube's Tx routine waits until TC after the last character.

JW

Glad you solved it. Two minor remarks.

The HAL loop worked for me on STM32-G431RB Nucleo-64 when not using timeouts, i.e.

 while (1)
  {
	  HAL_StatusTypeDef status = HAL_UART_Receive(&huart2, &c, 1, 0 );
	  if (status == HAL_OK) {
		  HAL_UART_Transmit(&huart2, &c, sizeof(c), 0 );
	  }
  }

Basically, if you start using timeouts, HAL uses SysTick which is comparatively slow (1ms) and not well suited for single char timeouts. And yes, with timeouts I saw overflows as @Community member​ suspected. The bad thing is that the HAL API encourages using timeouts.

FIFO mode is only avail in some MCU series and I haven't used it here, but I know it from the famous 16550 UART and clones. Proper error handling and recovery can be a serious issue for serial comm. This might get worse when FIFOs are used.

PS: I was surprised to see that the G4 Nucleo-32 board has the SWO pin available. This is a nice debugging aid for debugging by tracing, previously available only on larger boards.

Fantastic answer, thanks for the information. This is my first time tipping my toes into "real" embedded development as most of my experience is working with arduino. I am just trying to achieve an initial start point with some working serial comms and can look at a more robust implementation down the road.