cancel
Showing results for 
Search instead for 
Did you mean: 

How do I receive a command through UART in polling mode?

mighty aldenham
Associate

I'm new to STM32 processors. I'm learning on a Nucleo F103rb board. I was able to receive a single character through UART in polling mode, but unfortunately I have difficulties in receiving more than 1 character. It would be used for the device to wait for a user command and then execute it.

I'm using the HAL_UART_Receive function. This code allows me to receive a singe character and then use it e.g. in a switch/case instruction

	while(1)
	{
		if (__HAL_UART_GET_FLAG(&uart, UART_FLAG_RXNE) == SET)
		{
			uint8_t value;
			HAL_UART_Receive(&uart, &value, 1, 100);
 
			switch (value)

The value variable needs to be a uint8_t type. However now I need to receive a table of chars. How do I do that? If I need a 3-character command, shall I change 1 to 3 (or 4, because there is a \0 character on the end of each string)?

I would then use the string with an if and a strcmp() method, but I do need to know how to receive and store multiple characters with the terminal waiting for the full input.

This is probably a basic c programming matter and surely easy peasy for many experienced programmers. But I need to learn this somehow. I will be thankful for any help.

4 REPLIES 4
Bob S
Principal

HAL UART polled RX is only useful if you are receiving fixed-length data, and even then it can cause trouble. However...

Are all of your commands 3 characters? Or 4 characters if the other device sends a NULL (or some other terminator character)? And does the other device then wait for your response before sending more data? If so, then you can probably use HAL_UART_Receive() with the length value equal to your command length.

But if the other device can send more data before you respond (or if it never expects a response from you), polled RX using HAL_UART_Receive() will never work reliably. It all depends on whether your code can get back to the next HAL_UART_Receive() call before the other device has sent 2 characters (i.e. UART overrun error).

The usual solution to this is to use HAL_UART_Receive_DMA() with the DMA configured for "circular" mode so it just keeps receiving data. To check if there is any data for you to process, you need to keep your own pointer into the DMA RAM buffer (the "extract data from here" pointer) and compare that to where the DMA will write the next byte. I think someone posted some code to do this somewhere on this forum. You might try searching for "UART DMA Receive" (though in my experience this forum's search function doesn't work very well).

S.Ma
Principal

Time to discovery interrupt for processing incoming while doing something else (and useful) in the main loop. Byte by byte interrupt (or callback)

Otherwise, use DMA to roll over a big buffer and check in from time to time if a full meaningful packet was received... (which might be advanced)

Using HAL functions, byte-by-byte interrupt receive processing is not possible, without modifying the non-user sections of the HAL code (which is OK as long as you never use CubeMX to regenerate your code and never update HAL library versions). It is certainly possible to write your own UART code to do interrupt driven receive where you can check each byte as it comes in. But the DMA solution is already mostly there in the HAL code and requires less (i.e. no) interrupt overhead. All you need is your own function to check for unprocessed bytes in the DMA buffer and to extract bytes from the DMA buffer. Just be ware that the HAL code may disable DMA receive on any UART error (framing, noise, overrun, etc.).

mighty aldenham
Associate

Thank you very much guys, especially Bob S. I've moved forward with my learning course and I won't waste time for code and features, which I'll never use. DMA indeed seems to be a more pragmatic approach here and I will study this one.