cancel
Showing results for 
Search instead for 
Did you mean: 

Receive command UART polling mode using LL library

MCUnoob
Associate II

Hi everyone!

I've been trying to implement UART reception using LL library in polling mode. The code below is what handles the reception:

uint8_t LL_USART_Receive_Byte(USART_TypeDef *USARTx) {
	// Wait for Read Data Register is not empty
	while (!LL_USART_IsActiveFlag_RXNE(USARTx));
	return LL_USART_ReceiveData8(USARTx);;
}
 
/**
 * @brief Receive `len` amount of bytes on USARTx by calling LL_USART_Receive_Byte function.
 * Usually, this function will be used to receive data in our programs.
 * @param USARTx USART instance.
 * @param buff Receive buffer.
 * @param len Amount of bytes to receive
 */
void LL_USART_Receive(USART_TypeDef *USARTx, uint8_t *buff, uint32_t len) {
	for (int i = 0; i < len; i++) {
		buff[i] = LL_USART_Receive_Byte(USARTx);
	}
}

In order to test it, I have interconnected the UART6 Tx and UART1 Rx pins in the MCU and in the main program I simply send a message.

/* USER CODE BEGIN 2 */
  uint8_t textTx[8] = "Hello!\r\n";
  uint8_t textRx[8] = {};
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  LL_USART_Transmit(USART6, textTx, sizeof(textTx));
	  LL_USART_Receive(USART1, textRx, sizeof(textRx));
	  LL_mDelay(2000);
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

The transmit function is working as expected, but the problem is that it only receives the first character. I tested it in debug mode and checked Live Expressions and Variables.

The problem is because LL_USART_Receive_Byte() function is stuck in the while (!LL_USART_IsActiveFlag_RXNE(USARTx)) loop after receiving the first character. The first iteration of the for loop in LL_USART_Receive is fine but when receiving the second character is not working anymore.

I see that the problem is something related to the RXNE flag and maybe with Overrun flag as well as I read in the docs but I can't figure out how to read the whole message.

Hope someone can help me :)

7 REPLIES 7
Bruno_ST
ST Employee

Hello @MCUnoob​,

Yes, I don't know which MCU you are using but effectively, Overrun flags is raised and you have lost the rest of the characters.

I would suggest if you want to keep this interconnect tests on USART on the same MCU :

1) to use IT rather than polling for reception & emission of characters if you want to keep the above loop

2) transmit & receive 1 character at a time

BR,

Bruno

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Piranha
Chief II

First you transmit all of the bytes and then you start reception... You are lucky to get receive even the first byte. ;)

https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx

I don't really want to keep this interconnection, I set it up as a test in order to make sure how to implement UART Tx & Rx in polling mode using LL drivers. The main goal is to substitute the HAL functions HAL_UART_Transmit(...) & HAL_UART_Receive(...) with LL drivers in order to transmit and receive commands and its respones (fixed and known lengths).

By the way, I use STM32F401RE both in test and development environment. With IT, how could I receive a fixed length message?

Thank you for your time.

Why am I lucky? It is not suposed to work? I've seen the DMA approach, but I sticked to the polling mode solution (but it seems not to be ideal).

By the time you start to listen, the transmitted bytes are all gone.

JW

I see. Is this because of my test set up using various UARTs in the same MCU or it will be the same with UART communication between a STM32 & a modem SIM7070G?

What you basically need to learn is multitasking, i.e. ways to mimic the processor is doing multiple things at once. There are several approaches to this: using polling and state machines in superloop, using interrupts (DMA is roughly the same cathegory), using RTOS, maybe there are others or various subgroups and mixes.

Polling is simple, but you must not be stuck in one loop, and you have to remember the state of given process explicitly. Here, you would go like:

  • have a transmit buffer, index and length for Tx as global variables - you want index to be zeroed in initialization, implicitly or explicitly. For experiment, you can fill data to be transmitted and length in main(); however, in real programs, this usually happens upon some other process, eg. upon pressing a pushbutton (this can be your test program #2)
  • have a receive buffer and index for Rx as global variable (usually, you don't know the length of data to be received beforehand, and you figure it out as you receive, e.g. from some header in data, or from some ending sequence such as the NULL character at the end of an ASCIIZ string)
  • in loop (the familiar while(1) as the last thing in main()), call Receive() and Transmit() (and do other things, e.g. CheckButtons())
  • in Transmit(), check, if transmitter is empty; if not, return. Then check, if Tx index is below Tx length, if not, return. Then pick the next datum according to index, store it to transmit register, increment index and return.
  • in Receive(), check, if receiver is empty; if yes, return. Read out datum. Check receive index against allocated buffer length, if buffer is full, if yes, do some error recovery (this may be tricky and depends on the particular application - at least zero the receive index) and return. Store datum to buffer and increment index. Check if complete message was received (e.g. checking NULL character, checking index against previously received length, again this depends on application); if not return. Process message and reset receive index. (Later, for real world application, you might want to check also the overrun flag, and perhaps some other error flags from UART as well).

JW