Serial Communications Port

Address: $1008 (Port D)

Theory

How do we communicate data between computers, or between peripherals and the CPU? We've already talked about one way to communicate data: using a bus. The thing is, a bus is expensive (it needs a wire for every bit, plus wires for control information). It turns out that we can trade some money for speed, and cram all the bits down a single wire. This is the idea behind serial communication.

Parallel-serial conversion

Let's suppose we have some data we want to pass down the line. To do this, we need a ``shift register'' at each end. A shift register is a register that we can shift data through, one bit at a time, bringing data in one end and putting it out the other. Normally, you can also read or write all of the bits of a shift register at the same time. So the idea is that we can put a whole byte into the shift register all at once, and then ship it down the wire one bit at a time.

To use shift registers in serial communication, we need two of them. At the transmitter end, we need to be able to load up all the data bits in parallel, and then shift them out one bit at a time. At the receiver end, we need to be able to shift the data in one bit at a time, and then read the whole eight bits at once.

Bits per Second and Baud Rate

Now, we start to get into the details. First, how long (in time) is a bit? If the transmitter and the receiver don't agree, the receiver will get the wrong data. There are a bunch of standard bit-per-second speeds that are used; these are all multiples of 300 bps for historical reasons (note -- the new 56K modems seem to be an exception to this). Also for historical reasons, we frequently say baud (named after Baudot) when we mean bps. It turns out that these don't mean quite the same thing -- baud means the actual number of voltage transitions possible; modems use some pretty fancy signal processing techniques to encode more bits/second than the actual baud rate. Next question: how many bits are in a character? The original baudot code was a five bit code (I have no idea how they got the whole alphabet plus numbers in there!); for a very long time we normally saw a seven bit character; today we normally see an eight bit character.

The next problem is making sure the data is sent correctly. There are two subproblems here: getting it to work at all, and getting it to work in the presence of noise.

Start Bit

The transmitter is not going to send data continuously. You've seen this in doing downloads, and in running hexmon: there's normally more time spent between sending characters, than actually sending them. When you're not sending data, the line is held at a steady value of ``1.'' So, how do you tell when a data character is coming? Suppose we see a binary sequence 11111111000011111. If we're using a seven-bit ASCII character, this could be 1110000 (`p'), 1100001 (`a'), 1000011 (`C'), 0000111 (BEL), 1111110 0001111 (`~/', 1111100 0011111 (`|US') or 1111000 0111111 (`x?'). How can we tell the difference?

What we'll do is put a 0 bit in front of every character, to tell it that a character is coming (the 0 isn't be part of the data, it's in front of the data). We call this a ``start bit;'' it marks the start of a data character.

Stop Bit(s)

Now, suppose we get some noise on the line. We can end up thinking a data bit is the start bit, and read a character of nonsense. There are a couple of things we can do about this. The first one is to use a stop bit: we follow each data character with some number of 1's. This means the receiver does the following to try to read a character:
  1. Wait until it sees a 0.
  2. Read the bits following the 0.
  3. Make sure the character is followed by the right number of 1's. If it isn't, we had an error.

Parity

Notice that this will miss a lot of errors, especially if there's a lot of time between characters. If the noise ended halfway through a character, we'll see everything after the next 0 in the character as data, and then see the 1's that go between characters as more data. We can do a little better than this by adding another bit, called a parity bit. On the transmitter end, we'll take a look at a character to be sent and ask, ``are there an even or an odd number of 1's in this character?'' Then, we'll inject an extra bit after the character (but before the stop bit) to force the number of 1's to be either even or odd (our choice). So if we're going to send out ``odd parity,'' we make sure that the character+parity bit always contains an odd number of 1's. If we're going to send out even parity, we'll make sure it's even. There are five parity functions:
  1. No parity. Don't send out a parity bit at all.
  2. 0 parity. Make the parity bit always 0.
  3. 1 parity. Make the parity bit always 1.
  4. Even parity. Use the parity bit to make sure the parity of the character+bit is even.
  5. Odd parity. Use the parity bit to make sure the parity of the character+bit is odd.

Networks

This idea of putting extra ``stuff'' around the data you're actually interested in is called putting the data in a frame, and is a very standard technique in networking.

Real Life

At one time, the capabilities described for serial ports were all needed to make sure data was not lost. People tended to work at dumb computer terminals, which communicated over relatively long distances to central computers. Where I went to school, they even economized by using only two wires to connect the terminals to the department's computer: one wire for data in each direction. They relied on the building ground to provide a signal ground!

For most networking, the frame is quite a bit more complicated than this, because additional routing information is also required. A data packet is typically sent out with information that encodes things like what computer the packet started at, what computer it is supposed to go to, what process on the destination computer it is intended for, and so forth. We already know all this stuff in our application, so we can just send a bunch of bytes.

Practice

HC11 Serial Capabilities

The HC11 is capable of sending and receiving data at a wide variety of speeds from 75 to 125,000 bps (with the clock rate we're using). It supports one start bit, one stop bit, and eight or nine data bits. It can deliver interrupts on a variety of conditions.

A very nice feature of the SCI is that it provides some limited buffering, which makes it easier for you to keep the transmitter line full at all times, and gives you some latitude in receiving.

Configuring the port requires setting the speed, defining the character format, and enabling interrupts on desired conditions. Looking at these in turn:

BAUD register

The BAUD register (at $102b) determines the speed the SCI is running. The SCP1-0 and SCR2-0 bits select the rate (in conjunction with the system clock speed). The other bits in the baud register are not used.

SCCR1 and SCCR2

The only important bit in SCCR1 ($102c) is the M bit, which selects 8 or 9 bit mode. The other bits are used when the serial port is being used to implement a network, with a single wire connecting a bunch of ports on a serial bus.

SCCR2 ($102d) is used to enable and disable virtually the whole subsystem... transmitter, receiver, interrupts, etc. etc.

SCSR

The SCI Status Register ($102e) is used to report the current state of the serial interface. This includes both data presence/absence and error conditions.

SCDR

The SCI Data Register ($102f) is used to send/receive data. It is actually two registers, which share a single address. When you write to the register, you write to the transmiter UART. When you read from it, you read from the receiver UART.