Notice that the receive and transmit code both contain the essential elements of the polling implementations of putchar and getchar, they handle corner cases differently. If there is no room in the RX queue, the interrupt handler receives, but discards any data in the receive register. Whenever the interrupt handler discards data, it sets a global variable, RxOverflow to 1; it is up to the application code to monitor this variable and decide how to handle lost data. If the TX queue is empty, the interrupt handler cannot resolve the interrupt condition (since it has nothing to write to the transmit data register), so it disables the USART_IT_TXE condition. The variable TxPrimed is used to communicate to the application (specifically putchar) that the interrupt needs to be re-enabled when data is added to the TX queue