From: chbl@sbustd.rz.uni-sb.de (Christian Blum) 
Newsgroups: comp.sys.ibm.pc,comp.sys.ibm.pc.programmer,comp.sys.ibm.pc.hardware 
Subject: FAQ: The serial port (part 1) 
Date: 28 Feb 1993 22:00:51 GMT 
Organization: Studenten-Mail, Rechenzentrum Universitaet des Saarlandes 
NNTP-Posting-Host: sbustd.stud.uni-sb.de 
 
 
Date of release: 25 Feb 1993 
Part one: Hardware & Software 
 
  This is a FAQ answer on serial communications using the TTY protocol. It 
contains information on the TTY protocol and hardware and software implemen- 
tations on IBM PCs which is derived from National Semiconductor data sheets 
and practical experience of the author and his supporters. 
  If you want to contribute to this FAQ in any way, please email me (probably 
by replying to this posting). My email address is: chbl@stud.uni-sb.de 
  See the end for details. 
  It's the third publication of this file. Lots of errors have been removed, 
and lots of information has been added (which has surely brought other errors 
with it, see Murphy's Law). 
  [] brackets indicate comments to copied material. 
 
 
Corrected errors since the last publication 
=========================================== 
 
  Oh yeah, there have been *lots* of errors. 
 
  Nearly all line state information was wrong, and the rest was quite muddled. 
This section has been revised. 
  In the Software section, the two possibilities of 'stick parity' have 
been mixed up. 
  Pin 'RTS' of the 9 pin connector is now correctly numbered '7'. The pins 
RXD & TXD were also misnumbered. 
  The C functions for transmitting data didn't work. I mixed up == and != 
X-(. But that was not the only mistake... 
  The assembler procedure UART_send even hung! I POPped the stack once too 
often. A label was missing, too. 
 
 
Additional information 
====================== 
 
  A C function has been added that allows detection of the interrupt 
level/number of a UART. 
  The BIOS API for serial communication has been added (but better ignore 
that section :-). 
 
 
Acknowledgements 
================ 
 
  The following persons have contributed (directly or indirectly :-) to this 
summary by providing information or making suggestions/reporting errors: 
      Madis Kaal <mast@anubis.kbfi.ee> 
      Steve Poulsen <stevep@ims.com> 
      Scott C. Sadow <NS16550A@mycro.UUCP> 
      Dan Norstedt <?> 
      Alan J. Brumbaugh <brumba@maize.rtsg.mot.com> 
      Mike Surikov <surikov@adonis.ias.msk.su> 
 
  More errors have been reported by: 
      Varol Kaptan <E66964%trmetu.bitnet@relay.EU.net> 
 
 
 
Introduction 
============ 
 
  One of the most universal parts of the PC (except for the CPU, of course :-) 
is its serial port. You can connect a mouse, a modem, a printer, a plotter, 
another PC, ... 
  But its usage (both software and hardware) is one of the best-kept secrets 
for most users, besides that it is not difficult to understand how to 
connect (not plug-in) devices to it and how to program it. 
  Regard this FAQ as a manual of the serial port of your PC for both 
hardware and software. 
 
 
Historical summary 
------------------ 
 
  In early days of telecommunications, errand-boys and optical signals (flags, 
lights, clouds of smoke) were the only methods of transmitting information 
across long distances. With increasing requirements on speed and growing 
amount of information, more practical methods were developed. One milestone 
was the first wire-bound transmission on May 24th, 1844 ("What hath God 
wrought", using the famous Morse alphabet). Well, technology improved a bit, 
and soon there were machines that could be used like typewriters, except that 
you typed not only on your own sheet of paper but also on somebody elses. 
The only thing that has changed on the step from the teletyper to your PC 
regarding serial communications is speed. 
 
 
The TTY (teletyping) protocol 
----------------------------- 
 
  Definition: A protocol is a clear description of the LOGICAL method of 
transmitting information. This does NOT include physical realisation. 
 
  There is a difference between bits per second and baud: 'baud' means 
'state changes on the line per second' while 'bits per second' ... 
well, bits per second means bits per second. You may find this a bit weird; 
there's only a difference if the line has more than two states. Since this 
is not the case with the RS232C port of your PC, I don't differentiate 
between 'baud' and 'bits per second' in this text (most people don't either). 
In most cases, 'baud' should be read as 'bps'... BTW: Some people count only 
the actual data-'bits per second', not the framing bits (start, parity, stop, 
see below). So 2400 bps at 8n1 carry 1920 bits of information per second, 
and modems send them at 600 baud thru' the phone wires, while 1200 bps at 
7e1 carry 840 bits of information per second that modems send at 1200 
baud. I know it's confusing... so just forget about it. It's really not 
that important for the purpose of this file. (But thanks for the hint, Alan!) 
 
  The TTYp uses two different states of the line called 'mark' and 'space'. 
(For the sake of clearness I name the line states 'high' and 'low'). 
If no data is transmitted, the line is in the 'high' ('space') state or 
'broken' (low). Data looks like 
 
      space  ----------+   +-------+   +---+   +-------  high  '0' 
                       |   |       |   |   |   | 
      mark             +---+       +---+   +---+         low  '1' 
 
                        (1)  --------(2)-------- (3) 
 
  (1) start bit   (2) data bits   (3) stop bit(s) 
 
  Both transmitter (TX) and receiver (RX) use the same data rate (measured 
in bps/baud [see above], which is the reciprocal value of the smallest time 
interval between two changes of the line state. TX and RX know about the 
number of data bits (probably with a parity bit added), and both know about 
the size of the stop step (called the stop bit or the stop bits, depending 
on the size of the stop step; normally 1, 1.5 or 2 times the size of a data  
bit). Data is transmitted bit-synchronously and word-asynchronously, which 
means that the size of the bits, the length of the words etc.pp. is clearly 
defined while the time between two words is undefined. 
  The start bit indicates the beginning of a new data word. It is used to 
synchronize transmitter and receiver and is always a logical '1' (so the 
line goes 'low'). 
  Data is transmitted LSB to MSB, which means that the least significant 
bit (LSB, Bit 0) is transmitted first with 4 to 7 bits of data following, 
resulting in 5 to 8 bits of data. A logical '0' is transmitted by the 
'high' state of the line, a logical '1' by 'low'. 
  A parity bit can be added to the data bits to allow error detection. 
There are two (well, actually five) kinds of parity: odd and even (plus 
none, mark and space). Odd parity means that the number of 'low' steps in 
the data word (including parity bit) is always odd, so the parity bit is 
set accordingly (I don't have to explain 'even' parity, must I?). It is 
also possible to set the parity bit to a fixed state or to omit it. 
See Software section for details on types of parity. 
  The stop bit does not indicate the end of the word (as it could be 
derived from its name); it rather separates two consecutive words by 
putting the line into the 'high' state for a minimum time (that means the 
stop bit is a logical '0'). 
  The protocol is usually described by a sequence of numbers and letters, 
eg. 8n1 means 1 start bit (always), 8 bits of data, no parity bit, 1 stop 
bit. 7e2 would indicate 7 bits of data, even parity, 2 stop bits (but I've 
never seen this one...). The usual thing is 8n1 or 7e1. 
  Early teletypers used the neckbreaking speed of 50 baud (which means 
that one step is 20ms), 5 bits of data, no parity bit and 1.5 stop bits (don't 
ask me why!). Your PC is capable of serial transmission at up to 115,200 
baud (step size of 8.68 microseconds!). Typical rates are 300 baud, 1200 baud, 
2400 baud and 9600 baud. (Remember: two line states -> baud is bps) 
 
 
The physical transmission 
------------------------- 
 
  Teletypers use a closed-loop line with a space current of 20ma and a 
mark current of 0ma (typically), which allows to detect a 'broken line' 
(hence the name, see the Software section). The RS232C port of your PC uses 
voltages rather than currents to indicate logical states: 'mark'/'low' is 
signaled by -3v to -15v (typically -12v) and represents a logical '1', 
'space'/'high' is signaled by +3v to +15v (typically +12V) and represents a 
logical '0'. The typical output impedance of the serial port of a PC is 
2 kiloohms (resulting in about 5ma @ 10v), the typical input impedance is 
about 4.3 kiloohms, so there should be a maximum fan-out of 5 (5 inputs can 
be connected to 1 output). Please don't rely on this, it may differ from PC 
to PC. 
  Three lines (RX, TX & ground) are at least needed. 
 
Q. Why does my PC have a 25pin/9pin connector if there are only 3 lines 
   needed? 
A. There are several status lines that are only used with modems etc. See the 
   software section of this FAQ. 
 
Q. How can I easily connect two PCs by a three-wire lead? 
A. This connection is called a 'null-modem' connection. RX1 is connected 
   to TX2 and vice versa, GND1 to GND2. In addition to this, connect RTS 
   to CTS & DCD and connect DTR to DSR (modem software often relies on 
   that). See the hardware section for further details. 
 
  Please be aware that at 115,200 baud (ie. ca. 115 kHz, but we need the 
harmonics up to at least 806 kHz) lines can no longer be regarded as 'ideal' 
transmission lines. They are low-pass filters and tend to reflect and mutilate 
the signals, but some metres of twisted wire should be OK (I use 3m of 
screened audio cable, and it works fine. Not that other kinds of wire wouldn't 
do; I took what I found). See a good book on transmission lines for details... 
 
 
 
Hardware 
======== 
 
 
The connectors 
-------------- 
 
  PCs have 9pin/25pin male SUB-D connectors. The pin layout is as follows 
(seen from outside your PC): 
 
        1                         13      1        5 
      _______________________________      _______________ 
      \  . . . . . . . . . . . . .  /      \  . . . . .  / 
       \  . . . . . . . . . . . .  /     \  . . . .  / 
        ---------------------------          ----------- 
        14                      25            6       9 
 
 Name (V24)  25pin  9pin  Dir  Full name               Remarks 
-------------------------------------------------------------------------- 
    TxD         2     3    o   Transmit Data 
    RxD         3     2    i   Receive Data 
    RTS         4     7    o   Request To Send 
    CTS         5     8    i   Clear To Send 
    DTR        20     4    o   Data Terminal Ready 
    DSR         6     6    i   Data Set Ready 
    RI         22     9    i   Ring Indicator 
    DCD         8     1    i   Data Carrier Detect 
    GND         7     5    -   Signal ground 
     -          1     -    -   Protective ground       Don't use this one! 
 
  The most important lines are RxD, TxD, and GND. Others are used with 
modems, printers and plotters to indicate internal states. 
  '1' ('mark', 'low') means -3v to -15V, '0' ('space', 'high') means +3v 
to +15v. On status lines, 'high' is the active state: status lines go to the 
'high' state to signal events. 
 
  The lines are: 
 
  RxD, TxD: These lines carry the data; 'low' is '1' and 'high' is '0'. 
  RTS, CTS: Are used by the PC and the modem/printer/whatsoever (further 
    on referred to as the data set) to start/stop a communication. The PC 
    sets RTS to 'high', and the data set responds with CTS 'high'. (always 
    in this order). If the data set wants to stop/interrupt the communication 
    (eg. buffer overflow), it drops CTS to 'low'; the PC uses RTS to control 
    the data flow. 
  DTR, DSR: Are used to establish a connection at the very beginning, i.e. 
    the PC and the data set 'shake hands' first to assure they are both 
    present. The PC sets DTR to 'high', and the data set answers with DSR 
    'high'. Modems often indicate hang-up by resetting DSR to 'low'. 
  (These six lines plus GND are often referred to as '7 wire'-connection or 
  'hand shake'-connection.) 
  DCD: The modem uses this line to indicate that it has detected the 
    carrier of the modem on the other side of the phone line. 
  RI: The modem uses this line to signal that 'the phone rings' (even if 
    there is neither a bell fitted to your modem nor a phone connected B-). 
  GND: The 'signal ground', ie. the reference level for all signals. 
  Protective ground: This line is connected to the power ground of the 
    serial adapter. It should not be used as a signal ground, and it 
    MUST NOT be connected to GND (even if your DMM [Digital MultiMeter] shows 
    up an ohmic connection!). Connect this line to the screen of the lead (if 
    there is one), but beware doing this on both sides of the cable! Ground 
    loops can lead to malfunction and/or damage of the port! On the other 
    hand, connecting protective ground on both sides ensures that no large 
    currents flow thru' GND in case of an insulation defect on one side 
    (hence the name). 
 
  Technical data (typical): 
 
    Signal level: -10.5v/+11v 
    Short circuit current: 6.8ma  (yes, that's enough for your mouse!) 
    Output impedance: ca 2 kiloohms (non-linear!) 
    Input impedance: ca 4.3 kiloohms (non-linear!) 
 
 
Connecting devices (or computers) 
------------------ 
 
  Normally, a 7 wire connection is used. Connect: 
        GND1    to    GND2 
 RxD1    to    TxD2 
 TxD1    to    RxD2 
 DTR1    to    DSR2  (or DTR2 if it's a data set) 
 DSR1    to    DTR2  (or DSR2 if it's a data set) 
 RTS1    to    CTS2  (or RTS2 if it's a data set) 
 CTS1    to    RTS2  (or CTS2 if it's a data set) 
  If a modem is connected, add lines for the following: 
        RI, DCD 
  If software wants it, connect DCD1 to CTS1 and DCD2 to CTS2. 
  BEWARE! While PCs use pin 2 for RxD and pin 3 for TxD, modems normally 
have those pins reversed! This allows to easily connect pin2 to pin2, pin3 
to pin 3 etc. If you connect two PCs, cross RxD and TxD. 
 
  If hardware handshaking is not needed, a so-called null-modem connection 
can be used. Connect: 
        GND1    to    GND2 
 RxD1    to    TxD2 
 TxD1    to    RxD2 
Additionally, connect (if software needs it): 
        RTS1    to    CTS1 & DCD1 
 RTS2    to    CTS2 & DCD2 
 DTR1    to    DSR1 
 DTR2    to    DSR2 
You won't need long wires for these! 
  The null-modem connection is used to establish an XON/XOFF-connection 
between two PCs (see software section for details). 
  Remember: the names DTR, DSR, CTS & RTS refer to the lines as seen from 
the PC. This means that for your data set DTR & RTS are incoming signals 
and DSR & CTS are outputs! Modems, printers plotters etc. are connected 
1:1, ie. pin x to pin x. 
 
 
Base addresses & interrupts 
--------------------------- 
 
  Normally, the following list is correct: 
 
 
    Port     Base address    Int # 
 
    COM1         0x3F8        0xC 
    COM2         0x2F8        0xB 
    COM3         0x3E8        0xC 
    COM4         0x2E8        0xB 
 
  See the Programming section for a routine that detects the interrupt 
number. 
 
  In PCs, serial communication is realized with a set of three chips 
(there are no further components needed! (I know of the need of address 
logic & interrupt logic ;-) )): a UART (Universal Asynchronous 
Receiver/Transmitter) and two line drivers. Normally, the 82450/16450/8250 
does the 'brain work' while the 1488 and 1489 drive the lines.  
  These chips are produced by many manufacturers; it's of no importance 
which letters are printed in front of the numbers (mostly NS for National 
Semiconductor). Don't regard the letters behind the number also; they just 
indicate special features and packaging (Advanced, New, MILitary, 
bug fixes [see below] etc.) or classification. Letters in between the numbers 
(eg. 16C450) indicate technology (C=CMOS). 
  You might have heard of the possibility to replace the 16450 by a 16550A 
to improve reliability and software throughput. This is only useful if your 
software is able to use the FIFO (first in-first out) buffer features. The 
chips are fully pin-compatible except for two pins that are not used by 
any serial adapter card known to the author: pin 24 (CSOUT, chip select out) 
and pin 29 (NC, no internal connection). With the 16550A, pin 24 is -TXRDY 
and pin 29 is -RXRDY, signals that aren't needed and that even won't care if 
they are shorted to +5v or ground. Therefore it should always be possible to 
simply replace the 16450 by the 16550A - even if it's not always useful due 
to lacking software capabilities. IT IS DEFINITELY NOT NECESSARY FOR 
COMMUNICATION AT UP TO LOUSY 9600 BAUD! These rates can easily be handled by 
any CPU and the interrupt-driven communication won't slow down the computer 
substantially. But if you want to use high-speed transfer with or without 
using the interrupt features (ie. by 'polling'), it is recommended to use 
the 16550A in order to make transmission more reliable if your software 
supports it (see excursion some pages below). 
 
 
How to detect which chip is used 
-------------------------------- 
 
  This is really not difficult. The 8250 has no scratch register (see data 
sheet info below), the 16450/82450 has no FIFO, the 16550 has no working 
FIFO B-) and the 16550A performs alright. See the Software section for 
an example program that detects which one is used in your PC. 
 
 
Data sheet information 
---------------------- 
 
  Some hardware information taken from the data sheet of National 
Semiconductor (shortened and commented): 
 
  Pin description of the 16450 (16550A) [Dual-In-Line package]: 
 
                   +-----+ +-----+ 
               D0 -|  1  +-+   40|- VCC 
               D1 -|  2        39|- -RI 
               D2 -|  3        38|- -DCD 
               D3 -|  4        37|- -DSR 
               D4 -|  5        36|- -CTS 
               D5 -|  6        35|- MR 
               D6 -|  7        34|- -OUT1 
               D7 -|  8        33|- -DTR 
             RCLK -|  9        32|- -RTS 
              SIN -| 10        31|- -OUT2 
             SOUT -| 11        30|- INTR 
              CS0 -| 12        29|- NC (-RXRDY) 
              CS1 -| 13        28|- A0 
             -CS2 -| 14        27|- A1 
         -BAUDOUT -| 15        26|- A2 
              XIN -| 16        25|- -ADS 
             XOUT -| 17        24|- CSOUT (-TXRDY) 
              -WR -| 18        23|- DDIS 
               WR -| 19        22|- RD 
              VSS -| 20        21|- -RD 
                   +-------------+ 
 
  Note: The status signals are negated! If you write a '1' to the appro- 
priate register bit, the pin goes 'low'. On its way to the port, the 
signal is inverted again; this means that the status line at the port 
goes 'high' if you write a '1'. The same is true for inputs: you get a 
'1' from the register bit if the line at the port is 'high'. 
 
A0, A1, A2, Register Select, Pins 26-28: 
Address signals connected to these 3 inputs select a UART register for 
the CPU to read from or to write to during data transfer. A table of 
registers and their addresses is shown below. Note that the state of the 
Divisor Latch Access Bit (DLAB), which is the most significant bit of the 
Line Control Register, affects the selection of certain UART registers. 
The DLAB must be set high by the system software to access the Baud 
Generator Divisor Latches. 
 
  DLAB  A2  A1  A0    Register 
    0    0   0   0    Receive Buffer (read) Transmitter Holding Reg. (write) 
    0    0   0   1    Interrupt Enable 
    x    0   1   0    Interrupt Identification (read) 
    x    0   1   0    FIFO Control (write) [undefined on the 16450. CB] 
    x    0   1   1    Line Control 
    x    1   0   0    Modem Control 
    x    1   0   1    Line Status 
    x    1   1   0    Modem Status 
    x    1   1   1    Scratch [special use on some boards. CB] 
    1    0   0   0    Divisor Latch (LSB) 
    1    0   0   1    Divisor Latch (MSB) 
 
-ADS, Address Strobe, Pin 25: The positive edge of an active Address 
Strobe (-ADS) signal latches the Register Select (A0, A1, A2) and Chip 
Select (CS0, CS1, -CS2) signals. 
Note: An active -ADS input is required when Register Select and Chip 
Select signals are not stable for the duration of a read or write 
operation. If not required, tie the -ADS input permanently low. [As it is 
done in your PC. CB] 
 
-BAUDOUT, Baud Out, Pin 15: This is the 16 x clock signal from the 
transmitter section of the UART. The clock rate is equal to the main 
reference oscillator frequency divided by the specified divisor in the 
Baud Generator Divisor Latches. The -BAUDOUT may also be used for the 
receiver section by tying this output to the RCLK input of the chip. [Yep, 
that's true for your PC. CB]. 
 
CS0, CS1, -CS2, Chip Select, Pins 12-14: When CS0 and CS1 are high and CS2 
is low, the chip is selected. This enables communication between the UART 
and the CPU. 
 
-CTS, Clear To Send, Pin 36: When low, this indicates that the modem or 
data set is ready to exchange data. This signal can be tested by reading 
bit 4 of the MSR. Bit 4 is the complement of this signal, and Bit 0 is '1' 
if -CTS has changed state since the previous reading (bit0=1 generates an 
interrupt if the modem status interrupt has been enabled). 
 
D0-D7, Data Bus, Pins 1-8: Connected to the data bus of the CPU. 
 
-DCD, Data Carrier Detect, Pin 38: blah blah blah, can be tested by 
reading bit 7 / bit 3 of the MSR. Same text as -CTS. 
 
DDIS, Driver Disable, Pin 23: This goes low whenever the CPU is reading 
data from the UART. 
 
-DSR, Data Set Ready, Pin 37: blah, blah, blah, bit 5 / bit 1 of MSR. 
 
-DTR, Data Terminal Ready, Pin 33: can be set active low by programming 
bit 0 of the MCR '1'. Loop mode operation holds this signal in its 
inactive state. 
 
INTR, Interrupt, Pin 30: goes high when an interrupt is requested by the 
UART. Reset low by the MR. 
 
MR, Master Reset, Pin 35: Schmitt Trigger input, resets internal registers 
to their initial values (see below). 
 
-OUT1, Out 1, Pin 34: user-designated output, can be set low by 
programming bit 2 of the MCR '1' and vice versa. Loop mode operation holds 
this signal inactive high. [Not used in the PC. CB] 
 
-OUT2, Out 2, Pin 31: blah blah blah, bit 3, see above. [Used in your PC to 
connect the UART to the interrupt line of the slot when '1'. CB] 
 
RCLK, Receiver Clock, Pin 9: This input is the 16 x baud rate clock for 
the receiver section of the chip. [Normally connected to -BAUDOUT, as in 
your PC. CB] 
 
RD, -RD, Read, Pins 22 and 21: When Rd is high *or* -RD is low while the 
chip is selected, the CPU can read data from the UART. [One of these is 
normally tied. CB] 
 
-RI, Ring Indicator, Pin 39: blah blah blah, Bit 6 / Bit 2 of the MSR. 
[Bit 2 indicates only change from active low to inactive high! Curious, 
isn't it? CB] 
 
-RTS, Request To Send, Pin 32: blah blah blah, see DTR (Bit 1). 
 
SIN, Serial Input, Pin 10. 
 
SOUT, Serial Output, Pin 11: ... Set to 'break' (constantly 'low') upon MR. 
 
-RXRDY, -TXRDY: refer to NS data sheet. Those pins are used for DMA 
channeling. Since they are not connected in your PC, I won't describe them 
here. 
 
VCC, Pin 40, +5v 
 
VSS, Pin 20, GND 
 
WR, -WR: same as RD, -RD for writing data. 
 
XIN, XOUT, Pins 16 and 17: Connect a crystal here (1.5k betw. xtal & pin 17) 
and pin 16 with a capacitor of approx. 20p to GND and other xtal conn. 40p 
to GND. Resistor of approx. 1meg parallel to xtal. Or use pin 16 as an input 
and pin 17 as an output for an external clock signal of up to 8 MHz. 
 
 
Absolute Maximum Ratings: 
 
  Temperature under bias: 0 C to +70 C 
  Storage Temperature: -65 C to 150 C 
  All input or output voltages with respect to VSS: -0.5v to +7.0v 
  Power dissipation: 1W 
 
Further electrical characteristics see the very good data sheet of NS. 
 
UART Reset Configuration 
 
Register/Signal        Reset Control      Reset State 
-------------------------------------------------------------------- 
  IER                       MR            0000 0000 
  IIR                       MR            0000 0001 
  FCR                       MR            0000 0000 
  LCR                       MR            0000 0000 
  MCR                       MR            0000 0000 
  LSR                       MR            0110 0000 
  MSR                       MR            xxxx 0000 (according to signals) 
  SOUT                      MR            high 
  INTR (RCVR errs)     Read LSR/MR        low 
  INTR (data ready)    Read RBR/MR        low 
  INTR (THRE)          Rd IIR/Wr THR/MR   low 
  INTR (modem status)  Read MSR/MR        low 
  -OUT2                     MR            high 
  -RTS                      MR            high 
  -DTR                      MR            high 
  -OUT1                     MR            high 
  RCVR FIFO           MR/FCR1&FCR0/DFCR0  all bits low 
  XMIT FIFO           MR/FCR1&FCR0/DFCR0  all bits low 
 
 
 
Known problems with several chips 
--------------------------------- 
 
(From material Madis Kaal received from Dan Norstedt) 
 
    8250 and 8250-B: 
 
        * These UARTs pulse the INT line after each interrupt cause has 
          been serviced (which none of the others do). [Generates interrupt 
          overhead. CB] 
 
        * The start bit is about 1 us longer than it ought to be. [This 
          shouldn't be a problem. CB] 
 
        * 5 data bits and 1.5 stop bits doesn't work. 
 
        * When a 1 bit is written to the bit 1 (Tx int enab) in the IER, 
          a Tx interrupt is generated. This is an erroneous interrupt 
          if the THRE bit is not set. [So don't set this bit as long as 
          the THRE bit isn't set. CB] 
 
        * The first valid Tx interrupt after the Tx interrupt is enabled 
          is probably missed. Suggested workaround: 
          1) Wait for the THRE bit to become set. 
          2) Disable CPU interrupts. 
          3) Write Tx interrupt enable to the IER. 
          4) Write Tx interrupt enable to the IER again. 
          5) Enable CPU interrupts. 
 
        * The TEMT (bit 6) doesn't work properly. 
 
        * If both the Rx and Tx interrupts are enabled, and a Rx interrupt 
          occurs, the IIR indication may be lost; Suggested workarounds: 
          1) Test THRE bit in the Rx routine, and either set IER bit 1 
             or call the Tx routine directly if it is set. 
          2) Test the THRE bit instead of using the IIR. 
 
 [If one of these chips vegetates in your PC, go get your solder 
        iron heated... CB] 
 
    8250A, 82C50A, 16450 and 16C450: 
 
        * (Same problem as above:) 
          If both the Rx and Tx interrupts are enabled, and a Rx interrupt 
          occurs, the IIR indication may be lost; Suggested workarounds: 
          1) Test THRE bit in the Rx routine, and either set IER bit 1 
             or call the Tx routine directly if it is set. 
          2) Test the THRE bit instead of using the IIR. 
   3) [Don't enable both interrupts at the same time. I've never 
             had any need to do this. CB] 
   4) [Replace the chip by a 16550A; it has this bug fixed. CB] 
 
    16550 (without the A): 
 
        * Rx FIFO bug: Sometimes a FIFO will get extra characters. 
          [This seemed to be very embarrassing for NS; they've added a 
          simple detection method for the 16550A (bit 6 of IIR). CB] 
 
No 16550A bugs reported (yet?) 
 
[Same is true for the 16552, a two-in-one version of the 16550A. CB] 
 
 
 
Software 
======== 
 
 
Register Description 
-------------------- 
 
See "Hardware" for addresses. 
 
Register  Bit 0    Bit 1    Bit 2    Bit 3    Bit 4    Bit 5    Bit 6    Bit 7 
 
RBR (r/o)  ----------------------- data bits received ------------------------ 
THR (w/o)  ------------------ data bits to be transmitted -------------------- 
IER       ERBFI    ETBEI    ELSI     EDSSI      0        0        0       0 
IIR (r/o) pending  IID0     IID1     IID2       0        0      FIFO en  FIFOen 
FCR (w/o) enable   RFres    XFres    DMAsel     0        0      - RX trigger - 
LCR       - word length -   stopbits PAR en   even sel stick par SBR     DLAB 
MCR       DTR      RTS      OUT1     OUT2     Loop       0        0       0 
LSR       RBF      OE       PE       FE       Break    THRE     TEMT    FIFOerr 
MSR       DCTS     DDSR     TERI     DDCD     CTS      DSR      RI      DCD 
 
ERBFI:   Enable Receiver Buffer Full Interrupt 
ETBEI:   Enable Transmitter Buffer Empty Interrupt 
ELSI:    Enable Line Status Interrupt 
EDSSI:   Enable Delta Status Signals Interrupt 
IID#:    Interrupt IDentification 
RFres:   Receiver FIFO reset 
XFres:   Transmitter FIFO reset 
SBR:     Set BReak 
RBF:     Receiver Buffer Full (Data Available) 
OE:      Overrun Error 
PE:      Parity Error 
FE:      Framing Error 
THRE:    Transmitter Holding Register Empty (new data can be written to THR) 
TEMT:    Transmitter Empty (last word has been sent) 
DCTS:    Delta Clear To Send 
DDSR:    Delta Data Set Ready 
TERI:    Trailing Edge Ring Indicator 
DDCD:    Delta Data Carrier Detect 
 
LCR (Line Control Register): 
 
   Bit 1  Bit 0    word length         Bit 2      Stop bits 
     0      0        5 bits              0            1 
     0      1        6 bits              1          1.5/2 
     1      0        7 bits         (1.5 if word length is 5) 
     1      1        8 bits   (1.5 does not work with some chips, see above) 
 
   Bit 5  Bit 4  Bit 3     Parity type       Bit 6   SOUT condition 
     x      x      0       no parity           0     normal operation 
     0      0      1       odd parity          1     force 'space' (break) 
     0      1      1       even parity       Bit 7   DLAB 
     1      0      1       space parity        0     normal registers 
     1      1      1       mark parity         1     divisor at reg 0, 1 
 
  Space parity: The parity bit is always '1' (the line is 'low'). 
  Mark parity: The parity bit is always '0' (the line is 'high'). 
 
Baud Rate Generator: 
 
  DLAB must be set. Then write word (16 bits) to address 0 of the UART (this 
is the base address) or the lower byte to 0 and the higher byte to 1 to 
program the baud rate as follows: 
     xtal frequency in Hz / 16 / rate = divisor 
  Your PC uses an xtal frequency of 1.8432 MHz (that's 1843200 Hz B-). 
  Do *NOT* use 0 as a divisor (your maths teacher told you so)! [It 
results in a rate of about 3500 baud. CB] 
  An error of up to 5 percent is irrelevant. 
 
  Some values: 
 
     Baud rate   Divisor (hex)   Divisor (dec)   Percent Error 
  50          900             2304            0.0% 
         75          600             1536            0.0% 
        110          417             1047            0.026% 
        134.5        359              857            0.058% 
        150          300              768            0.0% 
        300          180              384            0.0% 
 600           C0              192            0.0% 
       1200           60               96            0.0% 
       1800           40               64            0.0% 
       2000           3A               58            0.69% 
       2400           30               48            0.0% 
       3600           20               32            0.0% 
       4800           18               24            0.0% 
       7200           10               16            0.0% 
       9600            C               12            0.0% 
      19200            6                6            0.0% 
      38400            3                3            0.0% 
      56000            2                2            2.86% 
     115200            1                1            0.0% 
 
  The 16450 is capable of up to 512 kbaud according to NS. 
  NS specifies that the 16550A is capable of 256 kbaud if you use a 4 MHz 
or an 8 MHz crystal. But a staff member of NS Germany (I know that this 
abbreviation is not well-chosen B-( ) told one of my friends on the phone 
that it runs correctly at 512 kbaud as well, but I don't know if the 
1488/1489 manage this. This is true for the 16C552, too. 
  BTW: Ever tried 1.76 baud? Kindergarten kids write faster. 
  Mice typically use 2400 baud, 8n1. 
 
 
LSR (Line Status Register): 
 
   Bit 0    Data Ready (DR). Reset by reading RBR. 
   Bit 1    Overrun Error (OE). Reset by reading LSR. Indicates loss of data. 
   Bit 2    Parity Error (PE). Indicates transmission error. Reset by LSR. 
   Bit 3    Framing Error (FE). Indicates missing stop bit. Reset by LSR. 
   Bit 4    Break Indicator (BI). Set if 'low' for more than 1 word ('break'). 
            Reset by reading LSR. 
   Bit 5    Transmitter Holding Register Empty (THRE). Indicates that a new 
            word can be written to THR. Reset by writing THR. 
   Bit 6    Transmitter Empty (TEMT). Indicates that no transmission is 
            running. Reset by reading LSR. 
   Bit 7    Set if at least 1 word in FIFO has been received with an error. 
            Cleared by reading LSR if there is no further error in the FIFO. 
     Clear with all other chips. 
 
FCR (FIFO Control Register): 
 
   Bit 0:    FIFO enable. 
   Bit 1:    Clear receiver FIFO. This bit is self-clearing. 
   Bit 2:    Clear transmitter FIFO. This bit is self-clearing. 
   Bit 3:    DMA mode (pins -RXRDY and -TXRDY), see sheet 
   Bits 6-7: Trigger level of the DR-interrupt. 
 
   Bit 7  Bit 6    Receiver FIFO trigger level 
     0      0          1 
     0      1          4 
     1      0          8 
     1      1         14 
 
 
   Excursion: Why and how to use the FIFOs (by Scott C. Sadow) 
   ----------------------------------------------------------- 
 
   Normally when transmitting or receiving, the UART generates an 
   interrupt for every character sent or received. For 2400 baud, typically 
   this is 240/second. For 115,200 baud, this means 11,520/second. With FIFOs 
   enabled, the number of interrupts is greatly reduced. For transmit 
   interrupts, the UART indicates the transmit holding register is not busy 
   until the 16 byte FIFO is full. A transmit hold register empty interrupt 
   is not generated until the FIFO is empty (last byte is being sent) Thus, 
   the number of transmit interrupts is reduced by a factor of 16. For 
   115,200 baud, this means only 720 interrupts/second. For receive data 
   interrupts, the processing is similar to transmit interrupts. The main 
   difference is that the number of bytes in the FIFO before generating an 
   interrupt can be set. When the trigger level is reached, a receive data 
   interrupt is generated, but any other data received is put in the FIFO. 
   The receive data interrupt is not cleared until the number of bytes in the 
   FIFO is below the trigger level. 
 
   To add 16550A support to existing code, there are 2 requirements. 
 
      1) When reading the IIR to determine the interrupt source, only 
         use the lower 3 bits. 
 
      2) After the existing UART initialization code, try to enable the 
         FIFOs by writing to the FCR. (A value of C7 hex will enable FIFO 
  mode, clear both FIFOs, and set the receive trigger level at 14 
  bytes). Next, read the IIR. If Bit 6 of the IIR is not set, the 
  UART is not a 16550A, so write 0 to the FCR to disable FIFO mode. 
 
 
IIR (Interrupt Identification Register): 
 
   Bit 3  Bit 2  Bit 1  Bit 0    Priority   Source    Description 
     0      0      0      1                 none 
     0      1      1      0      highest    Status    OE, PE, FE or BI of the 
                                                      LSR set. Serviced by 
            reading the LSR. 
     0      1      0      0      second     Receiver  DR or trigger level rea- 
                                                      ched. Serviced by read- 
                                                      ing RBR 'til under level 
     1      1      0      0      second     FIFO      No Receiver FIFO action 
                                                      since 4 words' time 
            (neither in nor out) but 
            data in RX-FIFO. Serviced 
            by reading RBR. 
     0      0      1      0      third      Transm.   THRE. Serviced by read- 
                                                      ing IIR (if source of 
            int only!!) or writing 
            to THR. 
     0      0      0      0      lowest     Modem     One of the delta flags 
                                                      in the MSR set. Serviced 
                                                      by reading MSR. 
   Bit 6 & 7: 16550A: set if FCR bit 0 set. 
              16550:  bit 7 set, bit 6 cleared 
       others: clear 
   In most software applications bits 3, 6 & 7 should be masked when servicing 
   the interrupt since they are not relevant. These bits cause trouble with  
   old software relying on that they are cleared... 
   NOTE! Even if some of these interrupts are masked, the service routine 
   can be confronted with *all* states shown above when the IIR is loop-polled 
   until bit 0 is set. Check examples in the Programming section. 
 
IER (Interrupt Enable Register): 
 
   Bit 0:   If set, DR interrupt is enabled. 
   Bit 1:   If set, THRE interrupt is enabled. 
   Bit 2:   If set, Status interrupt is enabled. 
   Bit 3:   If set, Modem status interrupt is enabled. 
 
MCR (Modem Control Register): 
 
   Bit 0:   Programs -DTR. If set, -DTR is low and the DTR pin of the port 
            goes 'high'. 
   Bit 1:   Programs -RTS. dito. 
   Bit 2:   Programs -OUT1. Not used in a PC. 
   Bit 3:   Programs -OUT2. If set to 1, interrupts generated by the UART 
            are transferred to the ICU (Interrupt Control Unit) while 0 
            sets the interrupt output of the card to high impedance. 
   Bit 4:   '1': local loopback. All outputs disabled. This is a means of 
            testing the chip: you 'receive' all the data you send. 
 
MSR (Modem Status Register): 
 
   Bit 0:   Delta CTS. Set if CTS has changed state since last reading. 
   Bit 1:   Delta DSR. Set if DSR has changed state since last reading. 
   Bit 2:   TERI. Set if -RI has changed from low to high (ie. RI at port 
            has changed from 'high' to 'low' [?]). 
   Bit 3:   Delta DCD. Set if DCD has changed state since last reading. 
   Bit 4:   CTS. 1 if 'high' at port. 
   Bit 5:   DSR. dito. 
   Bit 6:   RI. If loopback is selected, it is equivalent to OUT1. 
   Bit 7:   DCD. 
 
 
 
BIOS API (Application Programs Interface) 
----------------------------------------- 
 
  PC programs are meant to use the BIOS routines to program the UARTs. 
Even though this is *NOT RECOMMENDED* by me, I give you the BIOS calls as 
specified by Big Blue. Call INT 14h with: 
 
 
  AH=00h    Serial port - Initialize 
 
     AL: see table 
     DX: Port number (0-3; 0 equ. 0x3f8, 1 equ. 0x2f8, etc., see Hardware) 
 
     Bit 7  Bit 6  Bit 5      Rate [bps]         Bit 4  Bit 3     Parity 
       1      1      1        9600                 0      0       none 
       1      1      0        4800                 1      0       none 
       1      0      1        2400                 0      1       odd 
       1      0      0        1200                 1      1       even 
       0      1      1         600 
       0      1      0         300               Bit 1  Bit 0     Data bits 
       0      0      1         150                 0      0         5 
       0      0      0         110                 0      1         6 
                                                   1      0         7 
     Bit 2   0 -> 1 stop bit, 1 -> 2 stop bits     1      1         8 
 
     Returns:  
     AH: RS-232 line status bits 
        0: RBF  - input data is available in buffer 
        1: OE   - data has been lost 
        5: THRE - room is available in output buffer 
        6: TEMT - output buffer empty 
     AL: Modem status bits 
        3: always 1 
        7: DCD - carrier detect 
 
   AH=01h    Serial port - Write character 
 
     AL: character to be sent 
     DX: Port 
 
     Returns: 
     AH: Bit 7 clear if successful, set if not. Bits 0-6 see INT 14h AH=03h 
 
   AH=02h    Serial port - Read character 
   
     DX: Port 
 
     Returns: 
     AH: Line Status (see AH=03h) 
     AL: Received character (if AH bit 7 is clear) 
 
     Note: 
     This routine times out if DSR is not asserted, even if data is 
     available! 
 
   AH=03h    Serial port - Get port status 
 
     DX: Port 
 
     Returns: 
     AH: Line Status 
        Bit 7: Timeout 
 Bit 6: TEMT Transmitter empty 
 Bit 5: THRE Transmitter Holding Register Empty 
 Bit 4: Break (broken line detected) 
 Bit 3: FE Framing error 
 Bit 2: PE Parity error 
 Bit 1: OE Overrun error 
 Bit 0: RDF Receiver buffer full (data available) 
     AL: Modem Status 
        Bit 7: DCD Carrier detect 
 Bit 6: RI Ring indicator 
 Bit 5: DSR Data set ready 
 Bit 4: CTS Clear to send 
 Bit 3: DDCD Delta carrier detect 
 Bit 2: TERI Trailing edge of ring indicator 
 Bit 1: DDSR Delta data set ready 
 Bit 0: DCTS Delta Clear to send 
 
 
BIOS variables in the Data Segment at segment 40h: 
 
     Offset   Size     Description 
      00h     WORD     Base I/O address of 1st serial I/O port, zero if none 
      02h     WORD     Base I/O address of 2nd serial I/O port, zero if none 
      04h     WORD     Base I/O address of 3rd serial I/O port, zero if none 
      06h     WORD     Base I/O address of 4th serial I/O port, zero if none 
     Note: Above fields filled in turn by POST as it finds serial 
     ports. POST never leaves gaps. DOS and BIOS serial device 
     numbers may be redefined by re-assigning these fields. 
     [POST: Power-On Self Test. CB] 
 
 
  This information is sneaked from Ralf Brown's famous interrupt list (hope 
he doesn't mind). If you want more detailed facts on this interrupt, refer 
to this list. It's available from several FTP sites. 
 
(continued) 
 
-- 
------------- This compilation of characters brought to you by: ------------- 
Chris Blum  Fr.-Ebert-Str. 50  66578 Heiligenwald  Germany (+49)(0)6821 67476 
Internet: chbl@stud.uni-sb.de (preferred)   or   et11hks4@etcip1.ee.uni-sb.de 
The opinions expressed above are not necessarily my own, but if anybody feels 
embarrassed by them they most probably are. YOU =:-{ ME ;-) YOU :-) or <ZOT!>