After sufficiently testing our EEPROM chips and with the knowledge that we are communicating with them properly we can start to build programs to test other devices added to our system. One of the more useful devices to add is a UART, and that is just what we will do.
UART stands for Universal Asynchronous Receiver/Transmitter. In our case it is just a transmitter that will take the parallel data on our data bus, and send it out bit-by-bit “serially” to somewhere else. The somewhere else is another computer with a serial port that will assemble this data and do something useful to it like display it on a monitor.
I have struggled with assembling this circuit for so long because of many different factors,
- I am stubborn with my wiring, always thinking it is correct, when more than often it is not correct.
- The initialization of the UART (16550) is not discussed clearly in the data sheet.
- The USB-> TTL module I purchased on the cheap from China is garbage. Well maybe.
- I tried re-cycling code I found on the internet as if it would magically work.
- I overthought my initial test code, and I am awful at programming in assembly.
My test code is as follows,
INIT_UART initializes the UART. To do so we need to write to some of the UART’s registers. A0, A1, and A2 are used to address these registers along with the control signals /IOREQ, /WR, and /RD. The data bus is also attached to the UART to send the data we will write into these registers, and later to send data through the UART. The registers we are concerned with are the Divisor Latch Registers (DLAB: High Register: 00H & 01H), the Line Control Register (Register: 03H), the Line Status Register (Register: 05H), and the Transmitter Holding Register (DLAB: Low /WR: Low Register: 00H).
The Divisor Latch Register can be programmed by first setting bit 8of the Line Control Register high. This makes address 00H the LSB of the divisor and 01H the MSB of the divisor. What is the divisor to program? The divisor can be calculated by using the formula,
Typical baud rates are 9600 and 19200. Baud rate is how many bits per second you can send. Therefore it follows that with 8-bit data and one added start and stop bit, you have 18 bits for every “word”/character which is two bytes. So with a 9600 baud rate you could potentially send around 533 characters a second if there was no overhead from the microprocessor (about a page worth of characters). Typical UART frequencies can be found in the 16550 data sheet, I used 1.8432 MHz since I had this oscillator already in a half-can package. If we re –arrange the formula for the divisor and plug in our known values we get,
To program 12, we can either explicitly tell the assembler we want to put the decimal number 12 in, or program the Hex value ‘0C’. Remember the divisor latch register’s LSB is programmed at 00H and the divisor latch register’s MSB is programmed at 01. If your divisor was say 1000 then your HEX value would be 03E8H and E8H would go to the divisor latch register’s LSB 00H and 03H would go to your divisor latch register’s MSB 01H.
Next we program the line control register by sending the data 03H to its address 03H. According to the 16550’s data sheet this tells the UART to expect 8 bit data size and add one stop bit as well as the start bit for each word that will be sent. Along with this definition, 03H also resets DLAB to that we can start to transmit data when we send bytes to the Transmitter Holding Register.
Before we send the data however we need to check the Line Status Register’s bit 5 to make sure that when our loop does execute that we aren’t already sending a character when we try to send another. To do this the BIT command is used, which sets the Zero Flag to the opposite of the value on the bit being tested. For us this is the Transmitter Holding Register Empty bit, and when this bit is enabled the UART is ready to transmit again.
To send we ‘out’ a ‘word’ to the Transmitter Holding Register at 00H, since DLAB is low this should work. As we loop back our main program we again test the Transmitter Holding Register Empty bit in the Line Status Register before sending another word.
To capture the data my UART was sending I use a USB to RS-232 adapter, and used PUTTY to listen to the adapter at 9600 baud. To obtain the RS-232 requirements I used a MAX237 level shifter. You see, our circuit works at 5V which is sometimes called TTL level while RS-232 works around 12V levels. The level shifter takes care of bumping up the voltage to the correct level. The adapter has a DB9 serial connector, and since we are only transmitting, we hook up our transmit line to the receive line on the adapter’s DB9 connector (PIN 2) and our circuits ground connection to the adapter’s DB9 connector (PIN 5).
If all goes well you should see a steady stream of ‘A’ characters flooding your screen. After so much time trying to get this to work I was ecstatic to see all of the ‘A’s. Now our computer has a flexible and useful form of output that we can use for debugging, and we no longer have to rely on those LEDs, which at the MHz frequency are useless because of flicker threshold.
Below is the realized schematic for the Z80 UART Test Circuit. Remember how I mentioned that the USB-> TTL module I purchased on the cheap from China is garbage. Well I am just mad at it because the Tx and Rx lines are 3.3V TTL logic levels instead of 5V TTL logic levels. It is called a D-SUN USB->TTL adapter. When I initially ran my test I was using this and getting garbage on my serial terminal. This can probably be solved with a 5V to 3.3V level shifter, but I had the other adapter around and the MAX237 chip. You could get away with using one of the USB->TTL serial adapters, and negate the MAX237 altogether from the circuit. This would simplify the parts list a bit and the wiring since you could take the Tx line right from the UART and connect it to your adapter. Just make sure that your adapter is for 5V TTL levels and not 3.3V!
All Files from this project can be downloaded from my GitHub Repository,