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 Steve Poulsen Scott C. Sadow Dan Norstedt Alan J. Brumbaugh Mike Surikov More errors have been reported by: Varol Kaptan 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