16550 UART - Page 1
Forum section: electronics / beginners

author: pyromaniac4382
author_rank: Contributor
timestamp: March 27, 2015, 12:45:27 am
content: Hello,I have been working on an echo program for the 16550 UART using a Z80 and some ROM. I have attached the code and schematic I have been using. Everything half-works.What I mean by that is I have built up the circuit on my breadboard, and plugged it into the PC's serial port using a USB->Serial Adapter, and what I type into my PuTTy terminal emulator shows up on the program. This means the Z80 is receiving characters from the PC and echoing them back to it.The issue is that certain characters just don't seem to be echoed back right, for instance the character 7 echos back 0 or 7 sometimes.For the most part I am getting back the correct character echoed back, but a few here and there behave outside of what they should be behaving like.I am sure it is something to do with my code. I wanted to get this working before I started looking to integrate more components like RAM which is why the code is so dense.Thanks for any help you can provide.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: March 27, 2015, 03:46:14 am
content: Signal quality on some pins, or the serial cable?? Does the error vary with baudrate?Tim

author: macboy
author_rank: Super Contributor
timestamp: March 27, 2015, 01:18:21 pm
content: You have a baud rate error. Try measuring the baud rate on each transmitter and compare (repeatedly send char "U" which is 0x55 or b01010101). They must be within 4% of each other to work reliably. At >5% error, the last bit or bits transmitted are subject to error.I have an expensive terminal server (multi-port ethernet to serial box) that was consistently 4% slower than nominal. It would work with some devices that were also a little on the low side, but anything even a little high would not talk to it without errors. Changing a 25 MHz oscillator for a 26 MHz one made it perfectly reliable. Thank goodness for digi-key's made-to-order custom frequency oscillators!

author: pyromaniac4382
author_rank: Contributor
timestamp: March 27, 2015, 02:16:12 pm
content: @T3sl4co1l : My first thought was it was the USB->Serial cable I was using, but then I switched it out for another of a completely different brand, and the unwanted behavior did not change. I think I can kind of rule out signal quality connections on the pins because about 99% of all the keys on the keyboard echo back properly. The only keys that are having trouble are, 's' '7' and 'p' off the top of my head. I am currently using 9600 baud, but I will try increasing the DLAB divisor and lowering the baud to about half that and see if anything improves.@macboy : I had a feeling it might be this, but wasn't sure what to do about it. I will try your test to see if I am getting the correct signalling out of the BAUDOUT pin on the UART on my oscilloscope. I am not quite sure what I should be looking for in terms of signal. I have always been confused about frequency vs baud. If I am running at 9600 baud should I be looking for 9.6KHz on the BAUDOUT pin? The same question I would have if I sent out U's over and over. What should I bee looking for in terms of signaling?What I have tried so far is swapping the oscillator on the Z80 to a higher frequency (6MHz) and maintaining the oscillator on the UART (1.8432MHz). This seemed to help a bit actually, but does not solve the problem.

author: macboy
author_rank: Super Contributor
timestamp: March 27, 2015, 02:49:10 pm
content: Quote from: pyromaniac4382 on March 27, 2015, 02:16:12 pmWhat you need to look for is a bit period that is as close to the same as possible between the two devices. As mentioned earlier, anything over 4% total error (e.g. 3% high on one end plus 1% low on the other) is completely unacceptable and some devices won't tolerate even that much.The baud rate is the signalling rate on the wire, not the rate at whichdatais transmitted. There are framing bits (start/stop bits and optional parity) that use up some of the raw throughput. Typically, each byte requires 10 bits to be sent, so the data rate is 9600/10 = 960 Bytes per second.With 9600 baud, and alternating 0s and 1s, you will see either bursts of 4800 Hz square(ish) waves, or a continuous 4800 Hz square wave. This depends on whether the UART is transmitting truly continuously or not. It is only 4800 Hz because you need two bits - a zero and a one - to represent one 'cycle' of the square wave. UARTs will send a '1' bit to start a transmission, then the data, then a '0' stop bit. So it sends 10 bits per byte, in the case of "U" (b01010101), it sends b1010101010. Note that for logic level or TTL level UART, all data is inverted on the wire (1 is low and 0 is high), but for RS-232 level, 1 is a positive voltage and 0 is negative. The idle state is 0.

author: pyromaniac4382
author_rank: Contributor
timestamp: March 27, 2015, 06:18:27 pm
content: This is what I see on the scope using that test. I would say that it is spot on what I would be looking for at 9600 baud. AttachedI also tried the other test and changed the baud rate to 4800, and I have the same unwanted behavior. I can specify the baud rate in puTTy and I have played around going a little lower and higher that 4800 and 9600 with no change in unwanted behavior.So I have a feeling it isn't baud rate error. Its either my code now or the wiring I guess..

author: macboy
author_rank: Super Contributor
timestamp: March 27, 2015, 08:20:16 pm
content: Quote from: pyromaniac4382 on March 27, 2015, 06:18:27 pmYou tested both transmitters (PC and your Z80)? Random bit flipping smells of marginal baud rate matching, but it certainly could be something else. At least it's easy to eliminate baud rate mismatch.

author: pyromaniac4382
author_rank: Contributor
timestamp: March 28, 2015, 01:28:45 pm
content: Quote from: macboy on March 27, 2015, 08:20:16 pmYes I went ahead and tested both the TX and RX again using my echo program instead of just sending out 'U' over and over I held down 'U' on the keyboard so it would send and receive to the Z80 circuit and back to the PC via the terminal emulation program.(@9600 baud)I have attached both waveforms named respectively. I measured the RS232 signalling right before the serial cable input to thecircuit.txuart.png is from the Z80 circuit to the PCrxuart.png is from the PC to the Z80 circuitI am kind of at a loss right now. I want the UART interface to be spot-on reliable before I develop the system any further since this will be the main source of feedback for debugging for a little while. (besides test equipment of course)What I know so far.The baud rate error seems to be within the 5% pointed out in this thread. If it was out of spec I should be seeing ~46KHz or ~50KHzcorrect?Varying the baud rate does not solve the problem.The wiring has been checked for continuity dozens of times, and I highly doubt that I would be getting this far if there was a major error. I could see maybe if I got some control signals on UART itself incorrectly tied high or low that it might be causing this problem, but I don't think I have enough experience with this part to know that, so I cannot rule this out.The software is most likely the culprit. A register probably needs to be written a certain way, or I am incorrectly checking line status, or my Assembler (TASM3.2) is being wonky. Maybe looking at the bin file's HEX might give me some insight into the problem.I also ran a test just indefinitely transmitting out the keys I am having trouble with ('p' '7' 's') from the Z80 circuit to the PC, and they all send correctly without any error, so I think the UART receiver side is to blame here.

author: SeanB
author_rank: Super Contributor
timestamp: March 28, 2015, 02:23:43 pm
content: You do have decoupling capacitors on the Z80 I hope, 100-220n per chip close to them and 10-100uF as bulk decoupling. That might be the cause of the glitches, or you might want to delay /IORQ by a few dozen ns using a 100r series resistor with a 100pF to ground on the 16550 side. Reset also needs a 100n capacitor across the switch to get a noise free rise.

author: pyromaniac4382
author_rank: Contributor
timestamp: March 28, 2015, 02:38:50 pm
content: Quote from: SeanB on March 28, 2015, 02:23:43 pmYes sir. 100uF electrolytic tank cap. 100nF ceramic cap per chip decouple. I added the 100nF ceramic cap across my switch as well. Still the same behavior.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: March 28, 2015, 03:43:05 pm
content: Back when I breadboarded a Z80,http://seventransistorlabs.com/Images/Z80_Timer2.jpgI had a 32 bit LFSR running in the background (just making noise on an output port). It would freeze randomly; sometimes within hours of startup, sometimes days. The dynamic NMOS CPU requires stable clock; the clock generator is right there beside it, so I don't really know why that should make it freeze. I don't think other IO states are supposed to freeze it either (/WAIT was pulled high -- fast enough SRAM not to need it).In any case, this is just one of the problems you face with a breadboarded circuit. You might try dampening any of the bus signals (An, Dn, controls) with R+C (say 220 ohm + 47pF?) or series ferrite beads, or rerouting the buses so they follow the supply better (and intermingle more ground jumpers among the bus jumpers). You don't really know without a scope, and you need a scope over 100MHz bandwidth to really tell (since HC/LS logic will dubiously respond to edges and transients that fast). But your probe also affects the signal, so it may not produce the transient you were looking for -- and also not fail -- while you have the probe in circuit.Tim

author: SeanB
author_rank: Super Contributor
timestamp: March 28, 2015, 03:53:18 pm
content: Z80 clock really benefits from a 330R pull up resistor if driving from anything other than a proper driver, it needs the high level to be 5V, not anything lower. With direct driving of the peripherals without any decode logic delay it is likely the select lines are enabling the chip too soon before the data bus is stable, and this will probably be the cause of the glitch. The minimum set up times are important, as some transitions are going to take longer than others on the data bus, and if the latch holds the intermediate state every so often that will be it. Take the Z80 clock speed down to half and see if the problem persists, that will then point to a timing issue ( half and then adjust the RS232-USB data rate to half to compensate) that needs attention.

author: pyromaniac4382
author_rank: Contributor
timestamp: March 30, 2015, 01:06:42 pm
content: @T3sl4co1l : I don't think the failure is along those lines, but it probably has some effect, and I would rather not go down the path of optimization for the breadboard since I will quickly move to a PCB once this issue is settled. (and after I have added in some RAM of course.)@SeanB : The clock on my scope looks fairly clean. I have a oscillator "CAN" package driving the UART (1.8432MHz) I think you are completely right about the direct driving of the peripherals. I thought that I would do this for now to reduce complexity and still be able to test, but it may have just bit me in the *&% doing so.The more interesting test I had ran before I saw your post @SeanB was changing the ports in Software that the UART was "assigned" to. As you said since the UART is directly driven by the control logic of the Z80 it basically can map to any eight consecutive addresses that start with X0H -> X8H. I noticed that the higher the port number that was referenced the less of a problem I experienced. By the time I started using 60H - > 68H the problem essentially disappeared. My thinking is that the Z80 takes a bit of extra time to resolve the higher port number and therefore gives the UART a bit of extra time to latch the correct data.This all leaves me wondering if the Z80 is just too fast for the PC16550DN. If I just introduce a buffer or a double inversion to the control signals going to the UART this would most likely be the most simple solution, correct?

author: Laura
author_rank: Contributor
timestamp: April 01, 2015, 10:43:35 am
content: Quote from: pyromaniac4382 on March 30, 2015, 01:06:42 pmYour Z80 is likely having trouble driving data bus lines high quickly enough. I assume you are using an old NMOS chip. (Was a CMOS pin compatible Z80 ever made?) NMOS is not able to drive signals to a logic 1 very well - the output structure essentially uses a pull-up resistor. The capacitance of your breadboard is making things even worse.When the Z80 writes to an I/O port, the last values on the data bus will be the I/O port address (from the OUT instruction.) The more 1 bits you have in your I/O address block, the more data bus lines will be "precharged" to a logic 1 level. The Z80 won't have to work so hard to pull those lines up if the data being written also has 1's there.Check the spec'ed Voh of your Z80 versus the Vih of the 16550. Perhaps there isn't much margin. (I doubt it, but do check...)I see two possibilities of how the "slow 1's" cause your problem:1) The Z80 could be really weak and it hasn't pulled up the bus lines by the time the /IOWR finishes.2) The Z80 isn't done pulling up by the start of /IOWR, and the 16550 is so fast it already transfers written data into the serial shift register before the trailing edge of /IOWR.A quick solution is to slow the Z80 down. Perhaps run it from the 1.8432MHz baud rate clock.BTW, if this slow pullup is your problem, it will just get worse when you add (S)RAM. However, it isn't insurmountable. Back in the day there were systems where the data bus has traces several feet long looping all over the system PCB.

author: pyromaniac4382
author_rank: Contributor
timestamp: April 01, 2015, 02:31:22 pm
content: @Laura: I am using the Z84C0010PEG. This is a CMOS version so I am not sure if what you have pointed out still applies?Z80Voh1 : 2.4V @Iol = 2.0mA (floating)Voh2 : Vcc-0.8V = 4.2V @Ioh = -1.6mA (Address, Data ,MREQ,IORQ,RD,WR)UARTVih : 2.0V -> 5.0VMargins between seem ok. Both are CMOS chips. Need to check these later on today for measured values.I also have a Z84C0010PEG (20Mhz). I swapped out the CPU in circuit, and still the same issue. I have also swapped out the PC16550DN UART (DIP40) and no change. I can at least read the ROM chip with my programmer back to know that the ROM is not the issue.I will try to drive the Z80 with the BAUDOUT of the PC16550DN to slow it down and see if anything changes. This solution is not optimal though since I want to eventually run the Z80 at its maximum allowed frequency, or at least half.

author: Laura
author_rank: Contributor
timestamp: April 02, 2015, 09:03:41 am
content: Quote from: pyromaniac4382 on April 01, 2015, 02:31:22 pmCMOS will do much better at pulling high. But you observation about changing the I/O address still stands. So I still think you're not meeting some setup time.Can you look at the data bus with an oscilloscope? To get a stable signal, write a little code loop that writes a byte to the UART, and then JMPs back to the same instruction.Also write a little test routine: Find a UART location that you can treat like a byte of RAM - maybe a byte of the baud rate register will work for this. Write various values to it and read them back and compare with what you wrote. If there is an error, stop and report it back. This will test if you are having general problems accessing the UART, or just the send data register.