Design Brief for a UART
|USB? - Not always!
So how does it work then?
Before we can address the question of how the port is actually going to work, we have to ask the question, "What are we trying to achieve?" In this case, it's all a bit arbitrary mainly because the effort is to support a semi-interesting article on a VHDL serial port.
Although RS232 in a generic system has all but disappeared from mainstream commercial technology, it's still very much present in the technical world, and will doubtless be so for a long time to come. As a solution for connecting an iPod, or a camera to a PC RS232 was a pretty hopeless solution. For printers and (dare I say) plotters, RS232 was less of a disaster. The advent of simple to use solutions like USB, which have richer interfaces, are much better suited to cameras and iPods. By virtue of their benefit to those solutions, they have really improved interoperability in printers, scanners and such.
The richness of interface and protocol in USB is both it's strength and weakness. From the perspective of an average user, and/or every day utility, the Plug and Play USB mantra, is key to it's success. By contrast, if you have an ad-hoc requirement and the aim is to simply knock together a prototype; from an engineering perspective the detail of implementation for Plug and Play can be a hassle. The real benefit of RS232 and the UART today, is that it is a general purpose one (or three in practice) wire interface that can be directly connected to almost any computer. The wires can be stripped from a piece of spare power cord if necessary, and the connectors are cheap and can be made with a soldering iron. One can even use deletable PCB pin header to take a prototype to manufacture. Unlike USB per-se, RS232 can be connected to a modem and used with the phone system directly, merely using hardware that is spare. In any case, and even without termination RS232 has USB licked on communication distance, and at almost zero cost since one can use existing wiring.
On consideration much of this is debatable, but the thing that really stands out, is the software angle. For a quick prototype, perhaps the least desirable thing is to involve a lengthy software development program. With USB, it will probably involve writing driver software. With RS232 one can still get directly to the serial port from the command line on most computers. You can stream files to an RS232 device, with nothing more than a computer with Windows, Unix or Linux. If you need some sort of interaction, then you can implement it using either an old fashioned terminal, or terminal emulation software. On most computers opening a serial port is easy, and it's highly unlikely that a driver would be required.
For experimental hardware, such as one might produce in VHDL, RS232 is a good choice. The actual implementation is not more than 100 flip-flops which is dwarfed by typical cheap programmable logic which might have 100,000 flip-flops. There is no real software overhead, and if you want a quick way to get in and control or test some complex function which is under development, there is almost no comparison. This then outlines the target application for the serial port I have designed here.
The most notable disadvantage of RS232 is the setting of parameters on the transmitter and receiver. Whilst parameters like parity, stop bit count, and data bit count, are normally configurable on a serial port we fix these completely because their variation has little or no value in this fairly constrained application. Besides this in most modern applications of RS232 these settings never change.
We've not yet mentioned our implementation of the Baud rate. Our serial port implements a variable Baud rate simply because it is one of the few RS232 settings that is ever varied. Typically this is easily configured, but configuration is often forgotten. For this reason our serial port autodetects Baud rate at the receiver. Our serial port avoids the use of hardware handshaking and merges autodetection capability with a simplistic approach to software handshaking. This makes for a really simple USB like hardware and software setup, which is nearly as good as USB plug and play. The scheme works well in all circumstances but the one where the slave end of the serial link is not using our UART. Since we are explicitly implementing a UART for a slave, which can also be used as a master this should not be a problem.
Autodetecting Baud rates is not a new idea. I first saw it, on the serial port of the Texas Instruments family of TMS320 DSP's. It was a great idea then, and it's still great now. I don't know exactly how TI implemented their onboard UART, but to implement mine, I just time the length of the start bit in the receiver. Once the start bit ends, the count is transferred to the Baud rate divisor register, which for the first data bit of every byte is temporarily halved. Whenever the baud rate divisor timeout expires, a bit is sampled and pushed into the receive shift register. On completion of a byte where no baud rate was initially present, the received byte is compared with an "Auto Baud Key" byte. If a match is made the baud rate divisor, timed from the start bit, is accepted. The Key byte is chosen so as to ensure that the start bit is always one bit period. The diagram below illustrates;
The overall scheme for baud rate detection is simple, and works well with existing serial ports that one might find on a typical computer. The handshake is simple, and does not prevent large chunks of data being sent. The one potential difficulty is that the scheme has no facility for error detection or recovery. When I last used a scheme like this one, some high end computers had a single USB port, hidden under a cover at the back of the machine. Certainly nothing in the lab had one. Perhaps this gives some perspective on how long old this idea is. One thing I've not forgotten was that when I used this scheme in programmable logic, the cable lengths were short, and errors were not a problem of any kind.
The basic handshake merely consists of the main computer being described as a master with an "initiator" port. The master is responsible for setting the local Baud rate, although a default is acceptable. This rate is propagated to the slave "responder" receiver by virtue of the Auto Baud Key. Once the "responder" receiver has the Baud rate, the slave as a whole can read the rate and pass it on to it's "responder" transmitter. This transmitter then sends the Auto Baud Key back to the "initiator" and master. This reply serves two purposes. The first, is that it is possible that the "initiator" is actually our UART. Such an "initiator" receiver would need to receive it's Baud rate from the "responder" transmitter. Looping the Auto Baud Key serves this purpose, and can cause no harm. In practice the "initiator" receiver is most likely to be a standard serial port. Nevertheless the reply serves a second purpose. This purpose is to satisfy the implicit handshaking.
The handshaking rule holds at both ends of the serial link. Once a byte has been sent, one must not send another until a response has been received. On consideration this may seem like a limitation on performance, and in truth it is. However it is not a hard and fast rule. The serial port makes no other demands on the way in which data is transferred, so if the ad-hoc protocol is devised to allow a set number of bytes to be transferred by agreement, efficient simplex streaming is possible. Clearly, duplex streaming is not possible, but for this kind of application that is usually unnecessary. This implementation does require two wires of a full duplex link, but is only ever half duplex.
Next, we'll set out a basic specification and firm up the mechanics of the actual implementation.