I know that the RX interrupt is obviously used to save polling, but why the TX one too?
The main goal of the TX interrupt (really an END OF TX) is to send the content of a buffer (multiple bytes) automatically. When implemented in a proper way:
- Enable the TX interrupt.
- The user code starts transmission by sending only the first byte in the buffer.
- At the end of TX (of the first byte), an interrupt will be generated.
- In the TX ISR (Interrupt Service Routine), the code must send the next byte in the buffer and update the buffer index.
- At the end of this transmission, a new interrupt occurs, and so on, until the entire content of buffer is sent "automatically".
- Disable the TX interrupt.
The exact behavior depends on the microcontroller. That is a general description.
The TX interrupt is mainly for longer datagrams. You can initiate the transfer for a buffer of known length (bytecount). Now you can push your buffer pointer as often as there are bytes to send, when the TX interrupt occurs. This ensures the "as quick as possible" transfer of your buffer, without the need to poll any "TransferComplete"-Flag/Statusbit.
Some UARTS have an internal buffer that is larger than one, the 16xxx series for one.
The procedure here was
- Set a transmit window mask, for example to 4 remaining.
- fill buffer positions until the UART said full or no more data need to be send
- do other stuff
- when only 4 buffer positions are left unsend, set TX interrupt
- wait for the interrupt to be serviced
- if more data needs to be send go to 2.
This decreases the CPU load by offloading some processing to the UART thus enabling slower CPU's to keep up and service other task instead of getting interrupted all the time.
The TX interrupt fires when there is space in the transmit buffer.
For devices that don't have a transmit buffer (i.e. where you write one byte, which is transferred immediately), the interrupt is asserted when the transmit register can be written with the next byte.
For devices with a buffer, the interrupt is asserted at an implementation-defined time. For some, it is when the buffer is half empty, for some it is when transmission of the last byte has started and the buffer is completely empty.
Another use case is when you connect the UART to another communication interface like RS485. The controller has to release the bus driver as soon as the last bit has been shifted out of the TX buffer. This is easy to handle in the TX interrupt, but would be cumbersome to implement without, since you would have to wait an exact time after writing the last byte to the output buffer which would also vary with baud rate.