Part One : Hardware (PC's)
Part Two : Serial Port's Registers (PC's)
Port Addresses & IRQ's
Table 3 : Standard Port Addresses
Above is the standard port addresses. These should work for most P.C's. If you just happen to be lucky enough to own a IBM P/S2 which has a micro-channel bus, then expect a different set of addresses and IRQ's. Just like the LPT ports, the base addresses for the COM ports can be read from the BIOS Data Area.
Table 4 - COM Port Addresses in the BIOS Data Area;
The above table shows the address at which we can find the Communications (COM) ports addresses in the BIOS Data Area. Each address will take up 2 bytes. The following sample program in C, shows how you can read these locations to obtain the addresses of your communications ports.
Table 5 : Table of Registers
DLAB ?
You will have noticed in the table of registers that there is a DLAB column. When DLAB is set to '0' or '1' some of the registers change. This is how the UART is able to have 12 registers (including the scratch register) through only 8 port addresses. DLAB stands for Divisor Latch Access Bit. When DLAB is set to '1' via the line control register, two registers become available from which you can set your speed of communications measured in bits per second.
The UART will have a crystal which should oscillate around 1.8432 MHZ. The UART incorporates a divide by 16 counter which simply divides the incoming clock signal by 16. Assuming we had the 1.8432 MHZ clock signal, that would leave us with a maximum, 115,200 hertz signal making the UART capable of transmitting and receiving at 115,200 Bits Per Second (BPS). That would be fine for some of the faster modems and devices which can handle that speed, but others just wouldn't communicate at all. Therefore the UART is fitted with a Programmable Baud Rate Generator which is controlled by two registers.
Lets say for example we only wanted to communicate at 2400 BPS. We worked out that we would have to divide 115,200 by 48 to get a workable 2400 Hertz Clock. The "Divisor", in this case 48, is stored in the two registers controlled by the "Divisor Latch Access Bit". This divisor can be any number which can be stored in 16 bits (ie 0 to 65535). The UART only has a 8 bit data bus, thus this is where the two registers are used. The first register (Base + 0) when DLAB = 1 stores the "Divisor latch low byte" where as the second register (base + 1 when DLAB = 1) stores the "Divisor latch high byte."
Below is a table of some more common speeds and their divisor latch high bytes & low bytes. Note that all the divisors are shown in Hexadecimal.
Table 6 : Table of Commonly Used Baudrate Divisors
Interrupt Enable Register (IER)
Table 7 : Interrupt Enable Register
The Interrupt Enable Register could possibly be one of the easiest registers on a UART to understand. Setting Bit 0 high enables the Received Data Available Interrupt which generates an interrupt when the receiving register/FIFO contains data to be read by the CPU.
Bit 1 enables Transmit Holding Register Empty Interrupt. This interrupts the CPU when the transmitter buffer is empty. Bit 2 enables the receiver line status interrupt. The UART will interrupt when the receiver line status changes. Likewise for bit 3 which enables the modem status interrupt. Bits 4 to 7 are the easy ones. They are simply reserved. (If only everything was that easy!)
Interrupt Identification Register (IIR)
Table 8 : Interrupt Identification Register
The interrupt identification register is a read only register. Bits 6 and 7 give status on the FIFO Buffer. When both bits are '0' no FIFO buffers are active. This should be the only result you will get from a 8250 or 16450. If bit 7 is active but bit 6 is not active then the UART has it's buffers enabled but are unusable. This occurs on the 16550 UART where a bug in the FIFO buffer made the FIFO's unusable. If both bits are '1' then the FIFO buffers are enabled and fully operational.
Bits 4 and 5 are reserved. Bit 3 shows the status of the time-out interrupt on a 16550 or higher.
Lets jump to Bit 0 which shows whether an interrupt has occurred. If an interrupt has occurred it's status will shown by bits 1 and 2. These interrupts work on a priority status. The Line Status Interrupt has the highest Priority, followed by the Data Available Interrupt, then the Transmit Register Empty Interrupt and then the Modem Status Interrupt which has the lowest priority.
First In / First Out Control Register (FCR)
Table 9 : FIFO Control Register
The FIFO register is a write only register. This register is used to control the FIFO (First In / First Out) buffers which are found on 16550's and higher.
Bit 0 enables the operation of the receive and transmit FIFO's. Writing a '0' to this bit will disable the operation of transmit and receive FIFO's, thus you will loose all data stored in these FIFO buffers.
Bit's 1 and 2 control the clearing of the transmit or receive FIFO's. Bit 1 is responsible for the receive buffer while bit 2 is responsible for the transmit buffer. Setting these bits to 1 will only clear the contents of the FIFO and will not affect the shift registers. These two bits are self resetting, thus you don't need to set the bits to '0' when finished.
Bit 3 enables the DMA mode select which is found on 16550 UARTs and higher. More on this later. Bits 4 and 5 are those easy type again, Reserved.
Bits 6 and 7 are used to set the triggering level on the Receive FIFO. For example if bit 7 was set to '1' and bit 6 was set to '0' then the trigger level is set to 8 bytes. When there is 8 bytes of data in the receive FIFO then the Received Data Available interrupt is set. See (IIR)
Line Control Register (LCR)
Table 10 : Line Control Register
The Line Control register sets the basic parameters for communication. Bit 7 is the Divisor Latch Access Bit or DLAB for short. We have already talked about what it does. (See DLAB?) Bit 6 Sets break enable. When active, the TD line goes into "Spacing" state which causes a break in the receiving UART. Setting this bit to '0' Disables the Break.
Bits 3,4 and 5 select parity. If you study the 3 bits, you will find that bit 3 controls parity. That is, if it is set to '0' then no parity is used, but if it is set to '1' then parity is used. Jumping to bit 5, we can see that it controls sticky parity. Sticky parity is simply when the parity bit is always transmitted and checked as a '1' or '0'. This has very little success in checking for errors as if the first 4 bits contain errors but the sticky parity bit contains the appropriately set bit, then a parity error will not result. Sticky high parity is the use of a '1' for the parity bit, while the opposite, sticky low parity is the use of a '0' for the parity bit.
If bit 5 controls sticky parity, then turning this bit off must produce normal parity provided bit 3 is still set to '1'. Odd parity is when the parity bit is transmitted as a '1' or '0' so that there is a odd number of 1's. Even parity must then be the parity bit produces and even number of 1's. This provides better error checking but still is not perfect, thus CRC-32 is often used for software error correction. If one bit happens to be inverted with even or odd parity set, then a parity error will occur, however if two bits are flipped in such a way that it produces the correct parity bit then an parity error will no occur.
Bit 2 sets the length of the stop bits. Setting this bit to '0' will produce one stop bit, however setting it to '1' will produce either 1.5 or 2 stop bits depending upon the word length. Note that the receiver only checks the first stop bit.
Bits 0 and 1 set the word length. This should be pretty straight forward. A word length of 8 bits is most commonly used today.
Modem Control Register (MCR)
Table 11 : Modem Control Register
The Modem Control Register is a Read/Write Register. Bits 5,6 and 7 are reserved. Bit 4 activates the loopback mode. In Loopback mode the transmitter serial output is placed into marking state. The receiver serial input is disconnected. The transmitter out is looped back to the receiver in. DSR, CTS, RI & DCD are disconnected. DTR, RTS, OUT1 & OUT2 are connected to the modem control inputs. The modem control output pins are then place in an inactive state. In this mode any data which is placed in the transmitter registers for output is received by the receiver circuitry on the same chip and is available at the receiver buffer. This can be used to test the UARTs operation.
Aux Output 2 maybe connected to external circuitry which controls the UART-CPU interrupt process. Aux Output 1 is normally disconnected, but on some cards is used to switch between a 1.8432MHZ crystal to a 4MHZ crystal which is used for MIDI. Bits 0 and 1 simply control their relevant data lines. For example setting bit 1 to '1' makes the request to send line active.
Line Status Register (LSR)
Table 12 : Line Status Register
The line status register is a read only register. Bit 7 is the error in received FIFO bit. This bit is high when at least one break, parity or framing error has occurred on a byte which is contained in the FIFO.
When bit 6 is set, both the transmitter holding register and the shift register are empty. The UART's holding register holds the next byte of data to be sent in parallel fashion. The shift register is used to convert the byte to serial, so that it can be transmitted over one line. When bit 5 is set, only the transmitter holding register is empty. So what's the difference between the two? When bit 6, the transmitter holding and shift registers are empty, no serial conversions are taking place so there should be no activity on the transmit data line. When bit 5 is set, the transmitter holding register is empty, thus another byte can be sent to the data port, but a serial conversion using the shift register may be taking place.
The break interrupt (Bit 4) occurs when the received data line is held in a logic state '0' (Space) for more than the time it takes to send a full word. That includes the time for the start bit, data bits, parity bits and stop bits.
A framing error (Bit 3) occurs when the last bit is not a stop bit. This may occur due to a timing error. You will most commonly encounter a framing error when using a null modem linking two computers or a protocol analyzer when the speed at which the data is being sent is different to that of what you have the UART set to receive it at.
A overrun error normally occurs when your program can't read from the port fast enough. If you don't get an incoming byte out of the register fast enough, and another byte just happens to be received, then the last byte will be lost and a overrun error will result.
Bit 0 shows data ready, which means that a byte has been received by the UART and is at the receiver buffer ready to be read.
Modem Status Register (MSR)
Table 13 : Modem Status Register
Bit 0 of the modem status register shows delta clear to send, delta meaning a change in, thus delta clear to send means that there was a change in the clear to send line, since the last read of this register. This is the same for bits 1 and 3. Bit 1 shows a change in the Data Set Ready line where as Bit 3 shows a change in the Data Carrier Detect line. Bit 2 is the Trailing Edge Ring Indicator which indicates that there was a transformation from low to high state on the Ring Indicator line.
Bits 4 to 7 show the current state of the data lines when read. Bit 7 shows Carrier Detect, Bit 6 shows Ring Indicator, Bit 5 shows Data Set Ready & Bit 4 shows the status of the Clear To Send line.
Scratch Register
The scratch register is not used for communications but rather used as a place to leave a byte of data. The only real use it has is to determine whether the UART is a 8250/8250B or a 8250A/16450 and even that is not very practical today as the 8250/8250B was never designed for AT's and can't hack the bus speed.
Part 3 : Programming (PC's)
Part 4 : Interfacing Devices to RS-232 Ports
- Hardware Properties
Devices which use serial cables for their communication are split into two categories. These are DCE (Data Communications Equipment) and DTE (Data Terminal Equipment.) Data Communications Equipment are devices such as your modem, TA adapter, plotter etc while Data Terminal Equipment is your Computer or Terminal. The electrical specifications of the serial port is contained in the EIA (Electronics Industry Association) RS232C standard. It states many parameters such as -
| 1. | A "Space" (logic 0) will be between +3 and +25 Volts. |
| 2. | A "Mark" (Logic 1) will be between -3 and -25 Volts. |
| 3. | The region between +3 and -3 volts is undefined. |
| 4. | An open circuit voltage should never exceed 25 volts. (In Reference to GND) |
| 5. | A short circuit current should not exceed 500mA. The driver should be able to handle this without damage. (Take note of this one!) |
| Abbreviation | Full Name | Function | ||
| TD | Transmit Data | Serial Data Output (TXD) | ||
| RD | Receive Data | Serial Data Input (RXD) | ||
| CTS | Clear to Send | This line indicates that the Modem is ready to exchange data. | ||
| DCD | Data Carrier Detect | When the modem detects a "Carrier" from the modem at the other end of the phone line, this Line becomes active. | ||
| DSR | Data Set Ready | This tells the UART that the modem is ready to establish a link. | ||
| DTR | Data Terminal Ready | This is the opposite to DSR. This tells the Modem that the UART is ready to link. | ||
| RTS | Request To Send | This line informs the Modem that the UART is ready to exchange data. | ||
| RI | Ring Indicator | Goes active when modem detects a ringing signal from the PSTN. | ||
A Null Modem is used to connect two DTE's together. This is commonly used as a cheap way to network games or to transfer files between computers using Zmodem Protocol, Xmodem Protocol etc. This can also be used with many Microprocessor Development Systems.
Figure 2 : Loopback Plug Wiring Diagram | This loopback plug can come in extremely handy when writing Serial / RS232 Communications Programs. It has the receive and transmit lines connected together, so that anything transmitted out of the Serial Port is immediately received by the same port. If you connect this to a Serial Port an load a Terminal Program, anything you type will be immediately displayed on the screen. This can be used with the examples later in this tutorial. Please note that this is not intended for use with Diagnostic Programs and thus will probably not work. For these programs you require a differently wired Loop Back plug which may vary from program to program. |
We have already talked briefly about DTE & DCE. A typical Data Terminal Device is a computer and a typical Data Communications Device is a Modem. Often people will talk about DTE to DCE or DCE to DCE speeds. DTE to DCE is the speed between your modem and computer, sometimes referred to as your terminal speed. This should run at faster speeds than the DCE to DCE speed. DCE to DCE is the link between modems, sometimes called the line speed. Most people today will have 28.8K or 33.6K modems. Therefore we should expect the DCE to DCE speed to be either 28.8K or 33.6K. Considering the high speed of the modem we should expect the DTE to DCE speed to be about 115,200 BPS.(Maximum Speed of the 16550a UART) This is where some people often fall into a trap. The communications program which they use have settings for DCE to DTE speeds. However they see 9.6 KBPS, 14.4 KBPS etc and think it is your modem speed. Today's Modems should have Data Compression build into them. This is very much like PK-ZIP but the software in your modem compresses and decompresses the data. When set up correctly you can expect compression ratios of 1:4 or even higher. 1 to 4 compression would be typical of a text file. If we were transferring that text file at 28.8K (DCE-DCE), then when the modem compresses it you are actually transferring 115.2 KBPS between computers and thus have a DCE-DTE speed of 115.2 KBPS. Thus this is why the DCE-DTE should be much higher than your modem's connection speed. Some modem manufacturers quote a maximum compression ratio as 1:8. Lets say for example its on a new 33.6 KBPS modem then we may get a maximum 268,800 BPS transfer between modem and UART. If you only have a 16550a which can do 115,200 BPS tops, then you would be missing out on a extra bit of performance. Buying a 16C650 should fix your problem with a maximum transfer rate of 230,400 BPS. However don't abuse your modem if you don't get these rates. These are MAXIMUM compression ratios. In some instances if you try to send a already compressed file, your modem can spend more time trying the compress it, thus you get a transmission speed less than your modem's connection speed. If this occurs try turning off your data compression. This should be fixed on newer modems. Some files compress easier than others thus any file which compresses easier is naturally going to have a higher compression ratio. Flow Control
So if our DTE to DCE speed is several times faster than our DCE to DCE speed the PC can send data to your modem at 115,200 BPS. Sooner or later data is going to get lost as buffers overflow, thus flow control is used. Flow control has two basic varieties, Hardware or Software. Software flow control, sometimes expressed as Xon/Xoff uses two characters Xon and Xoff. Xon is normally indicated by the ASCII 17 character where as the ASCII 19 character is used for Xoff. The modem will only have a small buffer so when the computer fills it up the modem sends a Xoff character to tell the computer to stop sending data. Once the modem has room for more data it then sends a Xon character and the computer sends more data. This type of flow control has the advantage that it doesn't require any more wires as the characters are sent via the TD/RD lines. However on slow links each character requires 10 bits which can slow communications down. Hardware flow control is also known as RTS/CTS flow control. It uses two wires in your serial cable rather than extra characters transmitted in your data lines. Thus hardware flow control will not slow down transmission times like Xon-Xoff does. When the computer wishes to send data it takes active the Request to Send line. If the modem has room for this data, then the modem will reply by taking active the Clear to Send line and the computer starts sending data. If the modem does not have the room then it will not send a Clear to Send. The UART (8250 and Compatibles)
UART stands for Universal Asynchronous Receiver / Transmitter. Its the little box of tricks found on your serial card which plays the little games with your modem or other connected devices. Most cards will have the UART's integrated into other chips which may also control your parallel port, games port, floppy or hard disk drives and are typically surface mount devices. The 8250 series, which includes the 16450, 16550, 16650, & 16750 UARTS are the most commonly found type in your PC. Later we will look at other types which can be used in your homemade devices and projects.
| Notes | ||
| Data Bus | ||
| Receiver Clock Input. The frequency of this input should equal the receivers baud rate * 16 | ||
| Receive Data | ||
| Transmit Data | ||
| Chip Select 0 - Active High | ||
| Chip Select 1 - Active High | ||
| Chip Select 2 - Active Low | ||
| Baud Output - Output from Programmable Baud Rate Generator. Frequency = (Baud Rate x 16) | ||
| External Crystal Input - Used for Baud Rate Generator Oscillator | ||
| External Crystal Output | ||
| Write Line - Inverted | ||
| Write Line - Not Inverted | ||
| Connected to Common Ground | ||
| Read Line - Inverted | ||
| Read Line - Not Inverted | ||
| Driver Disable. This pin goes low when CPU is reading from UART. Can be connected to Bus Transceiver in case of high capacity data bus. | ||
| Transmit Ready | ||
| Address Strobe. Used if signals are not stable during read or write cycle | ||
| Address Bit 2 | ||
| Address Bit 1 | ||
| Address Bit 0 | ||
| Receive Ready | ||
| Interrupt Output | ||
| User Output 2 | ||
| Request to Send | ||
| Data Terminal Ready | ||
| User Output 1 | ||
| Master Reset | ||
| Clear To Send | ||
| Data Set Ready | ||
| Data Carrier Detect | ||
| Ring Indicator | ||
| + 5 Volts |
| 8250 | First UART in this series. It contains no scratch register. The 8250A was an improved version of the 8250 which operates faster on the bus side. |
| 8250A | This UART is faster than the 8250 on the bus side. Looks exactly the same to software than 16450. |
| 8250B | Very similar to that of the 8250 UART. |
| 16450 | Used in AT's (Improved bus speed over 8250's). Operates comfortably at 38.4KBPS. Still quite common today. |
| 16550 | This was the first generation of buffered UART. It has a 16 byte buffer, however it doesn't work and is replaced with the 16550A. |
| 16550A | Is the most common UART use for high speed communications eg 14.4K & 28.8K Modems. They made sure the FIFO buffers worked on this UART. |
| 16650 | Very recent breed of UART. Contains a 32 byte FIFO, Programmable X-On / X-Off characters and supports power management. |
| 16750 | Produced by Texas Instruments. Contains a 64 byte FIFO. |
Part Two : Serial Port's Registers (PC's)
Port Addresses & IRQ's
Above is the standard port addresses. These should work for most P.C's. If you just happen to be lucky enough to own a IBM P/S2 which has a micro-channel bus, then expect a different set of addresses and IRQ's. Just like the LPT ports, the base addresses for the COM ports can be read from the BIOS Data Area.
| COM1's Base Address | |
| COM2's Base Address | |
| COM3's Base Address | |
| COM4's Base Address |
The above table shows the address at which we can find the Communications (COM) ports addresses in the BIOS Data Area. Each address will take up 2 bytes. The following sample program in C, shows how you can read these locations to obtain the addresses of your communications ports.
#include <stdio.h>
#include <dos.h>
void main(void)
{
unsigned int far *ptraddr; /* Pointer to location of Port Addresses */
unsigned int address; /* Address of Port */
int a;
ptraddr=(unsigned int far *)0x00000400;
for (a = 0; a < 4; a++)
{
address = *ptraddr;
if (address == 0)
printf("No port found for COM%d \n",a+1);
else
printf("Address assigned to COM%d is %Xh\n",a+1,address);
*ptraddr++;
}
}
Table of RegistersDLAB ?
You will have noticed in the table of registers that there is a DLAB column. When DLAB is set to '0' or '1' some of the registers change. This is how the UART is able to have 12 registers (including the scratch register) through only 8 port addresses. DLAB stands for Divisor Latch Access Bit. When DLAB is set to '1' via the line control register, two registers become available from which you can set your speed of communications measured in bits per second.
The UART will have a crystal which should oscillate around 1.8432 MHZ. The UART incorporates a divide by 16 counter which simply divides the incoming clock signal by 16. Assuming we had the 1.8432 MHZ clock signal, that would leave us with a maximum, 115,200 hertz signal making the UART capable of transmitting and receiving at 115,200 Bits Per Second (BPS). That would be fine for some of the faster modems and devices which can handle that speed, but others just wouldn't communicate at all. Therefore the UART is fitted with a Programmable Baud Rate Generator which is controlled by two registers.
Lets say for example we only wanted to communicate at 2400 BPS. We worked out that we would have to divide 115,200 by 48 to get a workable 2400 Hertz Clock. The "Divisor", in this case 48, is stored in the two registers controlled by the "Divisor Latch Access Bit". This divisor can be any number which can be stored in 16 bits (ie 0 to 65535). The UART only has a 8 bit data bus, thus this is where the two registers are used. The first register (Base + 0) when DLAB = 1 stores the "Divisor latch low byte" where as the second register (base + 1 when DLAB = 1) stores the "Divisor latch high byte."
Below is a table of some more common speeds and their divisor latch high bytes & low bytes. Note that all the divisors are shown in Hexadecimal.
Interrupt Enable Register (IER)
| Reserved | |
| Reserved | |
| Enables Low Power Mode (16750) | |
| Enables Sleep Mode (16750) | |
| Enable Modem Status Interrupt | |
| Enable Receiver Line Status Interrupt | |
| Enable Transmitter Holding Register Empty Interrupt | |
| Enable Received Data Available Interrupt |
The Interrupt Enable Register could possibly be one of the easiest registers on a UART to understand. Setting Bit 0 high enables the Received Data Available Interrupt which generates an interrupt when the receiving register/FIFO contains data to be read by the CPU.
Bit 1 enables Transmit Holding Register Empty Interrupt. This interrupts the CPU when the transmitter buffer is empty. Bit 2 enables the receiver line status interrupt. The UART will interrupt when the receiver line status changes. Likewise for bit 3 which enables the modem status interrupt. Bits 4 to 7 are the easy ones. They are simply reserved. (If only everything was that easy!)
Interrupt Identification Register (IIR)
| No FIFO | |||
| FIFO Enabled but Unusable | |||
| FIFO Enabled | |||
| 64 Byte Fifo Enabled (16750 only) | |||
| Reserved | |||
| Reserved on 8250, 16450 | |||
| 16550 Time-out Interrupt Pending | |||
| Modem Status Interrupt | |||
| Transmitter Holding Register Empty Interrupt | |||
| Received Data Available Interrupt | |||
| Receiver Line Status Interrupt | |||
| Interrupt Pending | |||
| No Interrupt Pending | |||
The interrupt identification register is a read only register. Bits 6 and 7 give status on the FIFO Buffer. When both bits are '0' no FIFO buffers are active. This should be the only result you will get from a 8250 or 16450. If bit 7 is active but bit 6 is not active then the UART has it's buffers enabled but are unusable. This occurs on the 16550 UART where a bug in the FIFO buffer made the FIFO's unusable. If both bits are '1' then the FIFO buffers are enabled and fully operational.
Bits 4 and 5 are reserved. Bit 3 shows the status of the time-out interrupt on a 16550 or higher.
Lets jump to Bit 0 which shows whether an interrupt has occurred. If an interrupt has occurred it's status will shown by bits 1 and 2. These interrupts work on a priority status. The Line Status Interrupt has the highest Priority, followed by the Data Available Interrupt, then the Transmit Register Empty Interrupt and then the Modem Status Interrupt which has the lowest priority.
First In / First Out Control Register (FCR)
| Interrupt Trigger Level | |||
| 1 Byte | |||
| 4 Bytes | |||
| 8 Bytes | |||
| 14 Bytes | |||
| Enable 64 Byte FIFO (16750 only) | |||
| Reserved | |||
| DMA Mode Select. Change status of RXRDY & TXRDY pins from mode 1 to mode 2. | |||
| Clear Transmit FIFO | |||
| Clear Receive FIFO | |||
| Enable FIFO's | |||
The FIFO register is a write only register. This register is used to control the FIFO (First In / First Out) buffers which are found on 16550's and higher.
Bit 0 enables the operation of the receive and transmit FIFO's. Writing a '0' to this bit will disable the operation of transmit and receive FIFO's, thus you will loose all data stored in these FIFO buffers.
Bit's 1 and 2 control the clearing of the transmit or receive FIFO's. Bit 1 is responsible for the receive buffer while bit 2 is responsible for the transmit buffer. Setting these bits to 1 will only clear the contents of the FIFO and will not affect the shift registers. These two bits are self resetting, thus you don't need to set the bits to '0' when finished.
Bit 3 enables the DMA mode select which is found on 16550 UARTs and higher. More on this later. Bits 4 and 5 are those easy type again, Reserved.
Bits 6 and 7 are used to set the triggering level on the Receive FIFO. For example if bit 7 was set to '1' and bit 6 was set to '0' then the trigger level is set to 8 bytes. When there is 8 bytes of data in the receive FIFO then the Received Data Available interrupt is set. See (IIR)
Line Control Register (LCR)
| Divisor Latch Access Bit | ||||
| Access to Receiver buffer, Transmitter buffer & Interrupt Enable Register | ||||
| Set Break Enable | ||||
| Parity Select | ||||
| No Parity | ||||
| Odd Parity | ||||
| Even Parity | ||||
| High Parity (Sticky) | ||||
| Low Parity (Sticky) | ||||
| Length of Stop Bit | ||||
| One Stop Bit | ||||
| 2 Stop bits for words of length 6,7 or 8 bits or 1.5 Stop Bits for Word lengths of 5 bits. | ||||
| Word Length | ||||
| 5 Bits | ||||
| 6 Bits | ||||
| 7 Bits | ||||
| 8 Bits | ||||
The Line Control register sets the basic parameters for communication. Bit 7 is the Divisor Latch Access Bit or DLAB for short. We have already talked about what it does. (See DLAB?) Bit 6 Sets break enable. When active, the TD line goes into "Spacing" state which causes a break in the receiving UART. Setting this bit to '0' Disables the Break.
Bits 3,4 and 5 select parity. If you study the 3 bits, you will find that bit 3 controls parity. That is, if it is set to '0' then no parity is used, but if it is set to '1' then parity is used. Jumping to bit 5, we can see that it controls sticky parity. Sticky parity is simply when the parity bit is always transmitted and checked as a '1' or '0'. This has very little success in checking for errors as if the first 4 bits contain errors but the sticky parity bit contains the appropriately set bit, then a parity error will not result. Sticky high parity is the use of a '1' for the parity bit, while the opposite, sticky low parity is the use of a '0' for the parity bit.
If bit 5 controls sticky parity, then turning this bit off must produce normal parity provided bit 3 is still set to '1'. Odd parity is when the parity bit is transmitted as a '1' or '0' so that there is a odd number of 1's. Even parity must then be the parity bit produces and even number of 1's. This provides better error checking but still is not perfect, thus CRC-32 is often used for software error correction. If one bit happens to be inverted with even or odd parity set, then a parity error will occur, however if two bits are flipped in such a way that it produces the correct parity bit then an parity error will no occur.
Bit 2 sets the length of the stop bits. Setting this bit to '0' will produce one stop bit, however setting it to '1' will produce either 1.5 or 2 stop bits depending upon the word length. Note that the receiver only checks the first stop bit.
Bits 0 and 1 set the word length. This should be pretty straight forward. A word length of 8 bits is most commonly used today.
Modem Control Register (MCR)
| Reserved | |
| Reserved | |
| Autoflow Control Enabled (16750 only) | |
| LoopBack Mode | |
| Aux Output 2 | |
| Aux Output 1 | |
| Force Request to Send | |
| Force Data Terminal Ready |
The Modem Control Register is a Read/Write Register. Bits 5,6 and 7 are reserved. Bit 4 activates the loopback mode. In Loopback mode the transmitter serial output is placed into marking state. The receiver serial input is disconnected. The transmitter out is looped back to the receiver in. DSR, CTS, RI & DCD are disconnected. DTR, RTS, OUT1 & OUT2 are connected to the modem control inputs. The modem control output pins are then place in an inactive state. In this mode any data which is placed in the transmitter registers for output is received by the receiver circuitry on the same chip and is available at the receiver buffer. This can be used to test the UARTs operation.
Aux Output 2 maybe connected to external circuitry which controls the UART-CPU interrupt process. Aux Output 1 is normally disconnected, but on some cards is used to switch between a 1.8432MHZ crystal to a 4MHZ crystal which is used for MIDI. Bits 0 and 1 simply control their relevant data lines. For example setting bit 1 to '1' makes the request to send line active.
Line Status Register (LSR)
| Error in Received FIFO | |
| Empty Data Holding Registers | |
| Empty Transmitter Holding Register | |
| Break Interrupt | |
| Framing Error | |
| Parity Error | |
| Overrun Error | |
| Data Ready |
The line status register is a read only register. Bit 7 is the error in received FIFO bit. This bit is high when at least one break, parity or framing error has occurred on a byte which is contained in the FIFO.
When bit 6 is set, both the transmitter holding register and the shift register are empty. The UART's holding register holds the next byte of data to be sent in parallel fashion. The shift register is used to convert the byte to serial, so that it can be transmitted over one line. When bit 5 is set, only the transmitter holding register is empty. So what's the difference between the two? When bit 6, the transmitter holding and shift registers are empty, no serial conversions are taking place so there should be no activity on the transmit data line. When bit 5 is set, the transmitter holding register is empty, thus another byte can be sent to the data port, but a serial conversion using the shift register may be taking place.
The break interrupt (Bit 4) occurs when the received data line is held in a logic state '0' (Space) for more than the time it takes to send a full word. That includes the time for the start bit, data bits, parity bits and stop bits.
A framing error (Bit 3) occurs when the last bit is not a stop bit. This may occur due to a timing error. You will most commonly encounter a framing error when using a null modem linking two computers or a protocol analyzer when the speed at which the data is being sent is different to that of what you have the UART set to receive it at.
A overrun error normally occurs when your program can't read from the port fast enough. If you don't get an incoming byte out of the register fast enough, and another byte just happens to be received, then the last byte will be lost and a overrun error will result.
Bit 0 shows data ready, which means that a byte has been received by the UART and is at the receiver buffer ready to be read.
Modem Status Register (MSR)
| Carrier Detect | |
| Ring Indicator | |
| Data Set Ready | |
| Clear To Send | |
| Delta Data Carrier Detect | |
| Trailing Edge Ring Indicator | |
| Delta Data Set Ready | |
| Delta Clear to Send |
Bit 0 of the modem status register shows delta clear to send, delta meaning a change in, thus delta clear to send means that there was a change in the clear to send line, since the last read of this register. This is the same for bits 1 and 3. Bit 1 shows a change in the Data Set Ready line where as Bit 3 shows a change in the Data Carrier Detect line. Bit 2 is the Trailing Edge Ring Indicator which indicates that there was a transformation from low to high state on the Ring Indicator line.
Bits 4 to 7 show the current state of the data lines when read. Bit 7 shows Carrier Detect, Bit 6 shows Ring Indicator, Bit 5 shows Data Set Ready & Bit 4 shows the status of the Clear To Send line.
Scratch Register
The scratch register is not used for communications but rather used as a place to leave a byte of data. The only real use it has is to determine whether the UART is a 8250/8250B or a 8250A/16450 and even that is not very practical today as the 8250/8250B was never designed for AT's and can't hack the bus speed.
Part 3 : Programming (PC's)
- Polling or Interrupt Driven?
When writing a communications program you have two methods available to you. You can poll the UART, to see if any new data is available or you can set up an interrupt handler to remove the data from the UART when it generates a interrupt. Polling the UART is a lot slower method, which is very CPU intensive thus can only have a maximum speed of around 34.8 KBPS before you start losing data. Some newer Pentium Pro's may be able to achieve better rates that this. The other option is using a Interrupt handler, and that's what we have used here. It will very easily support 115.2K BPS, even on low end computers.
| Note: | The source code above is not a really good example on how to program but is rather cut down to size giving quick results, and making it easier to understand. Upon executing your communications program, it would be wise to store the status of the UART registers, so that they all can be restored before you quit the program. This is to cause the least upset to other programs which may also be trying to use the communications ports. |
Once we know the IRQ the next step is to find it's interrupt vector or software interrupt as some people may call it. Basically any 8086 processor has a set of 256 interrupt vectors numbered 0 to 255. Each of these vectors contains a 4 byte code which is an address of the Interrupt Service Routine (ISR). Fortunately C being a high level language, takes care of the addresses for us. All we have to know is the actual interrupt vector.
| Common Uses | ||
| System Timer | ||
| Keyboard | ||
| Redirected | ||
| Serial Comms. COM2/COM4 | ||
| Serial Comms. COM1/COM3 | ||
| Reserved/Sound Card | ||
| Floppy Disk Controller | ||
| Parallel Comms. | ||
| Real Time Clock | ||
| Reserved | ||
| Reserved | ||
| Reserved | ||
| PS/2 Mouse | ||
| Maths Co-Processor | ||
| Hard Disk Drive | ||
| Reserved |
Now, could we be off track just a little? Yes that's right, PORT1INT is the label to our interrupt handler called a Interrupt Service Routine (ISR). You can put just about anything in here you want. However calling some DOS routines can be a problem.
void interrupt PORT1INT()
{
int c;
do { c = inportb(PORT1 + 5);
if (c & 1) {
buffer[bufferin] = inportb(PORT1);
bufferin++;
if (bufferin == 1024) bufferin = 0;
}
} while (c & 1);
outportb(0x20,0x20);
}
From the example above we check to see if there is a character to receive and if their is we remove it from the UART and place it in a buffer contained in memory. We keep on checking the UART, in case FIFO's are enabled, so we can get all data available at the time of interrupt.
The last line contains the instruction outportb(0x20,0x20); which tells the Programmable Interrupt Controller that the interrupt has finished. The Programmable Interrupt Controller (PIC) is what we must go into now. All of the routines above, we have assumed that everything is set up ready to go. That is all the UART's registers are set correctly and that the Programmable Interrupt Controller is set.
The Programmable Interrupt Controller handles hardware interrupts. Most PC's will have two of them located at different addresses. One handles IRQ's 0 to 7 and the other IRQ's 8 to 15. Mainly Serial communications interrupts reside on IRQ's under 7, thus PIC1 is used, which is located at 0020 Hex.
| Parallel Port | ||
| Floppy Disk Controller | ||
| Reserved/Sound Card | ||
| Serial Port | ||
| Serial Port | ||
| PIC2 | ||
| Keyboard | ||
| System Timer |
| Reserved | ||
| Hard Disk Drive | ||
| Maths Co-Processor | ||
| PS/2 Mouse | ||
| Reserved | ||
| Reserved | ||
| IRQ2 | ||
| Real Time Clock |
Now we get to the UART settings (Finally) It's a good idea to turn off the interrupt generation on the UART as the first instruction. Therefore your initialization can't get interrupted by the UART. I've then chosen to set up our interrupt vectors at this point. The next step is to set the speed at which you wish to communicate at. If you remember the process, we have to set bit 7 (The DLAB) of the LCR so we can access the Divisor Latch High and Low Bytes. We have decided to set the speed to 38,400 Bits per second which should be find for 16450's and 16550's. This requires a divisor of 3, thus our divisor latch high byte will be 0x00 and a divisor latch low byte, 0x03. In today's standards the divisor low latch byte is rarely used but it still pays us to write 0x00 to the register just in case the program before us just happened to set the UART at a very very low speed. BIOS will normally set UARTs at 2400 BPS when the computer is first booted up which still doesn't require the Divisor Latch Low byte. The next step would be to turn off the Divisor latch access bit so we can get to the Interrupt Enable Register and the receiver/transmitter buffers. What we could do is just write a 0x00 to the register clearing it all, but considering we have to set up our word length, parity as so forth in the line control register we can do this at the same time. We have decided to set up 8 bits, no parity and 1 stop bit which is normally used today. Therefore we write 0x03 to the line control register which will also turn off the DLAB for us saving one more I/O instruction. The next line of code turns on the FIFO buffers. We have made the trigger level at 14 bytes, thus bits 6 and 7 are on. We have also enabled the FIFO's (bit 0). It's also good practice to clear out the FIFO buffers on initialization. This will remove any rubbish which the last program may of left in the FIFO buffers. Due to the fact that these two bits are self resetting, we don't have to go any further and turn off these bits. If my arithmetic is correct all these bits add up to 0xC7 or 199 for those people which still work in decimal. Then DTR, RTS and OUT 2 is taken active by the instruction outportb(PORT1 + 4,0x0B);. Some cards (Both of Mine) require OUT2 active for interrupt requests thus I'm normally always take it high. All that is left now is to set up our interrupts which has be deliberately left to last as to not interrupt our initialization. Our interrupt handler is only interested in new data being available so we have only set the UART to interrupt when data is received. Main Routine (Loop)
Now we are left with,
do {
if (bufferin != bufferout){
ch = buffer[bufferout];
bufferout++;
if (bufferout == 1024) bufferout = 0;
printf("%c",ch);
}
if (kbhit()){
c = getch();
outportb(PORT1, c);
}
} while (c !=27);
which keeps repeating until c = 27. This occurs when the ESC key is hit.
The next if statement checks to see if a key has been hit. (kbhit()) If so, it gets the character using the getch() statement and outputs it to the receiver buffer. The UART then transmits the character to the modem. What we have assumed here, is that the person using the Communications Program can't type as fast as the UART can send. However if the program wishes to send something, then a check should be made to see if BIT 5 of the Line Status Register is set before attempting to send a byte to the transmitter register.
The type of UART you have installed in your system can be determined without even needing a screwdriver in most cases. As you can see from Types of UART's each UART has minor differences, all we have to do it test these. The first procedure we do is to set bit 0 to '1' in the FIFO control register. This tries to enable the FIFO buffers. Then we read bits 6 and 7 from the interrupt identification register. If both bits are '1' then the FIFO buffers are enabled. This would mean the UART is a 16550a. If the FIFO's were enabled but not usable then it would be a 16550. If there is no FIFO buffer enabled it is most likely to be a 16450 UART, but could be a 8250, 8250A or 8250B on very old systems. AT's have a fast bus speed which the 8250 series of UART can't handle to well thus it is very unlikely to be found in any AT. However if you wish to test for them as well you can follow the same test as above to distinguish 16550's or 16550A's from the rest. If no FIFOs are enabled then a possible UART is the 16450, 8250, 8250A or 8250B. Once it is established the it could be one of these four chips, try writing a byte to the scratch register and then read it back and compare the results. If the results match then you must have a scratch register, if they don't you either don't have a scratch register, or it doesn't work to well. From the descriptions of the UART above if you read back your byte from the scratch register then the UART must be a 16450 or 8250A. (Both have scratch registers) If you don't read back your byte then it's either a 8250 or 8250B. The 16750 has 64 byte FIFO's, thus the easiest way to test for it's presence is to enable the 64 byte buffer using the FIFO Control Register and then read back the status of the Interrupt Identification Register. However I have never tested this.
Part 4 : Interfacing Devices to RS-232 Ports
- RS-232 Waveforms
So far we have introduced RS-232 Communications in relation to the PC. RS-232 communication is asynchronous. That is a clock signal is not sent with the data. Each word is synchronized using it's start bit, and an internal clock on each side, keeps tabs on the timing.
Almost all digital devices which we use require either TTL or CMOS logic levels. Therefore the first step to connecting a device to the RS-232 port is to transform the RS-232 levels back into 0 and 5 Volts. As we have already covered, this is done by RS-232 Level Converters. Two common RS-232 Level Converters are the 1488 RS-232 Driver and the 1489 RS-232 Receiver. Each package contains 4 inverters of the one type, either Drivers or Receivers. The driver requires two supply rails, +7.5 to +15v and -7.5 to -15v. As you could imagine this may pose a problem in many instances where only a single supply of +5V is present. However the advantages of these I.C's are they are cheap.
RS-232 Driver/Receiver. Right: (Figure 7) Typical MAX-232 Circuit. |
In order to do anything useful with our Serially transmitted data, we must convert it back to Parallel. (You could connect an LED to the serial port and watch it flash if you really want too, but it's not extremely useful). This in the past has been done with the use of UART's. However with the popularity of cheap Microcontroller's, these can be more suited to many applications. We will look into the advantages and disadvantages of each method. 8250 and Compatible UARTs
We have already looked at one type of UART, the 8250 and compatibles found in your PC. These devices have configuration registers accessible via the data and address buses which have to be initialized before use. This is not a problem if your device which you are building uses a Microprocessor. However if you are making a stand alone device, how are you going to initialize it? Most Microprocessors / Microcontrollers these days can be brought with build-in Serial Communication Interfaces (SCI). Therefore there is little need to connect a 40 pin 16550 to, for example a 68HC11 when you can buy one built in. If you are still in love with the Z-80 or 8086 then an 16550 may be option! (or if you are like myself, the higher chip count the better. After all it looks more complicated and impressive! - But a headache to debug!)
| Notes | ||
| Data Bus | ||
| Receiver Clock Input. The frequency of this input should equal the receivers baud rate x 16 | ||
| Receive Data | ||
| Transmit Data | ||
| Chip Select 0 - Active High | ||
| Chip Select 1 - Active High | ||
| Chip Select 2 - Active Low | ||
| Baud Output - Output from Programmable Baud Rate Generator. Frequency = (Baud Rate x 16) | ||
| External Crystal Input - Used for Baud Rate Generator Oscillator | ||
| External Crystal Output | ||
| Write Line - Inverted | ||
| Write Line - Not Inverted | ||
| Connected to Common Ground | ||
| Read Line - Inverted | ||
| Read Line - Not Inverted | ||
| Driver Disable. This pin goes low when CPU is reading from UART. Can be connected to Bus Transceiver in case of high capacity data bus. | ||
| Transmit Ready | ||
| Address Strobe. Used if signals are not stable during read or write cycle | ||
| Address Bit 2 | ||
| Address Bit 1 | ||
| Address Bit 0 | ||
| Receive Ready | ||
| Interrupt Output | ||
| User Output 2 | ||
| Request to Send | ||
| Data Terminal Ready | ||
| User Output 1 | ||
| Master Reset | ||
| Clear To Send | ||
| Data Set Ready | ||
| Data Carrier Detect | ||
| Ring Indicator | ||
| + 5 Volts |
Figure 9 : Pinout of CDP6402 | There are UARTs such as the CDP6402, AY-5-1015 / D36402R-9 and compatibles. These differ from the 8250 and compatibles, by the fact that they have separate Receive and Transmit data buses and can be configured by connecting certain pins to various logic levels. These are ideal for applications where you don't have a Microprocessor available. Such an example is if you want to connect a ADC0804 (Analog to Digital Converter) to the UART, or want to connect a LCD Display to the Serial Line. These common devices use a 8 bit parallel data bus. The CDP6402's Control Register is made up of Parity Inhibit (PI), Stop Bit Select (SBS), Character Length Select (CLS1 and 2) and Even Parity Enable (EPE). These inputs can be latched using the Control Register Load (CRL) or if you tie this pin high, changes made to these pins will immediately take effect. |
| Pin Number | Abbr. | Full Name | Notes |
| + 5v Supply Rail | |||
| Not Connected | |||
| Ground | |||
| Receiver Register Disable | When driven high, outputs RBR8:RBR1 are High Impedance. | ||
RBR1 | Receiver Buffer Register | Receiver's Data Bus | |
| Parity Error | When High, A Parity Error Has Occurred. | ||
| Framing Error | When High, A Framing Error Has Occurred. i.e. The Stop Bit was not a Logic 1. | ||
| Overrun Error | When High, Data has been received but the nData Received Reset had not yet been activated. | ||
| Status Flag Disable | When High, Status Flag Outputs (PE, FE, OE, DR and TBRE) are High Impedance | ||
| Receiver Register Clock | x16 Clock input for the Receiver Register. | ||
| Data Received Reset | Active Low. When low, sets Data received Output Low (i.e. Clears DR) | ||
| Data Received | When High, Data has been received and placed on outputs RBR8:RBR1. | ||
| Receiver Register In | RXD - Serial Input. Connect to Serial Port, Via RS-232 receiver. | ||
| Master Reset | Resets the UART. UART should be reset after applying power. | ||
| Transmitter Buffer Register Empty | When High, indicates that Transmitter Buffer Register is Empty, thus all bits including the stop bit have been sent. | ||
| Transmitter Buffer Load / Strobe | Active Low. When low, data present on TBR8:TBR1 is placed in Transmitter Buffer Register. A Low to High Transition on this pin, then sends the data. | ||
| Transmitter Register Empty | When High, Transmitter Register is Empty, thus can accept another byte of data to be sent. | ||
| Transmitter Register Out (TXD) | TXD - Serial Output. Connect to Serial Port, Via RS-232 Transmitter. | ||
TBR1 | Transmitter Buffer Register | Data Bus, for Transmitter. Place Data here which you want to send. | |
| Control Register Load | When High, Control Register (PI, SBS, CLS2, CLS1, EPE) is Loaded. Can be tied high, so changes on these pins occur instantaneously. | ||
| Parity Inhibit | When High, No Parity is Used for Both Transmit and Receive. When Low, Parity is Used. | ||
| Stop Bit Select | A High selects 2 stop bits. (1.5 for 5 Character Word Lengths) A Low selects one stop bit. | ||
CLS1 | Character Length Select | Selects Word Length. 00 = 5 Bits, 01 = 6 Bits, 10 = 7 Bits and 11 = 8 Bits. | |
| Even Parity Enable | When High, Even Parity is Used, When Low, Odd Parity is Used. | ||
| Transmitter Register Clock | 16x Clock input for Transmitter. |
Figure 10 : Baud Rate Generator using a 74HC4060 |
It is also possible to use microcontrollers to transmit and receive Serial data. As we have already covered, some of these MCU's (Micro Controller Units) have built in UART's among other things. Take the application we have used above. We want to monitor analog voltages using a ADC and then send them serially to the PC. If the Microcontroller also has a ADC built in along with the UART or SCI, then we could simply program the device and connect a RS-232 Line Driver. This would minimize your chip count and make your PCB much smaller. Take the second example, displaying the serial data to a common 16 character x 2 line LCD display. A common problem with the LCD modules, is they don't accept cartridge returns, line-feeds, form-feeds etc. By using a microcontroller, not only can you emulate the UART, but you can also program it to clear the screen, should a form-feed be sent or advance to the next line should a Line-feed be sent. The LCD example also required some additional logic (An Inverter) to reset the data receive line on the UART, and provide a -ve edge on the enable of the LCD to display the data present on the pins. This can all be done using the Microcontroller and thus reducing the chip count and the cost of the project. Talking of chip count, most Microcontrollers have internal oscillators thus you don't require the 74HC4060 14 Bit Binary Counter and Oscillator. Many Microcontrollers such as the 68HC05J1A and PIC16C84 have a smaller pin count, than the 40 Pin UART. This not only makes the project smaller in size, it reduces complexity of the PCB. But there are also many disadvantages of the Microcontroller. The major one, is that you have to program it. For the hobbyist, you may not have a development system for a Microcontroller or a method of programming it. Then you have to learn the micro's code and work out how to tackle the problem. At least with the UART, all you did was plug it in, wire it up and it worked. You can't get much simpler that that. So far we have only discussed Full Duplex Transmission, that is that we can transmit and receive at the same time. If our Microcontroller doesn't have a SCI then we can Emulate a RS-232 port using a Parallel line under software control. However Emulation has it's dis-advantages. It only supports slow transmission speeds, commonly 2400, 9600 or maybe even 19,200 BPS if you are lucky. The other disadvantage is that it's really only effective in half duplex mode. That is, it can only communicate in one direction at any one given time. However in many applications this is not a problem. As there are many different types of Micro-Controllers all with their different instruction sets, it is very hard to give examples here which will suit everyone. Just be aware that you can use them for serial communications and hopefully at a later date, I can give a limited number of examples with one micro.
No comments:
Post a Comment
Leave your comment here