Electronic – Does Interrupting a Microcontroller Data Receive with a Higher Priority Interrupt Cause Data Loss

interruptsmicrocontrollerserialuart

I would like to know what would happen if a Serial Terminal were to send a large amount of data to a PIC/AVR, for example over USART interrupt, which was then interrupted by a higher priority interrupt like a timer, which would postpone the data transfer. Would the data be lost? Or does the Serial Terminal have a buffer before sending, and hold on to the data until we go back to the receive interrupt?

For exmaple I am using an atxmega128a1, and am using this interrupt to receive bytes:

//interrupt to receive a byte 
ISR(USARTC0_RXC_vect){                      //ISR for when receive flag is set
if(FIFO_Put(&RxFIFO, USARTC0_DATA)){        //put data into receive FIFO
    USARTC0_STATUS |= USART_RXCIF_bm;       //write 1 to clear bit
}
}

If I send a large amount of bytes over a serial terminal at one time, this interrupt will trigger many times to receive every byte.

I also have a timer interrupt of a higher priority which may take a long time to complete:

ISR(TCC0_OVF_vect){
    AXISid n = X;
    static BOOL cycle;
    TimerAxisInterrupt(n, &cycle);
} 

To re-iterate, my question is, if the higher priority interrupt occurs during a large data receive transfer, will any data be lost?

If relevant: I am sending the USART data over rs232 using a max3232 logic converter. I have the handshaking lines and RTS CTS lines looped such that i am only using the Rx and Tx lines.

Best Answer

Assuming no handshaking, you will not lose any data if the UART interrupt is serviced often enough to keep whatever hardware buffer it has from overflowing. Typically that's at least one character, but it may be many characters depending on the chip (more powerful chips tend to have more bytes of buffer).

In my experience you cannot depend on XON/XOFF handshaking when the buffer size is small and the sender is a PC- it may send quite a few characters before it gets around to choking off the flow.

So if the buffer depth is one character, and the baud rate is such that one character takes 1msec then you must not take away more than 1msec in your higher priority interrupt or you could lose data (a bit less because you have to account for the time in the UART ISR to respond and pluck the incoming character from the buffer, and you also should account for the situation where the UART interrupt is in progress when interrupted (look at it occurring just before and just after the incoming character was read)

There are various ways of dealing with the situation where you have to have two interrupts with fast response. One way (usually the best way) would be to not do so much in your timer interrupt- interrupt service routines are best used for getting into and out of briskly). Another would be to implement a buffer in memory and set your UART interrupt to the highest priority (just stuff the received character into a circular queue, increment the write pointer modulo buffer size and return- you can check the equality if read and write pointers to see if the queue is empty). There are still other approaches depending on the requirements and the processor- maybe you don't need to have the timer routine with such high priority, or maybe you dynamically change the priority once it has finished the critical stuff then change it back to high priority, allowing it to be interrupted by the UART ISR.

More powerful processors will have larger buffers or DMA that will allow the processor to go walkabout for a great many characters before data loss occurs.

TL;DR You can predict this by profiling your timer interrupt and ISR interrupt code to find the maximum execution time and comparing with the minimum time to fill the buffer (at the maximum baud rate).