cancel
Showing results for 
Search instead for 
Did you mean: 

UART3 overrun interrupt

GTanova
Associate III

Hello,

It is the first time I am using STM32 and migrating my code from texas instruments controller using USART3. I want to receive data and then transmit data of different sizes. I get a problem that I see appears often but in my case I cannot see why it appears. I want to use USART on port C, PC4 = Tx and PC5 = Rx. I have a partner sending data via uart and I can see the data is on the Rx line but somehow it does not come to the buffer. I get to the interrupt handler and then Error callback. I am using the receive to Idle with interrupts when data is received. The first expected data is 10 bytes, my rx buffer is 1024 big and my rx buffer is defined , not NULL. I call the function for receive directly after my partner device is on and I have got the reply this device is on. The partner device is making 10 attempts to send the same data and without answer is shutting down. It starts sending shortly after it is on. 
My uart onfiguration is as follows:

 
 
handleUart3.Instance = USART3;
handleUart3.Init.BaudRate = 115200;
handleUart3.Init.WordLength = UART_WORDLENGTH_8B;
handleUart3.Init.StopBits = UART_STOPBITS_1;
handleUart3.Init.Parity = UART_PARITY_NONE;
handleUart3.Init.Mode = UART_MODE_TX_RX;
handleUart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
handleUart3.Init.OverSampling = UART_OVERSAMPLING_16;
handleUart3.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
handleUart3.Init.ClockPrescaler = UART_PRESCALER_DIV1;
handleUart3.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&handleUart3) != HAL_OK)
{
  Error_Handler();
}

if (HAL_UARTEx_SetTxFifoThreshold(&handleUart3, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
  Error_Handler();
}

if (HAL_UARTEx_SetRxFifoThreshold(&handleUart3, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
  Error_Handler();
}

if (HAL_UARTEx_DisableFifoMode(&handleUart3) != HAL_OK)
{
  Error_Handler();
}

HAL_NVIC_SetPriority(USART3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
__HAL_UART_CLEAR_FEFLAG(&handleUart3);
__HAL_UART_CLEAR_NEFLAG(&handleUart3);
__HAL_UART_CLEAR_OREFLAG(&handleUart3);

 


Then all I do is call the receive function and wait for interrupts

uint8 *uartRxBuf; // pointing to a buffer that is created for this communication handler, uint8 * const buffPtr
HAL_UARTEx_ReceiveToIdle_IT(handleUart3, uartRxBuf, 1024);

Then the code somes here 

void USART3_IRQHandler(void)
{
  HAL_UART_IRQHandler(&handleUart3);
}


and eventually HAL_UART_ErrorCallback()

Do you have any tips how to debug more and what can go wrong?


Edited to apply source code formatting - please see How to insert source code for future reference.

15 REPLIES 15
Ozone
Principal II

> The only thing really needed for data reception is "byte received" callback with no need/requirement of enabling reception in it or anywhere else.

And I would add, unless one uses a proper RTOS that needs to shield interrupts from user code / tasks, there is no reason for callbacks in the first place.
My code, which is mostly bare-metal, implements all this events directly in the interrupt handler.

How do you "enable" UART so that the code goes to interrupt handler when data is received? 

I would recommend to several related sections of the reference manual for your MCU, especially the UART/USART one. If you serious you will need to do this sooner or later.

First, select the events you need to deal with, like TxE, RxNE, or errors. They are reflected by bits in the interrupt config register of the UART peripheral. Set these bits using your favorite method (Cube code or direct register access).
Second, in the associated interrupt handler, check for each flag individually. This is done by checking the respective flags in the interrupt status register of the peripheral. Handle it according to your application requirements, taking care the flag is reset during the process, or it will reenter immediately.

Cube comes with with "template" interrupt handlers that often consist mostly of branching into callbacks.
I see no point in introducing another level of indirection, without any need. Especially for bare-metal applications (without RTOS).
You can change / edit this interrupt handler as you feel free, but again, I would recommend to read a few RM sections on interrupt handling before.

 

Hello @GTanova 
The HAL2 version provided in the above link is currently a preview at the alpha stage, with testing and validation still ongoing. The official HAL2 release is expected in the first quarter of 2026.

Guenael Cadier
ST Employee

hi @GTanova 

HAL_UARTEx_ReceiveToIdle_IT(handleUart3, uartRxBuf, 1024);

should behave as follows :
- if 10 bytes are received, and a "pause" (i.e. Idle event) occurs on the rx line, then reception stops and HAL_UARTEx_RxEventCallback callback is called with nb of received data in parameter.

- if the transmitter starts again sending data to your device, and your want to receive those data, you need to restart a new reception process by calling again HAL_UARTEx_ReceiveToIdle_IT();

In order to get rid of sync issues between transmitter and receiver, you could clear error flags, just before calling ReceptionToIdle API. Please also make sure that time needed for execution of HAL_UARTEx_RxEventCallback callback is not too long, as it could lead to overrun error in an it based process.
You could also have a look to HAL_UARTEx_ReceiveToIdle_DMA() API, with a circular buffer that could be interesting for endless reception loop.
An example is available in U5 FW package here.
Regards

 

 

Pavel A.
Super User

@Guenael Cadier IMHO in HAL2 ST could add a new function similar to "continuous receiver" in the Microsoft's WDF.

This functionality already exists in HAL_UART_Receive_DMA() with circular buffer mode, but is badly lacking in simple interrupt mode. As noted by @Bermingham  it can yield data byte-by byte, or (with FIFO) by small bursts. It should use RTO instead of "idle" event whenever possible.  It should run continuously, without disabling U(S)ART interrupts, until stopped by user. If overrun occurs, call the error handler, clear and continue.