Model 100 Serial Interface: Difference between revisions
Line 141: | Line 141: | ||
OUT 200,ASC("A") | OUT 200,ASC("A") | ||
In the UART, there is room for two characters: the character currently be transmitted, and the next one. This permits you to ensure there is always | In the UART, there is room for two characters: the character currently be transmitted, and the next one. This permits you to ensure there is always one character waiting in the wings. | ||
You should never overflow the transmission buffers. Either do some other work during the "downtime" and/or wait until there is room by polling bit 4 (0x10) of register $D8. The code that follows just does a "busy wait." | You should never overflow the transmission buffers. Either do some other work during the "downtime" and/or wait until there is room by polling bit 4 (0x10) of register $D8. The code that follows just does a "busy wait." |
Revision as of 11:11, 6 March 2009
Overview
The BASIC ROM provides access to the serial port. BASIC ROM support is well documented elsewhere. This article covers direct use of the IM6402 UART (datasheet) on the Model 100 and Tandy 102.
Configuration
Before the serial port can be used, it must be configured both for serial word format (data bits, stop bits, and parity) and baud rate.
Select RS232 Port
At any given time, either the internal modem or the external RS232 connector may be connected to the UART. This is controllable through software.
For RS232 access, port $B8
, bit #3 must be set to 0.
For Modem access, port $B8
, bit #3 must be set to 1.
Note that $B8
is shared with other functions, including power control.
Serial Word Format
Port $D8
controls the serial word format.
Actually, any of $D0 → $DF
can be used.
Bit | Function | Settings |
0 | Stop Bit Select | 0 → 1 stop bit 1 → 2 or 1.5 stop bits (1.5 if character length is 5, 2 otherwise) |
1 | Even Parity Enable | 0 → Odd parity 1 → Even |
2 | Parity Inhibit | 0 → Parity 1 → No parity |
4-3 | Character Length Select | Bits: 00 → 5 01 → 6 10 → 7 11 → 8 |
7-5 | Unused |
Baud Rate
CPU selection of baud rate is accomplished by loading a divisor into the PIO register through output ports $BC
or $B4
and $BD
or $B5
.
The baud rate selection must be committed by writing $C3
to register $B8
Baud Rate | PIO Divisor |
Port $BD |
Port $BC
|
75 | 2048 | 72 | 0 |
110 | 1396 | 69 | 116 |
300 | 512 | 66 | 0 |
600 | 256 | 65 | 0 |
1200 | 128 | 64 | 128 |
2400 | 64 | 64 | 64 |
4800 | 32 | 64 | 32 |
9600 | 16 | 64 | 16 |
19200 | 8 | 64 | 8 |
38400 | 4 | 64 | 4 |
Here is a practical example of using 38400bps using only BASIC code. This program dumps all RAM contents to the serial port.
1 DEFINTA-Z: OPEN"COM:98N1D"FOROUTPUTAS1: D$="": A=FRE("0"): L=VARPTR(D$)+1: M=L+1: POKEL-1,128: OUT180,4: OUT181,64: OUT184,195: FORI=0TO255: POKEM,128+I/2: POKEL,(IMOD2)*128: PRINT#1,D$;: NEXT
Unfortunately this BASIC code does not transmit the 32K of data any faster than the 19200bps code. Both take about 33 seconds to transmit the image.
So, here's an assembly language version of the same program. It transfers your Model 100's 32K RAM to a serial connection in about 8.5 seconds!
.org 64704 ; select RS232 port MVI A, $25 OUT $BA ; set up 8N1 MVI A, 28 OUT $D8 ; set up 38400 bps MVI A, 64 OUT $BD MVI A, 4 OUT $BC MVI A, $C3 OUT $B8 LXI H,32768 WAITEMPTY: IN $D8 ANI $10 JZ WAITEMPTY MOV A,M OUT $C8 INX H MOV A,H ORA L JNZ WAITEMPTY RET .END
Data Transmission
Once configured, sending a character is simply
MVI 'A' OUT $C8
or, in BASIC,
OUT 200,ASC("A")
In the UART, there is room for two characters: the character currently be transmitted, and the next one. This permits you to ensure there is always one character waiting in the wings.
You should never overflow the transmission buffers. Either do some other work during the "downtime" and/or wait until there is room by polling bit 4 (0x10) of register $D8. The code that follows just does a "busy wait."
WAITEMPTY: IN $D8 ANI $10 JZ WAITEMPTY
When deciding whether the other device is ready to receive you should also consider the Clear To Send (CTS) flow control line described later in this document.
Data Reception
BASIC ROM Interrupt 6.5 Handling
Whenever the UART receives another character, Interrupt 6.5 is signalled. Then, if interrupts are enabled, the CPU stops what it is doing and CALLs location 0x0034 in the BASIC ROM. This code disables further interrupts and jumps to the location 0x6DAC.
The ISR then jumps to vector 0xFE5C (0xF5FC?) in RAM. Normally this is just a return instruction, but you could hook the interrupt here. [ stack manipulation to avoid/ or include default processing + re-enable interrupts? - TBD ]
Polling Interrupt 6.5
Accepting the BASIC ROM's handling imposes significant overhead. With each interrupt, the instruction pointer must be placed on the stack and a jump performed at minimum. If the BASIC ROM (as opposed to an Option ROM) is switched in, then you will have the overhead of disabling interrupts, a jump to the DR vector, a return instruction, and then the default processing of reading and enqueing the new character. All that, and at this point no useful work has been performed other than to relieve the UART.
For maximum efficiency you may wish to poll Interrupt 6.5 pin rather than accept the overhead of an interrupt. This is made possible by the 8085's SIM and RIM instructions.
Using the SIM instruction, you can set the interrupt mask such that UART DR (data ready), bit 1, will not trigger an interrupt. Then, you can poll this bit using the RIM instruction ANDing with 0x02 to see if DR is set.
Alternatively, you could disable interrupt processing altogether during your polled routine, but still use RIM to poll. This has the disadvantage of disabling the background ISR.
Flow Control
The Model T has full support in hardware for the CTS and RTS flow control lines. In the BASIC ROM, however, it is not implemented. Instead the BASIC ROM relys on slow, kludgy XON/XOFF character escapes. This makes it difficult to transmit or receive binary files since the XON/XOFF some characters are reserved for flow control.
Since we are discussing direct control of the UART, we can do better and implement full flow control access.
Detect Clear to Transmit (CTS)
The CTS line is an input to the Model 100. It indicates whether the device attached to the serial port (or the remote equipment behind it) has room to accept new characters. The device can "flow off" the Model T when its receive buffers are full.
(IN PROGRESS)
Request Peer to Send (RTS)
The RTS line is an output from the Model 100 to the device connected on the serial port. It is a signal "requesting" the device to send (or not to send). From the other point of view, the device should transmit if and only if RTS is high.
(IN PROGRESS)
I/O Map
Name | Direction | Port |
TX | Output | $C8 (200) |
RX | Input | $C8 (200) |
RTS | Output | $BA (186), bit 7 |
CTS | Input | $BB (187), bit 4 |
DSR | Input | $BB (187), bit 5 |
DTR | Output | $BA (186), bit 6 |
nb: sense on DSR, CTS seem to be inverted. So CTS ==0 means that it is OK to transmit. A '1' means the device is flowing the Model T off.
Direction indicates both data flow, and whether to use an IN
or OUT
instruction to read/write to the given pin.