Nick's Guide to Designing an Elegant UART by Nicholas C Weaver This is a simple guide on how to design a UART for CS150. Although I don't explicitly give the total-complete-and-everything schematic for the design, this walkthrough should allow someone to quickly design a UART for the lab. Also, this UART is significantly different from the one suggested implementation in the lab, you don't have to use this design. I believe it is nearly the most compact possible, but somebody might have better results with a different design. This is also not a standalone document, but designed to accompany the lab handout. Therefore, I don't spend any significant time describing the problem. Finally, one WORD OF WARNING (err paragraph): This is largely a reconstruction with some variation of a design I did when taking CS150. Although the general design worked perfectly, there may be a bug or two lurking in this sketch. This particular design has not been implemented or debugged. Thus, view this as a guideline for how you should implement yours, NOT a cook-book recipe. Since much of this is for YOU to get practice as a designer, I don't view debugging this as a high priority for me. So use this as a guide, attempt to understand what is going on, but actually design and debug it for yourself so you know you will get it right. You don't blindly run someone's untested code, why should you blindly transcribe someone's untested design. There are a few problems we need to solve in order to make a working UART. 1) The UART requires a 31.25x8, or 256 kHz clock. This should be generated outside of the UART and taken as an input. The CS150 board uses a 16MHz operator, so one needs to divide the clock. The easiest way to generate this clock is to simply have a binary counter which is always running, clocked by the 16MHz clock. The 0th bit (B0) is an 8MHz signal, The 1st bit (B1) is a 4 MHz signal, etc. The 256 kHz clock should be passed through a BUFG before being used, and will be used in your UART and perhaps other places in your design. 2) Capturing the data. The easiest way to capture the data from the serial input is simply a shift register. An 8 element shift register with a clock enable should be sufficient. It will never be necessary to reset this register, and it should always be clocked by the 256 kHz clock. The only question (to be discussed later) is when to enable this shift register to clock in the data, SHIFT_CE. 3) Controlling everything. The easiest way to control things is with a simple, 8 bit binary counter with a clock enable and a synchronous reset, and should always be clocked by the 256 kHz clock. The design is simple: When the start bit comes (INPUT is low), we start counting. Whenever PROCEED is high, we keep counting. Logic equation for counter CE: COUNTER_CE = (~INPUT | PROCEED). Otherwise, under all other cases, we should reset the counter. Why? Either the input just glitched for a cycle or two (in which case we want to reset the counter or start again), or we have finished counting (and therefore want to be ready for the next block) in which case the stop bit will have a high INPUT and PROCEED will be dropped by the DRDY signal. Since PROCEED will be negated when we are done, we might escape the need for a separate reset from DRDY for the counter. But I'd like to insure that we stop on the cycle immediately after DRDY is asserted. Also, since external reset should always reset the counter, it should be Thus, logic equation for counter reset: COUNTER_R = (~COUNTER_CE | RESET | DRDY) Now we just have some additional decisions to make. The first is when to proceed and when to stop: This is straightforward. PROCEED should be the output of a register. This should start whenever the counter gets to 4 (so we know that we have received 4 cycles of the start bit), should stay high when PROCEED is high, but should always be reset to 0 whenever RESET or DRDY are asserted. Thus PROCEED_IN = (~RESET & ~DRDY & (B2 | PROCEED)) The next decision is when to enable the shift register. The easiest way is just to use the 3 least significant bits of the counter. Since the counter is started as soon as the start bit begins, when the counter reaches 3 or 4, we are almost exactly in the center of the bit. For ease, lets say 4. Thus, the logic equation for the shift register CE: SHIFT_CE = (~B0 & ~B1 & B2) Finally, we need to decide when we are done. This is also simple. Bits 3-6 of the counter should register a value of 9, so we have counted 9 full bits of data. We would also like to wait until the midpoint of the stop bit before signaling that the data is ready. It is probably best to stop one cycle before we would otherwise clock in the data, to save an entry in the shift register. 1001 is the binary value for 9. Note that we don't actually have to check B4 and B5 of the counter. Thus: DRDY = (B0 & B1 & ~B2 & B3 & B6) Voila, a simple UART, using an 8 bit shift register, an 8 bit counter, a single register for holding PROCEED, and a couple of LUTs worth of general logic gates.