Skip to main content
rwils.1
Associate III
July 24, 2022
Question

Using HAL UART, I can't receive a ~20 byte string at 115k, the string is variable length so I have to read character by character but the routine misses characters. Am I correct to think that the HAL routine is too slow to handle this?

  • July 24, 2022
  • 10 replies
  • 2746 views

..

This topic has been closed for replies.

10 replies

waclawek.jan
Super User
July 24, 2022

How would we know? You've given us no relevant information - not even what chip are you using.

UART overrun is an error indicated in UART status register, see RM, but that may be handled by Cube/HAL itself.

At the end of the day, it may be also your program which drops the characters.

Try increasing compiler optimization level.

JW

rwils.1
rwils.1Author
Associate III
July 24, 2022

Thanks for replying BTW

rwils.1
rwils.1Author
Associate III
July 24, 2022

Fair point Jan, I'm using the STM32L471RGT6 at 80MHz. The code is a simple IT based jump to the HAL routine to receive a character, increment a ring buffer, wait for 10 characters in the buffer ( at present) and then transmit the characters out of the serial line using HAL_UART_TX. The messages are incomlete with missing characters. As the code is not complex, and other people have claimed the HAL routines are bloated , I wondered if fundamentally, the HAL routines are just not capable of operating at this speed?

I'll try increasing the optimization level.

Javier1
Principal
July 28, 2022

STM32L471RGT6 at 80MHz should be more than capable of transmitting 20 byte at 115k speed

>>"wait for 10 characters"

that sounds like an ugly active wait loop...... manage your reception buffer outside the interruption or use DMA (<- DMA is nice and fast)

hit me up in https://www.linkedin.com/in/javiermuñoz/
gregstm
Senior II
July 24, 2022

A simple/efficient write to the GPIO BSRR register can set/reset an IO pin. That way you can do your own timing with an oscilloscope (I'm assuming your micro has that register, and also that you have access to an oscilloscope).

Also, I would just use UART status/data register reads in a hard loop (placing data into a simple buffer) to see if you receive the data ok, just to make sure that it is not a hardware issue causing the missing data. (Note: I've never used HAL, I just write to registers)

rwils.1
rwils.1Author
Associate III
July 24, 2022

Thank you Greg, I have tried using register reads/writes but for some other reason, I can't get data from the RDR register, I must have the syntax of the following wrong -> Temp = READ_REG(UART4->RDR);

Tesla DeLorean
Guru
July 24, 2022

temp = UART4->TDR;

It's a structure in memory, the MCU can read it directly.

Keep the acquisition of the data separate from the processing. The interrupt should focus on collecting the data, if you stay in the interrupt/callback the MCU can't re-enter.

An 80 MHz MCU should be able to sink 115,200 baud data without loss.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
MM..1
Chief III
July 24, 2022

Good time waste solver is place here some code

your code relevant lines ...

receive character by character is classic mistake = is imposible with bad implement not relevant to HAL or registers control.

rwils.1
rwils.1Author
Associate III
July 24, 2022
Function in main 
 
while(1) {
		if(character_available==1) 		//Character_available set to 1 by interrupt routine
		{
			character_available=0;
			UART4->TDR = Temp; 		// Load the Data and transmit 
			while (!(UART4->ISR & (1<<6))); //Wait for transmission to end 
		}
 
Interrupt function
 while (!(UART4->ISR & (1<<5))); //Ensure that there is a character to be read
	Temp=UART4->RDR;				//Read the character and store in temp
	character_available=1;			//Informs main loop that a character is available

Thanks for the suggestion MM, here is the relevant code, as you can see , it's pretty straightforward, simply receive a character in the interrupt routine and transmit the character in the main routine. The problem with the code is that Temp never receives data from RDR.

If add Temp='A' then an A is transmitted when a character is received so I have reason to believe that the problem lies with line 13.

MM..1
Chief III
July 24, 2022

Your low level coding is under my low level knowl. You dont show where and how declare Temp.

Too isnt good practice place while in irq.

waclawek.jan
Super User
July 24, 2022

Cube/HAL may be bloated, but I somehow refuse to believe that it can't cope with 115200 in an 80MHz mcu. IMO that might've been some improper usage.

> Too isnt good practice place while in irq.

+1, while has nothing to do in ISR, so

> while (!(UART4->ISR & (1<<5))); //Ensure that there is a character to be read

No. You want only

if (UART4->ISR & USART_ISR_RXNE) { 
 Temp = UART4->RDR;
 character_available = 1;
}

Check also the overrun flag and clear it.

JW

S.Ma
Principal
July 27, 2022

Monitor the overflow flag and make a nop to breakpoint as it happen in debug mode.

Interrupt should never wait, the duration of the interrupt should be as fixed as possible. Check on WCET. Are there any other interrupt disabled long code strip in the sw? Are you managing tx within rx interrupt? Does the used uart have hw fifos?

rwils.1
rwils.1Author
Associate III
July 27, 2022

My own code now works. I wrote a tight circular buffer in the interrupt and used the code that I previously posted. I can read and write at 115k without losing bytes. what was not clear to me was that in Cube MX I foolishly enabled Jtag TMS as an i/o pin ( wrong bank) and so what was happening was that following programming, the program disabled the JTAG and so the breakpoints and the values in the registers were messed up 9 ways since Sunday. After correcting this I can now see that the code works as it should. Thank you all for your advice. now on to FATFS - which really doesn't work!

Piranha
Principal III
July 27, 2022

By the way, for the absolute best and simplest circular buffer implementations, read these:

https://ferrous-systems.com/blog/lock-free-ring-buffer/

https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/

rwils.1
rwils.1Author
Associate III
July 28, 2022

Thank you Piranha , I'll take a look

vd_it
Associate II
July 27, 2022

Or you could use this ring buffer, super easy to use and does the job!

https://github.com/AndersKaloer/Ring-Buffer