A universal asynchronous receiver-transmitter (UART) is a hardware device for asynchronous serial communication commonly found in personal computers and embedded devices. The term UART refers specifically to the hardware responsible for the transmission and receiving of data over a serial port interface, the most well-known implementation of which is the serial port common to x86 computers. This hardware is usually found in the form of an IC integrated onto a motherboard or system-on-chip.
This article provides a theoretical introduction to the topic of UARTs and their relevance to operating system development. It does not intend to provide a comprehensive guide to programming any specific implementation, rather to introduce the reader to a high-level understanding of the topic of UART hardware and their use in serial communication.
The most common implementation of a UART is the 16650 UART, developed in 1987 by National Semiconductor. It is frequently used to implement the serial port interface for IBM PC compatible personal computers, where it is commonly connected to an RS-232 port. The implementation in x86/64 is known as the COM interface, which is accessible via standard IO Ports mapped to addresses from 0x3F8 through 0x3FF.
Hardware serial interfaces can be found on nearly every personal computer manufactured prior to 2005. Even systems without physical serial ports will typically include drivers for interfacing with compatible hardware. For the purposes of operating system development on x86 computers, the 16550 UART is of particular relevance. Its support is nearly guaranteed in PC emulators, as well as being particularly well documented and easy to develop drivers for. Most consumer embedded systems feature an integral UART or USART implementation, often accessible via a GPIO interface. UART implementations in embedded systems vary somewhat between vendors, however implementations tend to be reasonably mutually intelligible.
UART hardware typically includes a clock generator responsible for regulating the baud rate of communications. As well as multiple memory-mapped registers, commonly referred to as 'shift registers', responsible for holding data to be transmitted or received. For a more detailed description of an individual hardware implementation, refer to its datasheet. A datasheet explaining the individual hardware components of the 16550D UART manufactured by Texas Instruments can be obtained here.
Serial communication is facilitated by the UART hardware taking bytes of data and transmitting individual bits in a sequential fashion, hence the use of the term 'serial'. At the destination, the receiving UART reassembles the stream of bits into the complete data payload. This is facilitated by the use of the aforementioned 'shift registers', which will typically interface with the driver via the generation of interrupts.
Note: What follows is a technical explanation of the line protocol used by UART devices to transmit and receive data. In depth knowledge of the electrical characteristics of UART communication is not necessary for the implementation of UART drivers, but is useful background knowledge.
The UART hardware is configured to transmit and receive at a predetermined baud rate. This value corresponds to the number of bits that are transmitted across the line per second. Both the sender and receiver UART will need to use the same UART to ensure that communication is synchronised. Configuration of the baud rate is typically accomplished via populating a 'clock divisor' register to limit the baud rate to a quotient of the device's maximum. For example: if the device has a maximum baud rate of 115200 ( A common default value ), populating the clock divisor register with a divisor of 1 will give 115200 baud, a divisor of 2 will give 57600 baud, 3 will give 38400 baud, etc.
The idle, no data state on a serial line is typically a high-logic state. Transmission of an individual character over a serial line consists of each character being framed with a logic-low start bit, an arbitrary number of data bits, an optional parity bit and one or more stop bits. In most UART implementations the least significant bit is transmitted first.
It is important to note that the bit-width of a character in a particular serial line protocol might not necessarily be 8. In most UART implementations this is a configurable setting, which the end-user may tailor to the individual requirements of the system.
The logic-low start bit signals to the receiver that a new character is pending. The next bits, which will vary in length depending on the configuration, represent the character payload. If a parity bit is used, it will be placed after all of the data bits. The next one or two bits, called the stop bits, are always in the high-logic state. They signal to the receiver that character transmission is complete. These predictable bits can be used by the hardware to test whether the transmitter and receiver are in phase.
If the line is held in the logic low condition for longer than the period necessary to transmit a character, this is a 'break condition' that can be detected by the UART, typically via the generation of an interrupt.
The use of a parity bit in UART communication is a method of detecting errors in transmission. When a parity bit is used with a serial port, an extra data bit is sent along with each transmitted character. The parity bit has a logical value corresponding to whether the number of 1's in the binary character being transmitted is even or odd. There are two variants of parity bits: even and odd parity bits. In the case of an even parity bit, for a given set of bits, the occurrences of bits whose value is 1 is counted. If that count is odd, the parity bit value is set to 1, making the total count of occurrences of 1's in the whole set (including the parity bit) an even number. If the count of 1's in a given set of bits is already even, the parity bit's value is 0. In the case of an odd parity bit, the value is reversed, so that the value of the parity bit will ensure that the total number of 1's in the transmission is an odd number. The transmitting and receiving UART hardware must have a matching parity bit configuration or their signals will be mutually unintelligible.
The commonly used standard for serial configuration is known as 8N1: eight (8) data bits, no (N) parity bit, and one (1) stop bit.
Prior to the 2000s, serial ports were a common way for personal computers to interface with external consumer peripherals. Despite being more-or-less entirely superseded by USB for communicating with peripherals in personal computers, UART remains in more common use in embedded systems for communicating with hardware peripherals.
Serial programming is of special relevance to operating system development, as it provides an easy to implement and robust interface between an operating system and external logging mechanisms. In systems where video hardware may not be present, or may not be suitable for the printing of debugging information, a serial driver can easily be implemented to fulfill this need. Serial port interfaces to the host operating system are widely available in common PC emulators such as QEMU and bochs.