cancel
Showing results for 
Search instead for 
Did you mean: 

How to check the UART Serial Buffer If They Are Available using HAL Library

CDolo.1
Associate II

I am using STM32F429 in my project which connects to an ATmega2560 thru UART. In arduino, there is a function Serial.Available() to check if the serial buffer is empty or not.

Is there a function in STM32 that is similar to Serial.Available() in Arduino?

BTW, I am using HAL libraries in STM32CubeIDE and HAL_UART_Receive(huart, pData, Size, Timeout) to read the contents of UART buffer.

Please help. Thanks!

PS. I've read the documentation in HAL library but I'm not sure if there is one. I've looked into HAL_UART_GetState but Im not sure.

1 ACCEPTED SOLUTION

Accepted Solutions
KnarfB
Principal III

There is no simple equivalent to Serial.Available() in HAL. But, when you call HAL_UART_Receive with timeout 0 and buffer size 1, it will return with HAL_TIMEOUT if there was no char available or HAL_OK if there was a char which is returned in the pData buffer. At register level, you can probe for available chars using __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE) == receive register not empty.

The reason is, that there is no receive buffer managment implemented in HAL. You just read from the hardware registers. This also means that you must quite often check for available chars, otherwise you will miss some. This topic is regularily discussed here :-) Remedies include using interrupts or cyclic DMA for receive, effectively implementing a receive buffer mangement. Tilen Majerle has nice blog posts and code for that: https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx

hth

KnarfB

View solution in original post

10 REPLIES 10
KnarfB
Principal III

There is no simple equivalent to Serial.Available() in HAL. But, when you call HAL_UART_Receive with timeout 0 and buffer size 1, it will return with HAL_TIMEOUT if there was no char available or HAL_OK if there was a char which is returned in the pData buffer. At register level, you can probe for available chars using __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE) == receive register not empty.

The reason is, that there is no receive buffer managment implemented in HAL. You just read from the hardware registers. This also means that you must quite often check for available chars, otherwise you will miss some. This topic is regularily discussed here :-) Remedies include using interrupts or cyclic DMA for receive, effectively implementing a receive buffer mangement. Tilen Majerle has nice blog posts and code for that: https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx

hth

KnarfB

CDolo.1
Associate II

Thank you for this. At register level, I use this right? --

	while(1) {
		if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_RXNE) == SET) {													
			HAL_UART_Receive(&huart3, (int16_t *) &CAM_reso_W, 2, 1000);
                }
         }									

Is that correct?

Looks reasonable.

But, it also depends on how reliable your communication timing is. When 2 chars are sent in a row, HAL_UART_Receive will happily return HAL_OK (which you should check) and the buffer contains the result. If only one char is sent within 1000 ms, HAL_UART_Receive will return HAL_TIMEOUT and there is no return value indicating how many chars were read. Okay here must be at least 1 because the register was not empty and less than 2, so you can deduce the result. But: not if you had choosen a larger buffer.

As said in my first reply, you really have to check often, because there is no buffer keeping chars for you inbetween calls to HAL_UART_Receive.

hth

KnarfB

If HAL_UART_Receive returns HAL_TIMEOUT, huart->RxXferCount is the number of remaining characters not received.

So you can know how many characters are received.

-- pa

Oops, you're right, Pavel. I forgot about that.

I've tried making a consecutive send to the STM32 serial buffer but it won't work.

This is my code in STM32:

uint8_t handshake_ATmega = 0;
uint8_t handshake_ATmega2 = 0;
uint8_t Ack_ATmega = 0x18;
uint8_t Ack_ATmega2 = 0x30;
 
  while(1) {
	  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
	  HAL_Delay(500);
 
	  if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) == SET) {
		  HAL_UART_Receive(&huart2, (uint8_t *) &handshake_ATmega, 1, 100);
 
		  if (handshake_ATmega == 0x20) {
			  HAL_UART_Transmit(&huart2, (uint8_t *) &Ack_ATmega, 1, 100);
 
			  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
			  //HAL_Delay(500);
 
			  if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) == SET) {
				  HAL_UART_Receive(&huart2, (uint8_t *) &handshake_ATmega2, 1, 100);
 
				  if (handshake_ATmega2 == 0x40) {
					  HAL_UART_Transmit(&huart2, (uint8_t *) &Ack_ATmega2, 1, 100);
 
					  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
					  HAL_Delay(500);
					  break;
				  }
				  else {
					  continue;
				  }
			  }
		  }
		  else {
			  continue;
		  }
	  }
 
  }

And this is the code in Arduino:

uint8_t handshake1 = 0;
uint8_t handshake2 = 0;
 
  Serial.begin(9600);                                                                        
  Serial1.begin(9600);                                                                           
 
  Serial.println("UART Communication test\r\n\n");
  Serial1.write(0x20);
  Serial.println("Sending 1st Handshake to STM32 MCU\n");
 
  while(1){
    if (Serial1.available()){
    handshake1 = Serial1.read();
    Serial.println (handshake1, HEX);
      
      if (handshake1 == 0x18){
        Serial.println("1st Acknowledgement Received from STM32 MCU\r\n\n");
        delay(500);
 
        Serial1.write(0x40);
        Serial.println("Sending 2nd Handshake to STM32 MCU\n");
        
        if (Serial1.available()){
          handshake2 = Serial1.read();
          Serial.println (handshake2, HEX);
          
          if (handshake2 == 0x30) {
            Serial.println("2nd Acknowledgement Received from STM32 MCU\n");
            break;
          }
        }
      }
    }
  }

This is the output in the serial monitor:

0693W000008wVucQAE.jpgIt works in the first handshake and acknowledgement, but it wont work on the second.

What is wrong with this?

Well, I won't debug deep into your code. Add some tracing as described here STM32 microcontroller debug toolbox. A first glance it seems like after the condition in line 10 is fulfilled for the very first time, the condition in line 19 is not immediately fulfilled and the prog continues, reading the 2nd handshake with the first transmit?

Generally speaking: better use a (simple) state machine than hard coding the communications flow.

hth

KnarfB

I managed to get the right code. But I feel this is not very efficient, gotta learn to use the HAL library more.

STM32 Code:

while(!break_loop) {
 
	  if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) == SET) {
		  HAL_UART_Receive(&huart2, (uint8_t *) &handshake_ATmega, 1, 100);
		  HAL_Delay(500);
		  __HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_RXNE);
 
		  if (handshake_ATmega == 0x20) {
			  HAL_Delay(500);
		          HAL_UART_Transmit(&huart2, (uint8_t *) &Ack_ATmega, 1, 100);
 
			  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
			  HAL_Delay(500);
 
			  while (1) {
				  if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) == SET) {
					  HAL_UART_Receive(&huart2, (uint8_t *) &handshake_ATmega2, 1, 100);
					  HAL_Delay(500);
					  __HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_RXNE);
 
					  if (handshake_ATmega2 == 0x40) {
						  HAL_Delay(500);
						  HAL_UART_Transmit(&huart2, (uint8_t *) &Ack_ATmega2, 1, 100);
 
						  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
						  HAL_Delay(500);
						  break_loop = 1;
						  break;
					  }
					  else {
						  continue;
					  }
				  }
			  }
		  }
		  else {
			  continue;
		  }
	  }
 
  }

Arduino Code:

while(!break_loop){
    if (Serial1.available()){
    handshake1 = Serial1.read();
    Serial.println (handshake1, HEX);
    delay(500);
      
      if (handshake1 == 0x18){
        Serial.println("1st Acknowledgement Received from STM32 MCU\r\n\n");
        delay(500);
 
        Serial1.write(0x40);
        Serial.println("Sending 2nd Handshake to STM32 MCU\n");
 
        while(1) {
          if (Serial1.available()){
            handshake2 = Serial1.read();
            Serial.println (handshake2, HEX);
            delay(500);
            
            if (handshake2 == 0x30) {
              Serial.println("2nd Acknowledgement Received from STM32 MCU\n");
              delay(500);
              break_loop = 1;
              break;
            }
            else {
              continue;
            }
          }
        }
      }
      else {
        continue;
      }
    }
  }

Serial Monitor Output:

0693W000008wWunQAE.jpg

>>What is wrong with this?

Bails early if no data available, doesn't have a re-entry strategy

Nesting posts on this "forum" is seriously broken

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