UART assembly routine - Page 1
Forum section: electronics / general

author: ChristofferB
author_rank: Frequent Contributor
timestamp: November 29, 2016, 10:49:02 pm
content: Hey guys, I'm at it again. I'm trying to get an i8251 USART running with an 8085 microprocessor, in this rack based system I'm building.I just can't get my head around it, interfacing the chip is easy enough, with it being designed to be compatible, but getting it to, at first, actually spewing serial at me is another matter.It has this register thing, where just after reset, first command word it gets sets baudrate division, parity, etc, and afterwards, the same register is just commands, like toggle handshaking lines, enable/disable rx/tx so forth.I've migrated from the motorola 6850 , since it had horrible compatibility with the 8085 , and I've been trying to modify the serial routines meant for that, originally adapted from an old altair bootloader.Here's my code:Code:0001 0000 ;SIMPLE TEST ROUTINE TO PUNCH OUT CHARACTERS TO A SERIAL PORT0002 0000 ;BASED LOOSELY ON THE ALTAIR 8800 TURNKEY MONITOR CODE, ADAPTED FOR THE INTEL 82510003 0000 ;VERSION 10004 00000005 00000006 0000 UARTDR.EQU10H; 8251 UART DATA REGISTER0007 0000 UARTCR.EQUUARTDR+1; 8251 UART STATUS AND COMMAND REGISTER0008 0000 ;UARTRST.EQU03H; UART MASTER RESET (DUNNO HOW YET, IT RESETS WITH CPU, MIGHT NOT BE NEEDED.)0009 0000 UARTINIT.EQU01001101B; /1 STOP, NO PARITY, 8 BIT, X1 CLOCK0010 00000011 0000 LEADCH.EQU0DH; PUNCH LEADER CHAR0012 0000 LEADCNT.EQU3CH; PUNCH LEADER COUNT0013 0000 SOFB.EQU3CH; PUNCH "START OF BLOCK" CHAR0014 00000015 0000 PROMPT.EQU'.'; COMMAND PROMPT0016 00000017 0000 ;STACKEQU0FC00H0018 0000 STACK.EQU02FFFH;START OF STACK IS THE TOP!! - 4K OF RAM ENDING AT 2FFFH0019 00000020 0000 .ORG00H;START OF MONITOR ( BOTTOM OF ROM)0021 00000022 0000 MON:0023 0000 3E 4DMVIA,UARTINIT0024 0002 D3 11OUTUARTCR ;SET UART /1, 8 BITS, NO PARITY, 1 STOP, NO INTS0025 0004;MVIA,UARTRST; RESET 2SIO /PUT SIORST IN A0026 0004;OUTUARTCR; AND INITIALIZE /ENABLE INT.0027 00040028 00040029 0004 ENTER:0030 0004 31 FF 2FLXISP,STACK; LOAD STACK0031 0007;CALLCRLF; FORMAT OUTPUT0032 0007 3E 20MVI A, ' '0033 0009 CD 4C 00CALLOUTCHK0034 000C 3E 20MVI A, ' '0035 000E CD 4C 00CALLOUTCHK0036 0011 3E 38MVI A, '8'0037 0013 CD 4C 00CALLOUTCHK0038 0016 3E 32MVI A, '2'0039 0018 CD 4C 00CALLOUTCHK0040 001B 3E 35MVI A, '5'0041 001D CD 4C 00CALLOUTCHK0042 0020 3E 31MVI A, '1'0043 0022 CD 4C 00CALLOUTCHK0044 0025 3E 20MVI A, ' '0045 0027 CD 4C 00CALLOUTCHK0046 002A 3E 4FMVI A, 'O'0047 002C CD 4C 00CALLOUTCHK0048 002F 3E 4BMVI A, 'K'0049 0031 CD 4C 00CALLOUTCHK0050 0034 CD 42 00CALLCRLF; FORMAT OUTPUT0051 0037 3E 2EMVIA,PROMPT; HELLO MONITOR0052 0039 CD 4C 00CALLOUTCHK0053 003C 00 STOP:NOP0054 003D 00NOP0055 003E 00NOP0056 003F C3 3C 00JMP STOP; JUST LOOPING FOREVER0057 00420058 00420059 0042 3E 0D CRLF:MVIA,0DH; DO A CRLF AND RETURN TO MONITOR0060 00440061 0044 CD 4C 00CALLOUTCHK0062 00470063 0047 3E 0AMVIA,0AH0064 00490065 0049 C3 4C 00JMPOUTCHK0066 004C0067 004C F5 OUTCHK:PUSHPSW; SAVE CHARACTER0068 004D 81ADDC; ADD IN CHECKSUM0069 004E 4FMOVC,A; UPDATE CHECKSUM0070 004F0071 004F LOOP:;INUARTCR; READ STATUS0072 004F;CPI ' ' OMMIT ERROR0073 004F;JNCLOOP; READY ?0074 004F0075 004F F1POPPSW; YES, GET CHAR0076 0050 D3 10OUTUARTDR; PRINT CHARACTER0077 00520078 0052 C9RET; FROM WHENCE YE CAME0079 00530080 0053.ENDtasm: Number of errors = 0The datasheet for the 8251:http://map.grauw.nl/resources/midi/intel_8251.pdfand my schematic, just in case you spot a giant blunder I haven't.What am I not getting? I've never worked with the 8251 before, and I originally chose the 6850 mainly because I had some good example code to work from.Thanks in advance.

author: Andy Watson
author_rank: Super Contributor
timestamp: November 29, 2016, 11:22:35 pm
content: From an Intel data book:QuoteDoes it have a valid CTS signal? Do you have means of checking that it has both baud and system clocks?

author: ChristofferB
author_rank: Frequent Contributor
timestamp: November 29, 2016, 11:46:56 pm
content: ...Wow, completely missed that. I'll try that, as a first.I haven't actually checked the clocks in circuit, but I should sic the scope on them, you're right.It does have CTS from the terminal, but the other flow control is probably the culprit.Thanks!

author: westfw
author_rank: Super Contributor
timestamp: November 30, 2016, 07:31:16 am
content: the way I read the datasheet, you should initialize by sending the sequence 0, 0, 0, 0x40, <mode>, <command to enable stuff>This allows for the 'initial state' of the 8251 to be unknown. If it was already in command state, the three zeros are essentially no-op (or 'disable everything') commands, and the 0x40 puts the chip into "reset" status (ready for the "mode" byte.) If the chip was expecting <mode>, the zeros configure a relatively benign mode that doesn't last very long, since the RESET instruction follows immediately.

author: coppice
author_rank: Super Contributor
timestamp: November 30, 2016, 09:11:07 am
content: Do you actually have an 8251 or an 8251A? Its 36 years since I used these, and I can't remember the exact details, but the 8251 was badly botched, and couldn't really be used for interrupt serviced I/O. The 8251A fixed that, but was incompatible with the 8251.

author: ChristofferB
author_rank: Frequent Contributor
timestamp: November 30, 2016, 08:37:35 pm
content: Quote from: westfw on November 30, 2016, 07:31:16 amYou may be right, but since the chip master reset is tied to the processor reset (out), and it has power on reset, I don't think It'll start in an undefined state. In any case, it's only a few cycles, so it might be worth to have just for belt-and-braces.Quote from: coppice on November 30, 2016, 09:11:07 amOne is a NEC D8251C, the other is a NEC D71051C. I can't find datasheet on the former, and the latter doesn't say whether it's the 8251 or A version.I think I'm going to use them polled more than anything so both would hopefully do the trick.

author: ChristofferB
author_rank: Frequent Contributor
timestamp: November 30, 2016, 10:54:21 pm
content: Okay, updated the code with the recommendations, still doesn't do anything:Code:0001 0000 ;SIMPLE TEST ROUTINE TO PUNCH OUT CHARACTERS TO A SERIAL PORT0002 0000 ;BASED LOOSELY ON THE ALTAIR 8800 TURNKEY MONITOR CODE, ADAPTED FOR THE INTEL 82510003 0000 ;VERSION 1.10004 00000005 00000006 0000 UARTDR.EQU10H; 8251 UART DATA REGISTER0007 0000 UARTCR.EQUUARTDR+1; 8251 UART STATUS AND COMMAND REGISTER0008 0000 UARTRST.EQU40H; UART RESET0009 0000 UARTINIT.EQU01001101B; /1 STOP, NO PARITY, 8 BIT, X1 CLOCK0010 00000011 00000012 0000 LEADCH.EQU0DH; PUNCH LEADER CHAR0013 0000 LEADCNT.EQU3CH; PUNCH LEADER COUNT0014 0000 SOFB.EQU3CH; PUNCH "START OF BLOCK" CHAR0015 00000016 0000 TXEN.EQU00100001B;0017 00000018 0000 PROMPT.EQU'.'; COMMAND PROMPT0019 00000020 0000 ;STACKEQU0FC00H0021 0000 STACK.EQU02FFFH;START OF STACK IS THE TOP!! - 4K OF RAM ENDING AT 2FFFH0022 00000023 0000 .ORG00H;START OF MONITOR ( BOTTOM OF ROM)0024 00000025 0000 3E 00 MON:MVI A, 00H;NOP0026 0002 D3 11OUTUARTCR0027 0004 3E 00MVI A, 00H0028 0006 D3 11OUTUARTCR0029 0008 3E 00MVI A, 00H0030 000A D3 11OUTUARTCR0031 000C 3E 40MVI A, UARTRST;RESET UART0032 000E D3 11OUTUARTCR0033 0010 3E 4DMVIA,UARTINIT0034 0012 D3 11OUTUARTCR ;SET UART /1, 8 BITS, NO PARITY, 1 STOP, NO INTS0035 00140036 00140037 00140038 0014 ENTER:0039 0014 31 FF 2FLXISP,STACK; LOAD STACK0040 0017;CALLCRLF; FORMAT OUTPUT0041 0017 3E 20MVI A, ' '0042 0019 CD 5C 00CALLOUTCHK0043 001C 3E 20MVI A, ' '0044 001E CD 5C 00CALLOUTCHK0045 0021 3E 38MVI A, '8'0046 0023 CD 5C 00CALLOUTCHK0047 0026 3E 32MVI A, '2'0048 0028 CD 5C 00CALLOUTCHK0049 002B 3E 35MVI A, '5'0050 002D CD 5C 00CALLOUTCHK0051 0030 3E 31MVI A, '1'0052 0032 CD 5C 00CALLOUTCHK0053 0035 3E 20MVI A, ' '0054 0037 CD 5C 00CALLOUTCHK0055 003A 3E 4FMVI A, 'O'0056 003C CD 5C 00CALLOUTCHK0057 003F 3E 4BMVI A, 'K'0058 0041 CD 5C 00CALLOUTCHK0059 0044 CD 52 00CALLCRLF; FORMAT OUTPUT0060 0047 3E 2EMVIA,PROMPT; HELLO MONITOR0061 0049 CD 5C 00CALLOUTCHK0062 004C 00 LOP:NOP0063 004D 00NOP0064 004E 00NOP0065 004F C2 4C 00JNZLOP; JUST LOOPING FOREVER0066 00520067 00520068 0052 3E 0D CRLF:MVIA,0DH; DO A CRLF AND RETURN TO MONITOR0069 00540070 0054 CD 5C 00CALLOUTCHK0071 00570072 0057 3E 0AMVIA,0AH0073 00590074 0059 C3 5C 00JMPOUTCHK0075 005C0076 005C F5 OUTCHK:PUSHPSW; SAVE CHARACTER0077 005D 81ADDC; ADD IN CHECKSUM0078 005E 4FMOVC,A; UPDATE CHECKSUM0079 005F0080 005F 3E 21 LOOP:MVI A, TXEN;ENABLE TX0081 00610082 0061;INUARTCR; READ STATUS0083 0061;CPI ' ' OMMIT ERROR0084 0061;JNCLOOP; READY ?0085 00610086 0061 F1POPPSW; YES, GET CHAR0087 0062 D3 10OUTUARTDR; PRINT CHARACTER0088 00640089 0064 C9RET; FROM WHENCE YE CAME0090 00650091 0065.ENDtasm: Number of errors = 0Does this look like it'd at least 'sorta' work? If that's the case I'll get to hardware debugging.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: December 01, 2016, 06:54:51 am
content: This lineCode:LOOP:MVI A, TXEN;ENABLE TXdoesn't do what the comment says. I think to actually enable the transmitter you need to follow it withCode:OUT UARTCR

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 01, 2016, 11:45:23 am
content: You're absolutely right. Jeez, my assistant must have been drunk that day! He's also made some really dumb wiring errors, resulting in no baud-clock and floating reset, both now fixed.Thankfully, vero-wire is pretty easy to correct.

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 01, 2016, 02:48:27 pm
content: Okay, been through the hardware issues, uart clock works, main clock works, reset works, it's executing the code, and it's doing something right, since the correct chip's /CS is triggered every loop cycle, rs232 drivers works, and can drive both low and hi, but I still don't get any data out.I'm suspecting my very vintage uarts may be duds. Either that or a software thing.

author: stfsux
author_rank: Contributor
timestamp: December 01, 2016, 05:19:05 pm
content: Don't you have to check the TxRDY signal before sending an other byte?

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: December 01, 2016, 05:54:19 pm
content: Quote from: ChristofferB on December 01, 2016, 02:48:27 pmCan you toggle RTS and DTR? If so then the chip is working.Your OUTCHK routine needs to be tidied up:-1. Move tx enable code to initialization.2. Wait until the transmitter is ready (UARTCR bit 0 = 1) before sending the next character.Note: As well as setting TXEN, CTS (pin 17) must be low to enable the transmitter.

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 01, 2016, 06:36:20 pm
content: Quote from: Bruce Abbott on December 01, 2016, 05:54:19 pmI'll do some tests on RTS and DTR.The reason TxEN is in the actual routine, is that there's also an RxEN, and I don't assume you could just tick them both at initialization - wouldn't they have to be toggled between Rx and Tx routines?I absolutely should wait for tx to be ready, but for simplicity, I just wanted it to spew data, less controlled, integrity less important, until I knew the hardware was solid.thanks again.

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 02, 2016, 06:24:55 pm
content: Okay, now hardware IS sorted out, made a small loop to toggle RTS, and it does that splendidly, so the chip works and is initialized correctly.Here's my cleaned assembly routine, I still can't get it to behave. Does anyone have an idea what I might have missed?Code:;SIMPLE TEST ROUTINE TO PUNCH OUT CHARACTERS TO A SERIAL PORT;BASED LOOSELY ON THE ALTAIR 8800 TURNKEY MONITOR CODE, ADAPTED FOR THE INTEL 8251;VERSION 1.1UARTDR.EQU10H; 8251 UART DATA REGISTERUARTCR.EQUUARTDR+1; 8251 UART STATUS AND COMMAND REGISTERUARTRST.EQU40H; UART RESETUARTINIT.EQU01001101B; /1 STOP, NO PARITY, 8 BIT, X1 CLOCKTXEN.EQU00100011B;LEADCH.EQU0DH; PUNCH LEADER CHARLEADCNT.EQU3CH; PUNCH LEADER COUNTSOFB.EQU3CH; PUNCH "START OF BLOCK" CHARPROMPT.EQU'.'; COMMAND PROMPT;STACKEQU0FC00HSTACK.EQU02FFFH;START OF STACK IS THE TOP!! - 4K OF RAM ENDING AT 2FFFH.ORG00H;START OF MONITOR ( BOTTOM OF ROM)MON:MVI A, UARTRST;RESET UARTOUTUARTCRMVIA,UARTINITOUTUARTCR ;SET UART /1, 8 BITS, NO PARITY, 1 STOP, NO INTSMVI A, TXEN;SET MODE /RTS LO, /DTR LO, TX ENABLEOUTUARTCR;ENABLE TXENTER:LXISP,STACK; LOAD STACK;CALLCRLF; FORMAT OUTPUTMVI A, ' 'CALLOUTCHKMVI A, ' 'CALLOUTCHKMVI A, '8'CALLOUTCHKMVI A, '2'CALLOUTCHKMVI A, '5'CALLOUTCHKMVI A, '1'CALLOUTCHKMVI A, ' 'CALLOUTCHKMVI A, 'O'CALLOUTCHKMVI A, 'K'CALLOUTCHKCALLCRLF; FORMAT OUTPUTMVIA,PROMPT; HELLO MONITORCALLOUTCHKLOP:NOPNOPNOPJNZENTER; JUST LOOPING SERIAL FOREVERCRLF:MVIA,0DH; DO A CRLF AND RETURN TO MONITORCALLOUTCHKMVIA,0AHJMPOUTCHKOUTCHK:PUSHPSW; SAVE CHARACTERADDC; ADD IN CHECKSUMMOVC,A; UPDATE CHECKSUMLOOP:INUARTCR; READ STATUSRRC; ROTATE TxREADY TO CARRYJNCLOOP; READY ?POPPSW; YES, GET CHAROUTUARTDR; PRINT CHARACTERRET; FROM WHENCE YE CAME.END

author: Andy Watson
author_rank: Super Contributor
timestamp: December 02, 2016, 07:27:40 pm
content: It's been three decades since I dabbled with these chips - so what I say with respect to the 8251 may not be appropriate, or even correct! But here are some thoughts:Have a good look at the timing. There is a note at the top of page 14 (of the 8215A datasheet) that says that the status flags may be delayed by 28 clock periods from the event that caused them. I assume this means the system clock. With short sections of assembly code it is quite possible that your processor can change a uart flag and perform a complete loop of code before the flag is actually set.Another thing to consider is that the processes within the uart are often clocked by the baud-rate clock. For example, the transmitter status flags may get updated only when TxClock happens - you have to make allowances in your code for the fact that your CPU is operatingasynchronouslywith respect to the uart.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: December 03, 2016, 02:08:21 am
content: Quote from: ChristofferB on December 02, 2016, 06:24:55 pmDoes the CPU get past testing TXRDY, and if so does TXD outputanything? If it is then check the baud rate. If not then what is happening on pins 15, 17, and 18?

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 03, 2016, 11:58:52 am
content: Quote from: Bruce Abbott on December 03, 2016, 02:08:21 amI don't know. I don't have any output devices that could be used to tell where it was in the code. Maybe that's the next project for it.TXD outputs nothing at all, it just sits at -12V.Here's the observations so far:- voltages are good- rom's being read correctly- uart reset line's good- uart clocks are good, both baud and system.- I can write to the uart, get it to wag its RTS pin.The test setup is just looping RTS to CTS on the db9 connector, and putting a oscilloscope probe in TX.and I get nothing.

author: westfw
author_rank: Super Contributor
timestamp: December 03, 2016, 06:09:56 pm
content: QuoteQuotePut an LED on RTS and use that...

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: December 03, 2016, 06:40:20 pm
content: Quote from: ChristofferB on December 03, 2016, 11:58:52 amYou can 'waggle' RTS at certain points in your code. If you feed that signal into your scope's external trigger then you can see what other pins are doing at the time.TXRDY (pin 15) should go high when the transmitter is enabled, and pulse low as each character is sent. If it stays low then either the transmitter is not enabled or CTS (pin 17) is high. TXEMPTY should start out high but go low while characters are being transmitted.In case there is something wrong with the rs232 driver, disconnect it from TXD (pin 19) and look directly at the pin.QuoteNo. The UART can send and receive simultaneously.

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 03, 2016, 07:52:17 pm
content: Removing the driver chips might actually be a good idea. the MC1488/1489 likely takes a fair bit more abuse than the components later in the chain, being both higher voltage and 'front end'.Adding some status LEDs might be a good idea, but I've actually made some progress:I've added the dummy control words  to the start of the MON routine, and that did something:Code:0026 0000 3E 00MVI A, 00H0027 0002 D3 11OUTUARTCR0028 0004 D3 11OUTUARTCR0029 0006 D3 11OUTUARTCRStill have no idea what this does.A good visualization is the A8-15 led panel I have on the thing, since the 8085 also duplicates its IO ports to the upper addresses:Now, when no RS232 connector is plugged in, it stabilizes in a loop of an IO request at 00010001B, the control reg. That must be the waiting loop:Code:LOOP:IN UARTCR ; READ STATUSRRC ; ROTATE TxREADY TO CARRYJNC LOOP ; READY ?When a DB9 with RTS and CTS shorted is inserted, it breaks from the loop, doing things too fast for the naked eye, presumably sending the characters to the UART.Removing the plug plunges it back into aforementioned state.With one of my two UART chips (swapping between them), it sends something. too slow and few pulses to be data, but it is something. The other doesn't.It looks like the handshaking portion of the UART (1 of them) is at least working.Maybe it'd be worth it to buy a set of new 8251A's, so they can be ruled out.Another thing - I'm only using RTS/CTS for handshaking - should something be done to DSR/DTR?Thanks again, slowwly getting there.

author: westfw
author_rank: Super Contributor
timestamp: December 03, 2016, 09:20:53 pm
content: QuoteDo you have anything connected to the SOD pin yet? that's another place you can stick an LED. Or a scope if you want to bit twiddle it. Or a serial device, if you want to implement bit-banged serial before you get the USART working...

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 03, 2016, 11:53:17 pm
content: I don't have anything connected to the SOD pin, might use that. I reaally don't want to do bit-bang serial, as much done in hardware as possible!I have another potential explaination for the very very slow shifting serial output I see. In the setup, the baud prescaler has to be set, /1, /16 or /64.If I feed it a low baudrate like 1200 hz, and it's not initializing properly, thus dividing that by either 16 or 64, that could account for some very slow data transmission..edit: that seemed to be wishful thinking, unless a registry bit is stuck in the chip (can they do that?)editedit: There aren't any strict requirements for the cpu clock, is there? I think mine's 4.1 MHz, within the spec of my 8085.

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 04, 2016, 02:44:32 am
content: I only just realized there's something seriously wrong with my clock.I went from measuring the baudrate gen to the system clock with my scope, and only then relized I had to turn the timebase knob the 'wrong' way!Measuring the system clock (buffered, from 'CLK' on the 8085), the period's about 0,3 ms! that'd be a 3.2 kHz system clock!What's going on??Trying another xtal, about 3 mhz, from another scrap 8085 board didn't change that outcome notably.Tomorrow I'm gonna try to replace the entire crystal circuitry with a 9MHz can-oscillator, that's a known good, can't really go wrong.The super-slow-system-clock would explain alot of the issues I've been having. First, I can see the IO/M pin flicker - that should probably be too fast @3mhz,secondly, my previous UART board worked, but had the strange bug that it sent the characters very. very. slowly. like one every second.

author: westfw
author_rank: Super Contributor
timestamp: December 04, 2016, 04:44:52 am
content: Quote"Just for debugging" (you've probably heard THAT before!)(and only because you're using "difficult" hardware for peripherals.)

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 04, 2016, 01:21:47 pm
content: Yeah, you're right. might be worth it. Anyway, I think the clock is a bigger issue now. I shifted to the can oscillator (seemed to be dead), removed it,and the machine still runs exactly the same when powered up with no clock!I removed power from the BAUDrate crystal to be sure it didn't catch crosstalk from that.It still runs, no clocks, exactly the same behavior as before. Am I running a computer off of mains hum?Anyway, I'll try to find a crystal that works and fits and throw in there. Perhaps my main clock crystal has been damaged all along.

author: ChristofferB
author_rank: Frequent Contributor
timestamp: December 04, 2016, 02:17:27 pm
content: Aand now we're done. Got it working at last! It was the clock, it must've run off of noise all this time. Putting in a 9MHz can oscillator and removing the xtal capacitors and now it just runs. Here's proof and a portrait.This fault obviously accounts for most of the larger issues I've had with this the last year, maybe actually measuring frequencies with a scope instead of just going 'yep, there's a signal' is a wise idea..Thanks for all the assistance!