Skip to content

A serial port

A computer that can only light LEDs and read buttons can’t say much. A serial port lets it talk to another computer, a byte at a time, over a single wire each way: the computer’s keyboard and screen become its terminal. It’s the oldest way computers have of talking, from teleprinters onwards, and still the first thing most small boards bring up. The circuit that does it is a UART (a universal asynchronous receiver-transmitter), and the same one, at a different speed, carries MIDI on the next page.

Inside the computer, a byte moves along eight wires at once, with a clock saying when to look. Between two boards that’s a lot of wires, and a clock wire has its own troubles over a long cable. So a serial line sends the bits one after another, down a single wire, and sends no clock at all: each end has its own, and they agree beforehand how fast the bits come. That’s what asynchronous means: not sharing a clock.

The line rests at 1. To send a byte:

  • a start bit, 0: the line falls, and the receiver knows a byte is coming, and when it began;
  • the eight bits, lowest first;
  • a stop bit, 1: the line goes back to rest for at least a bit’s time, so the next start bit has an edge to fall from.

A byte on a serial line: type a character to see its byte (in ASCII, the code computers use for text). The line rests high, falls for the start bit, then carries the eight bits, lowest first, and the stop bit. The marks are where a receiver samples each bit: in its middle. Ten bits carry eight, so a line of 115,200 baud (bits a second) moves at most 11,520 bytes a second.

The speed is in baud, bits a second. The usual speeds come from the history of teleprinters and modems: 9,600, then doubling up to 115,200 and beyond. Both ends must be set to the same one.

The UART counts its own clock to time each bit. At 115,200 baud a bit lasts 8.68 µs: 104.17 clocks of the UPduino’s 12 MHz. A counter can only count whole clocks, so it counts 104, and its bits are 0.16% short. That’s fine, as the next section shows: a few per cent either way works.

But not every clock divides so well:

For each usual speed: how many clocks a bit would take, the whole number the UART counts instead, and how far off that leaves the speed. With the UPduino’s 12 MHz, every speed is within 0.16%. With the 6502’s own 1 MHz, 115,200 baud would be 9 clocks a bit, 3.55% slow, and the faster ones hopeless. The odd-looking 1.8432 MHz crystal, standard in old PCs’ serial ports, divides into all of them exactly.

That’s why the serial port runs on the board’s 12 MHz clock, not on the CPU’s 1 MHz, and why 1.8432 MHz crystals existed: 1.8432 MHz is 16 × 115,200, and 115,200 divides by 2 and 3 down to every other speed.

The receiver watches the line. When it falls, a start bit has begun, perhaps. The receiver waits half a bit and looks again: if the line is still low it really was a start bit, not a glitch, and now the receiver is in the middle of it. From there it looks every whole bit: each look lands in the middle of a bit, where the line is steadiest, far from the edges where it changes.

Each byte begins with a fresh start bit, so the receiver lines itself up again at every byte. Its clock only has to stay close to the sender’s for ten bits. How close?

A receiver sampling a byte from a sender whose clock is fast (or slow) by the amount on the slider. The receiver counts its own bit times from the start bit’s edge, so its samples drift a little further from the middles with every bit. The last, the stop bit’s, drifts furthest: 9.5 bits in. Past ±5.3% it lands in the next bit over (or the one before), and the byte is wrong.

The stop bit’s sample is 9.5 bits after the edge, so it stays inside its bit while 9.5 × the difference is less than half a bit: a difference under 5.3% between the two clocks, in all. In practice less, since the edges aren’t perfectly sharp and the receiver only notices the start bit’s edge at its next clock: real systems aim for under 2% or so. The UPduino’s 0.16% leaves plenty to spare.

The receiver also checks the stop bit: if the line isn’t high there, the byte didn’t end properly (a framing error: the speeds don’t match, or something interfered), and the port sets a flag to say so.

Sending is the simpler half: a counter to time the bits, a shift register to put them out lowest first, and a count of which bit it’s on. This is uart.v’s sender, cut down to 4 clocks a bit so you can step through a whole byte:

A serial sender, simulated gate by gate. Set data (65 is the letter A), set send to 1 for one clock, then back to 0, and keep clocking: tx falls for the start bit, then gives data’s bits lowest first, 4 clocks each, then rises for the stop bit. bitno counts through the ten bits; busy is high until it’s done.

The CPU and the serial line run at very different speeds. At 115,200 baud a byte takes 87 µs, a few dozen of the 6502’s instructions; a program writing a line of text would spend most of its time waiting for each byte to go. And bytes arriving don’t wait for the program: if it’s busy when one comes, and another comes after it, the first is overwritten and lost.

So uart.v has two queues (FIFOs: first in, first out) of 32 bytes each, in block RAM. A byte written to DATA joins the back of the send queue, and the sender takes them from the front as fast as the line allows; the program can write 32 at once and get on with something else. Bytes received join the back of the receive queue, and reading DATA takes the one at the front. At 115,200 baud the receive queue holds 2.8 ms of bytes arriving back to back: the program has that long to come and collect them. If it doesn’t, the 33rd byte has nowhere to go and is lost, and the port says so with an overrun flag.

A queue in a memory is two counters: where the next byte goes in, and where the next one comes out. When they’re equal the queue is empty. When the writer has gone a whole lap ahead it’s full, and the positions are equal again, so each counter has one bit more than the address needs: equal in every bit, empty; equal except the top bit, full.

AddressRegister
$8030DATAwrite: send this byte (it joins the queue). Read: take the next byte received
$8031STATUSbit 0: a byte is waiting; bit 1: room to send; bit 2: everything sent; bit 6: framing error; bit 7: overrun (write anything: clear bits 6 and 7)
$8032CTRLbit 0: interrupt while a byte is waiting; bit 1: interrupt while there’s room to send
$8033–$8034DIVclocks a bit (low byte, high byte): 12,000,000 / baud; 104 after reset, for 115,200

The computer with the serial port at $8030, connected to a terminal: click the terminal and type. Hello sends a line. Echo, in capitals sends back what you type, in capitals (ASCII puts each capital 32 below its small letter, so clearing bit 5 makes it). Echo by interrupts does the same from an interrupt handler while the main program runs a light along the LEDs: each byte that arrives interrupts it for a moment, and nothing is lost, however fast you type.

One detail in that table matters on the 6502: reading DATA takes a byte, so a read is not harmless. The 6502 sometimes reads an address it doesn’t need, in a “dummy” cycle (indexed instructions crossing a page, for one; see The CPU), and a dummy read of DATA would lose a byte. Real 6502 computers had the same problem with their serial chips; the cure is to read DATA only with instructions that read it once, such as LDA $8030.

The FPGA’s serial port needs a partner on the other end: a computer, through a USB-serial adapter, a small chip that appears to the computer as a serial port and turns its bytes into a UART’s bits and back. The UPduino already has one, the same chip that loads the FPGA’s bitstream, and the carrier board has a header for an adapter cable as well. On the computer, a terminal program (any of the many free ones) set to 115,200 baud, 8 data bits, no parity, 1 stop bit, the usual “8N1”, is the other end.

The port costs 341 logic cells and two block RAMs for the queues: a lot for so simple an idea, mostly the counters and the queues’ pointers. The next page uses a second one for MIDI.

  • A serial line sends a byte as a start bit, eight bits lowest first, and a stop bit, with no clock: each end times the bits with its own, at an agreed baud rate.
  • A clock has to divide well into the speed: 12 MHz gives every usual speed within 0.16%; the 6502’s 1 MHz doesn’t.
  • The receiver lines up on each start bit and samples each bit in its middle; the two clocks may differ by up to about 5%.
  • Queues let the CPU and the line each go at their own pace; a queue in memory is two counters, each a bit wider than the address.
  • The data sheet of the 16550 UART, the serial chip of PCs since the 1980s, for a full-featured UART: queues, interrupts, and the 1.8432 MHz crystal.
  • Jan Axelson, Serial Port Complete: serial ports from the wires up.