cancel
Showing results for 
Search instead for 
Did you mean: 

UART not receiving as expected

KCB11
Associate II

Hello, I am completely new to STM32. I am using a RAK3172 based on the stm32wle5ccu6 chip. I have already tested some basic codes on it and works fine. I am trying to write a code to perform modbus communication with a certain device. So i started with implementing UART in the chip. Transmitting the data works exactly as intended. However I am not able to receive data more than once. I have started testing using this documentation: Getting Started with UART . 

Code:

 

 

while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  HAL_UART_Transmit(&huart2, tx_buff, 10, 1000);
	  if(HAL_UART_Receive(&huart2, rx_buff, 10, 10000)==HAL_OK) //if transfer is successful
		{
		  __NOP(); //You need to toggle a breakpoint on this line!
		} else {
		  __NOP();
		}
  }

 

 

I have connected the USART tx,rx line to USB-TTL converter and opened the connection in Arduino Serial monitor. I am able to transmit from the stm properly, however, when I send data from the Arduino serial monitor to the stm, the very first time it receives data properly,  but after that no matter how many times i send data from the serial monitor it never reaches the breakpoint.

I am also facing similar issue when using interrupt mode for UART. 
this code doesn't work:

 

 

/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, rx_buff, 10);
/* USER CODE END 2 */
.
.
.
.
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  HAL_UART_Receive_IT(&huart1, rx_buff, 10); //You need to toggle a breakpoint on this line!
}
/* USER CODE END 4 */

 

 

but this code kinda works:

 

 

  while (1)
  {
     HAL_UART_Receive_IT(&huart1, rx_buff, 10);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
..
.
.
.
.
.
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  HAL_UART_Receive_IT(&huart1, rx_buff, 10); //You need to toggle a breakpoint on this line!
}
/* USER CODE END 4 */

 

 

The first interrupt code is facing the exact same problem as the blocking code. It receives exactly once and never after that. But I saw i another post here that we shouldnt use the

HAL_UART_Receive_IT(&huart1, rx_buff, 10);

 withing a while loop. Any help is appreciated Thank you.

1 ACCEPTED SOLUTION

Accepted Solutions

You never checked HAL status when you called HAL_UART_Receive_IT

If it returns HAL_BUSY, then the interrupt didn't get enabled.

 

Here is another project similar to the first git project link, but this one uses DMA in Normal mode instead of Circular mode. It also shows how to check for HAL status and to call HAL_UART_Receive_DMA again if it didn't get enabled the first try, which is the same concept as HAL_UART_Receive_IT

https://github.com/karlyamashita/Nucleo-G431RB_Three_UART/wiki

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

View solution in original post

5 REPLIES 5

Both expect 10 bytes of valid data to arrive.

The polled version blocks and will likely timeout if your not responsive within the time window.

Also you'll need.to watch for and clear any reception errors. ie noise, framing, etc

Reception and Transmission can occur concurrently. 

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

I am sending HELLOWORLD first time then followed by TESTING123. When I checked in debug mode after the first try rx_buf= HELLOWORLD all is fine, then in the next iteration, I sent TESTING123, but the receive timesout and when i check rx_buf after the timeout it has value "\rELLOWORLD" i.e it got only one character. I also tried clearing the rx_buf after reception or creating new buffers for each iteration once it receives the \r no more characters are received after that i dont know why.

I tried to receive characters one by one and it received all characters but once it encounters this \r it just completely stops receiving characters i dont know why. I also wrote an if condition to continue the loop(skip and read next character) once it encounters a \r or \n character but it did nothing. I send data without \r\n at the end and I was able to receive both HELLOWORLD and TESTING123. What is going on?

EDIT: I have found out that if it ever receives more data than the buffer size it will no longer receive any data when read again. Is there any way to flush the uart buffer after reading it? What do I do if I receive more data than my buffer size?

You have HAL_UART_Receive_IT in a while loop which is the incorrect way of using it. You initialize it once to just to enable the interrupt.

Then in your HAL_UART_RxCpltCallback you enable it again. But you don't do anything with the data that you just received. You need to copy that received data to another buffer for parsing outside of the interrupt. 

 

Your strings are 10 characters but you also have a LF, or maybe CR/LF so that is 1 - 2 characters (11 or 12 bytes) more than your buffer size. So messages will start getting out of sync in your buffer and/or overrun error (ORE). 

 

If you have string that are different sizes you should instead take advantage of HAL_UARTEx_ReceiveToIdle_IT( or DMA) and HAL_UARTEx_RxEventCallback

 

This github project uses the DMA with idle detection. It can receive any string size, as long as you set the define for the buffer size. It copies the received DMA buffer data from the callback to a secondary larger circular buffer for parsing in the main while loop.

https://github.com/karlyamashita/Nucleo-G071RB_UART_DMA_Idle_Circular/wiki

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
KCB11
Associate II

OK  thank you. I just have one more doubt, if I send more than 10 bytes of data why does HAL_UART_Receive() function stop working after it. If I send 12 bytes of data then it should only lead to loss of 2 bytes right. If I send 10 bytes after some time after sending 12 bytes then HAL_UART_Receive() should receive it right? Why does HAL_UART_Receive() stop working as soon as it gets more data than the buffer size. Is there any way to flush the buffer or do I have to reset the device every time I get data more than the size of buffer? 

You never checked HAL status when you called HAL_UART_Receive_IT

If it returns HAL_BUSY, then the interrupt didn't get enabled.

 

Here is another project similar to the first git project link, but this one uses DMA in Normal mode instead of Circular mode. It also shows how to check for HAL status and to call HAL_UART_Receive_DMA again if it didn't get enabled the first try, which is the same concept as HAL_UART_Receive_IT

https://github.com/karlyamashita/Nucleo-G431RB_Three_UART/wiki

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.