Next Previous Contents

2. How It Works --Overview

2.1 Transmitting

Transmitting is sending bytes out of the serial port away from the computer. What follows is an explanation of how older obsolete serial ports work (with only 1-byte hardware buffers). Once you understand the old ones it will be easy to understand the more modern ones. When the computer wants to send a byte out the serial port the CPU sends the byte on the bus inside the computer to the I/O address of the serial port. The serial port takes the byte, and sends it out one bit at a time (a serial bit-stream) on the transmit pin of the serial connector. For what a bit (and byte) look like electrically see Voltage Waveshapes.

Here's a replay of the above in some more (but not full) detail. Most of the work at the serial port is done by the UART chip (or the like). The device driver program, running on the CPU, sends a byte to the serial's I/O address. This byte goes into a 1-byte transmit buffer in the serial port. When the port is ready to transmit it, it moves this byte to its transmit shift register and sends it out the transmit pin bit-by-bit. Now the transit buffer is empty and another byte may be put in it while the original byte is being transmitted from the transmit shift register. Once a byte is completely transmitted, the port takes another byte out of its transmit buffer and sends that bit-by-bit also. It continues doing this as long as it finds a new byte in the transmit buffer.

But that's not the whole story. In order for there not to be any gaps in transmission, the CPU must keep the 1-byte transmit buffer supplied with bytes. It does this by utilizing interrupts. As soon as a byte has been moved out of the 1-byte transmit buffer (and is about to be transmitted from the transmit shift register), the transmit buffer is empty and needs another byte. The serial port then issues an interrupt to say it is ready for the next byte. The interrupt is actually a voltage put on a dedicated wire used only by that serial port (although in some cases the same wire may be shared by more than one port).

The device driver is notified about the interrupt and checks registers at I/0 addresses to find out what has happened. It finds out that the serial's transmit buffer is empty and waiting for another byte. So if there are more bytes to send, it sends the next byte to the serial's I/0 address. This next byte should arrive when the previous byte is still in the transmit shift register and still being transmitted bit-by-bit. This new byte goes into the transmit buffer but it can't be moved into the transmit shift register until the previous byte there has been completely sent out. When the last bit has been sent out the following 3 things happen almost simultaneously:

  1. Another new byte is moved from the transmit buffer into the transmit shift register
  2. The transmission of this new byte (bit-by-bit) begins
  3. Another interrupt is issued to tell the device driver to send another byte to the transmit buffer.

We thus say the serial port is interrupt driven. Each time the serial port issues an interrupt, the CPU sends it another byte. Once a byte has been sent to the transmit buffer by the CPU, then the CPU is free to pursue some other activity until it gets the next interrupt. The serial port transmits bits at a fixed rate which is selected by the user. It's sometimes called the baud rate. The serial port adds extra bits to each byte so there are often 10 bits sent per byte. At a rate (also called speed) of 19,200 bits per second (bps), there are thus 1,920 bytes/sec (and also 1,920 interrupts/sec).

Doing all this is a lot of work for the CPU. This is true for many reasons. First, just sending one 8-bit byte at a time over a 32-bit data bus (or even 64-bit) is not a very efficient use of bus width. Also, there is a lot of overhead in handing each interrupt. When the interrupt is received, the device driver only knows that something caused an interrupt at the serial port but doesn't know that it's because a character has been sent. The device driver has to make various checks to find out what happened. The same interrupt could mean that a character was received, one of the control lines changed state, etc.

One improvement over the above has been the enlargement of the buffer size of the serial port. Most serial ports today have 16-byte buffers instead of just 1-byte buffers. This means that when the CPU gets an interrupt it gives the serial port up to 16 new bytes to transmit. This is fewer interrupts to service but data must still be transferred one byte at a time over a wide bus.

2.2 Receiving

Receiving bytes by a serial port is similar to sending them only it's in the opposite direction. It's also interrupt driven. For the obsolete type of serial port with 1-byte buffers, when a byte is fully received it goes into the 1-byte receive buffer. Then the port gives the CPU an interrupt to tell it to pick up that byte so that the serial port will have room for storing the byte which is currently being received. For newer serial ports with 16-byte buffers, this interrupt may be sent after 14 bytes are in the receive buffer. The CPU then stops what it was doing, runs the interrupt service routine, and picks up 14 or more bytes from the port. It will be more than 14 if any additional bytes arrive after the interrupt was issued. But if 3 or more new bytes have arrived, then the 16 byte buffer will overrun since it can't store 17 (14 + 3) or more bytes.

2.3 The Large Serial Buffers

We've talked about small (1 or 16 byte) serial port buffers in the hardware but there are also much larger buffers in main memory. When the CPU takes a byte (or say 14 bytes) out of the receive buffer of the hardware, it puts it into a huge (say 8K-byte) receive buffer in main memory. Then a program that is getting bytes from the serial port takes the bytes it's receiving out of that large buffer (using a "read" statement in the program). A similar situation exists for bytes that are to be transmitted. When the CPU needs to fetch some bytes to be transmitted it takes them out of a large (8K-byte) transmit buffer in main memory and puts them into the small transmit buffer (1 or 16 bytes) in the hardware.


Next Previous Contents