В не совсем явной форме это уже прозвучало, но хочу подчеркнуть - прерывание TXC действительно возникнет только при отправке последнего байта.
Флага прерывания TXC имеет шанс взвестить - на высокой скорости, при нагруженном другими, более приоритетными прерываниями процессоре - UDRE может "опоздать" и взведётся ещё и TXC. Но у UDRE выше приоритет и поэтому сначала вызовется его обработчик.
И вот в нём можно проверить - есть ли ещё байты для передачи и если есть - то сбросить флаг TXC, а если нет - самозапретиться и не трогать флаг TXC, пусть вызовется его обработчик.
Смысл такого действа - под операционной системой сделать (более частое) прерывание UDRE более "лёгким", не обращащимся к сервисам ОС (и, как следствие, имеющим шансы не вызывать не-inline функции и сохранять/восстанавливать только реально необходимые для работы регистры), а обращение к ОС поместить в прерывание TXC.
Приблизительно так:
Код
template<uart_channel_t channel> void
uart_t<channel>::tx_isr()
{
OS::TISRW isrw;
tx_event.SignalISR();
}
template<uart_channel_t channel> void
uart_t<channel>::udre_isr()
{
if( tx_available() ) {
uint8_t temp = tx_get_byte();
if( channel == uart_ch0) {
UDR0 = temp;
UCSR0A |= (1 << TXC);
} else {
UDR1 = temp;
UCSR1A |= (1 << TXC);
}
} else {
if( channel == uart_ch0)
UCSR0B &= ~(1 << UDRIE);
else
UCSR1B &= ~(1 << UDRIE);
}
}