cancel
Showing results for 
Search instead for 
Did you mean: 

UART Interrupt not triggering when receiving board is powered on before master board starts transmitting

BMart.5
Associate

Hello,

I have 2 boards connected via UART (baud rate of 115200). The first board is a custom board with an STM32F479 chip using the Standard Peripheral Drivers and mostly custom firmware(for sake of coherence I'm going to call this the master board). This board packages and sends data over UART to my second board. Shown below is how I package and send data from this board:

void dummy_tlm()
{
    srand(300);
    uint8_t data[480];
    uint8_t data_with_opcode[483] = {1,2,3};
    while(1)
    {
        // Generate dummy telemetry
        for(int i = 0; i < 5; i++)
        { // These are just arrays of doubles and ints defined elsewhere, filling with random data
            position[i] = (double)rand()/(double)(RAND_MAX/360);
            velocity[i] = (double)rand()/(double)(RAND_MAX/80);
            current[i] = (double)rand()/(double)(RAND_MAX/10);
            temp_a[i] = (double)rand()/(double)(RAND_MAX/100);
            temp_b[i] = (double)rand()/(double)(RAND_MAX/100);
            status[i] = (int8_t)(rand() % 2);
            limits[i] = (int8_t)(rand() % 2);
        }
        package_tlm(&data); // This function packages all telemetry into a data buffer of size 480
        memcpy(data_with_opcode + 3, data, 480); // appends data to the end of buffer starting with {1,2,3}
 
        for(int i = 0; i < 483; i++)
        {
            USART_SendData(LCD_UART, data_with_opcode[i]);
            while(!USART_GetFlagStatus(LCD_UART, USART_FLAG_TC));
        }     
 
        vTaskDelay(1000);
    }
}

This code does basically what I want, sending out my data buffer of size 483 over uart every second or so.

The second board is an STM32F746-Discovery board, running a TouchGFX application and mostly autogenerated HAL driver functions (calling this one the slave board). This board's job is to receive data over UART and display it on the screen, which it does just fine when it receives data properly. Here is the code I use to receive the UART transmission, largely based on the approach in this video ( https://www.youtube.com/watch?v=bCppZf8FKYg&t=1408s :(

#include "main.h"
#include "UartPollingRoutines.h"
#include "string.h"
#include "cmsis_os.h"
 
extern UART_HandleTypeDef huart6;
extern osSemaphoreId BinarySemUartRxHandle;
 
uint8_t uartMsgBuf[483];
uint8_t msgRdyFlag = 0;
 
void PollingInit()
{
	// enable interrupt
	HAL_UART_Receive_IT(&huart6, uartMsgBuf, 483);
}
 
void PollingRoutine()
{
	if(__HAL_UART_GET_FLAG(&huart6, UART_FLAG_ORE))
		__HAL_UART_CLEAR_OREFLAG(&huart6);
	if(msgRdyFlag)
	{
		xSemaphoreGive(BinarySemUartRxHandle);
		msgRdyFlag = 0;
	}
}
 
// IRQ for HAL_UART_Receive_IT
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        // Check for the 1,2,3 at the start of the data buffer, make sure we're not catching it mid-stream
	if(uartMsgBuf[0] == 1 && uartMsgBuf[1] == 2 && uartMsgBuf[2] == 3)
		msgRdyFlag = 1;
        // Re-enable the interrupt
	HAL_UART_Receive_IT(&huart6, uartMsgBuf, 483);
}

PollingInit() is called once from main, and PollingRoutine() is called continuously from a task in main. The semaphore releases to trigger a series of events in Model::tick on the TouchGFX side of things.

When the master board is running and transmitting over UART prior to the slave board being powered on, the slave board gets the interrupt just fine. However, if the slave board is already on before the master board is powered and starts transmitting, we never enter HAL_UART_RxCpltCallback and the information is not received. I discovered from debugging the slave board that the UART handle has an error code of 8, which indicates that UART_FLAG_ORE (overrun error) is set, but checking and clearing it in the PollingRoutine() has not fixed the problem.

Is there some other specific flag I need to check/set/reset? Still somewhat new to using UART communication, so any and all feedback is appreciated!

2 REPLIES 2
Pavel A.
Evangelist III

>  I discovered from debugging the slave board that the UART handle has an error code of 8, which indicates that UART_FLAG_ORE (overrun error) is set, but checking and clearing it in the PollingRoutine() has not fixed the problem.

Overrun is a very notorious condition that is not handled correctly in old versions of ST libraries. If you see it stuck and not going away this may be the culprit.

This is fixed in latest HAL library.

--pa

Guenael Cadier
ST Employee

Dear @BMart.5​ 

My understanding is that in your error case, when master board is started, reception for a 483 bytes long sequence is already started on slave side.

Then, for reaching an Overrun error, this would mean than more then 483 bytes are received (or that interrupts could not be processed fast enough to empty the RDR register, but as it is working well in normal case, i guess it should not be the case).

Just an hypothesis : when master side is started after slave side, could this generate some falling edge of the line ?

If so, this could be interpreted as start bits from slave side, which will start reception and storing unexpected characters as first data, then further 483 bytes sent by master board could not all be captured in reception buffer.

I'm not sure it could be an explanation for this faulty case, as even in this case, you should have entered the HAL_UART_RxCpltCallback().

Your check for 1,2,3 might probably fail (so no valid data would be recognized, msgRdyFlag will remain 0) but i would expect the callback to be called ...

Second question : if you set a breakpoint on ORE flag clearing instruction on slave side (line 21), when execution stops on this breakpoint, what is the content of your uartMsgBuf reception buffer, and could you dump values of following fields from your UART Handle structure (RxXferSize, RxXferCount, RxState and ErrorCode) + content of RDR register of UART instance ? Just to try to understand the use case ...