cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 HAL Uart receive interrupt stops receiving at random times

DBERG.1
Associate II

I am using an F303RE and UART communications for a project.

I'm using all 5 uarts, all with the HAL-library interrupt based transmit and receive.

The main communication protocol is MAVLINK, with one of the UARTs being SBUS.

My issue:

After a random amount of time, a UART channel stops receiving messages.

It is also not always the same channel to stop, and it might be multiple channels to do so (not at the same time).

Note:

I'm dealing with this issue for 3 weeks now, without any progress.

I know the 'correct' way would be to write a new HAL, but I don't have resources or knowledge to do so at the moment.

I am using HAL_UART_RxCpltCallback, this way:

(There's HAL_UART_Receive_IT at the end of each reading function)

(I know the code isn't pretty, a switch-case would be a better fit for readability)

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	USART_TypeDef *uart = huart->Instance;
	if(uart == USART1)
	{
		readUartOne();
	}
	else if(uart == USART2) // from PC
	{
		// do some stuff (not too much, though)
		HAL_UART_Receive_IT(&huart2, &inBuff2[0], 1);
	}
	else if(uart == USART3) // from SBUS
	{
		readSbusPacket();
	}
	else if(uart == UART4)
	{
		readUartFourPacket();
	}
	else if(uart == UART5)
	{
		readNVPacket();
	}
}

I've tried to catch an interrupt override using some variables - I added an if(uart != huart->Instance) to see if the interrupt is being overridden.

But couldn't find any, so I assume it's not the case.

Please let me know if you have any ideas or tips on how to handle this.

17 REPLIES 17

@S.Ma​ @Pavel A.​ 

Understood. Anyways using HAL_UART_Receive_IT( ... , x > 1) wouldn't work for me since the protocol allows for different packet lengths.

Would you say DMA should be an OK solution, or should I go LL?

Consider that I'm with limited resources as far as development time, and have no experience with LL at the moment.

If you're going to use DMA with variable data length, you can use HAL_UARTEx_ReceiveToIdle_DMA. For the data length juse use a number greater than what you're expecting.

When packets of data stop coming in, it'll interrupt. I've checked on a oscilloscope and after about 4 bits of none activity it'll interrupt. Thats for baud rate of 115200. I haven't checked but it is probably 4 bits for idle for all other baud rates as well.

Then use HAL_UARTEx_RxEventCallback instead of HAL_UART_RxCpltCallback.

I'm starting to move my code over to use HAL_UARTEx_RxEventCallback instead of HAL_UART_Receive_IT because now i don't have to look for a delimiter to know it's the end of a string. And works just as good with binary data packets as well.

Thanks, I'll have a look at the extended library.

You need probably a "continuous reader" that never stops, and yields input data whenever it arrives. The ST UART library operates like this only with DMA in circular mode + UART RX timeout detection. I am not sure if STM32F3 library implements it. If not, it can be done 'manually'.

Any other mode of the ST library has a limited number of bytes to receive, thus it is not a continuous reader.

Alright, maybe DMA will be the way to go.

On another note - once I get an overrun, I can't get the UART to work again.

The CR1 register has the value of 13, meaning PEIE and RXNEIE are both 0, compared to the working UARTS that have them set to 1.

I tried recalling receive functions, but they don't seem to affect these bytes.

Are you using HAL_UARTEx_ReceiveToIdle_DMA?

Hey S.Ma, a year after the creation of this post I found myself in a simular situation and I found your response interesting but since i'm still getting used to the terminology can you maybe explain in more words what you mean with "to use LL low layer for uart communication to reduce WCET" ? Thank you in advance

 

 

https://en.wikipedia.org/wiki/Worst-case_execution_time

With the UART's it's usually better to service very quickly, most STM32 only have a single byte buffer for each direction, and the interrupt isn't going to be re-entrant (won't pre-empt, and all the UART1 interrupts come through a single vector).

Do your work quickly and leave. Buffer data. Process when the execution time is not critical, it's easy to get distracted decoding and processing the stream in the interrupt.

The interrupt / callback are done in interrupt context.

Most STM32 interrupt for every single byte, regardless of what you do with HAL_UART_ReceiveIT()

Observe and clear pending error status (ie Noise, Overrun, Underrun, Parity, Framing, etc) when you dispatch new data to a buffer, and when handling the interrupt(s)

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