Serial Ports

From OSDev.wiki
Revision as of 20:04, 16 December 2006 by osdev>Jhawthorn
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Introduction

Serial ports are a legacy communications port which has pretty much been succeeded by USB and other modern communications technology. However, it is much easier to program than USB, and it is still found in a lot of computers (especially older ones such as the ones the broke amateur OS writer/tester might use). Also, a lot of phone modems (which are still used to access the internet quite often, even though broadband is very accessable and affordable) connect via the serial interface. So for completeness, it is covered here. Wires, Pins, Connectors and the like

The serial interface is very simple. There are actually two kinds of serial port: 25-pin and 9-pin. 25-pin ports are not any better, they just have more pins and are bigger. 9-pin is smaller and is used more often though in the past the 25-pin ones were used more often. The 9-pin ones are called DE-9 (or more commonly, DB-9 even though DE-9 is it's technical name) and the 25-pin ones are called DB-25. They plug in to your computer using a female plug (unless your computer is odd and has a female port, in which case your cable will need a male plug).

Both have the same basic types of pins. Most of the pins are not used. Most of the pins are ground pins. There is a transmitting pin (for sending information away) and a receiving pin (for getting information). Some serial ports can have a duplex mode--that is, they can send and receive simultaneously. There are a few other pins, used for hardware handshaking. In the past, there was no duplex mode, so if a computer wanted to send something it had to tell the other device or computer that it was about to transmit, using one of the hardware handshaking pins. The other thing would then use another handshaking pin to tell it to send whatever it wanted to send. Today there is duplex mode, but the handshaking pins are still used.

If you want to connect two computers, you need two things in your cable:

  1. The cable needs to have two female plugs so it can plug into both computers.
  2. The cable needs to have it's transmit-receive wires and it's handshaking wires switched. Otherwise the computers can't communicate.

When you setup a cable in this way, it is called a Null Modem.

For serial devices, you don't need to setup the cable this way. The receiving end of the device has the wires switched and it has a female port, which means you can plug a male plug into it.

Programming the Serial Communications Port

If you want to use the serial port for communications, you first have to initialize it. You tell it how fast your connection speed between the other computer or device will be (this is called the baud rate)--you must have the same speed as the other device or computer is setup to use, or you will have problems. It is probably safer to use the slower speeds unless you need the faster speeds for some reason, for example if you are playing a multi-player game over a serial connection. You also need to setup the parity type and the number of bits in a character. Once again, your computer must be setup with the same values for these things as the other computer or device has, or communication will not work.

Once you have setup these things, you still need to setup the interrupt handlers. You can poll the port to see if any new things have arrived, or if it's time to send another character, but this slows things down and will not work very well in most real-time applications or multithreaded environments. In the case of a game, this is not a good idea at all.

You use IRQ #4 for COM ports 1 or 3, and IRQ #3 for COM ports 2 or 4 (you can tell which port sent the interrupt when you receive the interrupt). The IRQ handlers check if you are receiving something, and if so they receive the character and handle it somehow, such as placing it into a buffer. They also check if the other side is ready to receive something from you, and if you have something to send, it is sent.

Examples on how to do these things are below. Of course, you will need to setup the IRQ handlers, and some other miscellaneous things. However, most of the information you need in order to do these things is given below, or elsewhere in the OSFAQ Wiki. Hopefully you can figure out the rest from here on.

You will find extra information on OSRC's "communication" section http://www.nondot.org/sabre/os/articles/CommunicationDevices/

Initialization

The baud rate is set by writing a divisor value to the UART. The divisor is the fraction of 115200 that makes the baud rate. For instance, the baud rate 57600 would have a divisor of 2.

The number of bits in a character is variable. Less bits is, of course, faster, but they store less information. If you are only sending ASCII text, you probably only need 7 bits.

The parity type can be even, odd, or none.

#define PORT 0x3f8   /* COM1 */

void init_serial() {
   outb(PORT + 1, 0x00);    // Disable all interrupts
   outb(PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
   outb(PORT + 0, 0x03);    // Set divisor to 3 (lo byte) 38400 baud
   outb(PORT + 1, 0x00);    //                  (hi byte)
   outb(PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
   outb(PORT + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
   outb(PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
}

Receiving data

int serial_recieved() {
   return inb(PORT + 5) & 1;
}

char read_serial() {

   while (serial_recieved() == 0) {
      continue;
   }

   return inb(PORT);
}

Sending data

int is_transmit_empty() {
   return inb(PORT + 5) & 0x20;
}

void write_serial(char a) {

   while (is_transmit_empty() == 0) {
      continue;
   }

   outb(PORT,a);

}

Glossary

baud rate
the 'speed' at which transmission occurs, in characters per second
I'm not SerialPorts guru, but bauds is usually symbols per second on the wire, and afaik, each symbol on a RS-232 line will only carry 1 bit, so the baud rate (here) is more likely to be the bitrate than the byte-per-second speed ... note however than modems typically send many bits per baud (because you may have more than 2 waveforms used), but not necessarily 8 of them ... Someone should check the specs and confirm/correct. -- PypeClicker
baud rate divisor
the number 115200
stop bits
the NULL bit(s) sent between each character to synchronize the transmitter and the receiver
UART
for Universal Asynchronous Receiver/Transceiver: the chip that picks a byte a send it bit per bit on the serial line and vice versa.