cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 UART Rx Interrupt Overflow Error

jhcovington
Associate II
Posted on November 09, 2015 at 19:23

Hello,

I am currently attempting to get the HAL UART functions to read the incoming serial data from a GPS module. From a high level POV, I have the UART rx callback function set to parse the byte that was read in (simply add to a global buffer if the byte is valid GPS data) and then start a new HAL UART IT receive transaction. The issue occurs inside the parsing function when the full GPS message has been received as I write this out to a separate UART for debugging (connected to my computers COM port). It seems that the overflow error is occurring (maybe due to the time it takes to write this out) and thereafter it causes the Error callback routine to be serviced.

I can alleviate this by using ''__HAL_UART_CLEAR_OREFLAG(&huart5);'' but I don't see why I need this as an overflow should not be occurring (I am reading in a single byte every time the tx interrupt occurs). From my understanding, the UART should be ignoring data that is coming in while inside the interrupt routine.

Am I missing something fundamental here or is there simply a better way to do this?

Initialization routine for UART5:

void MX_UART5_Init(void)
{
huart5.Instance = UART5;
huart5.Init.BaudRate = 38400;
huart5.Init.WordLength = UART_WORDLENGTH_8B;
huart5.Init.StopBits = UART_STOPBITS_1;
huart5.Init.Parity = UART_PARITY_NONE;
huart5.Init.Mode = UART_MODE_TX_RX;
huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart5.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart5);
}

MSP Init function that gets called inside HAL_UART_Init():

void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
if(huart->Instance==UART5)
{
/* USER CODE BEGIN UART5_MspInit 0 */
/* USER CODE END UART5_MspInit 0 */
/* Peripheral clock enable */
__UART5_CLK_ENABLE();
/**UART5 GPIO Configuration
PC12 ------> UART5_TX
PD2 ------> UART5_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_UART5;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_UART5;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* Peripheral interrupt init*/
HAL_NVIC_SetPriority(UART5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(UART5_IRQn);
/* USER CODE BEGIN UART5_MspInit 1 */
/* USER CODE END UART5_MspInit 1 */
}
}

UART5 IRQ Handler Function:

/**
* @brief This function handles UART5 global interrupt.
*/
void UART5_IRQHandler(void)
{
/* USER CODE BEGIN UART5_IRQn 0 */
/* USER CODE END UART5_IRQn 0 */

HAL_UART_IRQHandler(&huart5);

/* USER CODE BEGIN UART5_IRQn 1 */

HAL_NVIC_ClearPendingIRQ(UART5_IRQn);

/* USER CODE END UART5_IRQn 1 */
}

*** The receive function is called for the first time in main.c to start it off ***

HAL UART Receive callback function:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart5)
{
//__HAL_UART_FLUSH_DRREGISTER(&huart5);
//__HAL_UART_CLEAR_OREFLAG(&huart5);
parse_gps_data(gps_byte);
HAL_UART_Receive_IT(&huart5,gps_byte,1);
}
}

Snippet from parse GPS data routine once full message has been received:

uint8_t gps_byte[2];
char gps_buf[100]; // Increasing size of this does not fix the overflow issue
char gps_msg[100]; // Increasing size of this does not fix the overflow issue
void parse_gps_data(uint8_t* data_array)
{ // Called by UART5 interrupt routine
char data = data_array[0]; //Get single received byte
switch(data)
{
......
......
......
case '\n': //End of GPS message
if(gps_buf[0] == '$')
{
if( local_checksum == 16*hex_to_int(gps_buf[gps_buf_count-3]) + hex_to_int(gps_buf[gps_buf_count-2]) )
{ // Check received checksum and proceed if no errors
memcpy(gps_msg,gps_buf,gps_buf_count-1);
gps_msg[gps_buf_count-1] = 0;
STM_UART_TX(gps_msg); //ERROR IS OCCURRING DUE TO THIS!
STM_UART_TX(''\r\n'');
//__HAL_UART_CLEAR_OREFLAG(&huart5); //ERROR IS FIXED IF I USE THIS BUT AN OVERFLOW STILL OCCURS AND IS CAUSING ISSUES WITH MY CODE IN OTHER AREAS
gps_msg_ready = 1;
}
}
break;
......
......
......
}
gps_buf_count = gps_buf_count > 99 ? 0 : gps_buf_count;
}

4 REPLIES 4
Posted on November 09, 2015 at 20:23

You really need to process the received byte and leave expeditiously. You can't be printing dozens of characters to some other serial output, as this will take multiple byte times.

You should accumulate the line of data, and dispatch it to some other task for processing. This could be a foreground while loop if you are not multi-tasking.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
jhcovington
Associate II
Posted on November 09, 2015 at 21:53

Ok that makes sense. Related to that suggestion, does a serial output of that size really take up enough CPU cycles (@ 168MHz) to cause the data coming in at a slower rate (Baud = 38,400) to fire the interrupt (i.e. Time it takes to send gps_msg > time between each received GPS byte ?). 

In the mean time, I'll reorganize the processing structure and let you know how things change. Thank you.

Posted on November 09, 2015 at 22:14

I'm not using the HAL, so don't know exactly where it's stuffing the data, or how it buffers it, but you're getting overflow errors because the stream of data keeps coming from the GPS/NMEA device and you're not handling it, and stalling in the interrupt routine doesn't stop it.

I've got a number of applications handling GPS data, the only thing the interrupt routine does is buffer the data. The STM32 USART has no FIFOing or buffer depth to accommodate long latency in your processing routines, where ever that is coming from. When going between multiple USARTs I'd always want some reasonably deep FIFO to give a degree of elasticity in the processing between them.

Processing strings, and dealing with floating point sscanf(), is going to burn a significant number of cycles.

[DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Issue%20with%20USART%20RX%20buffer%20and%20char%20filter&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=217]https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex_mx_stm32%2FIssue%20with%20USART%20RX%20buffer%20and%20char%20filter&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=217

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
jhcovington
Associate II
Posted on November 12, 2015 at 22:57

I ended up going with the two message approach, alternating between which message was written to from the GPS buffer. It seems to be working great! Thanks again.