by Zhahai Stewart
(Note, the links to the author
and for this page were dead so I have saved a copy to my site for
posterity)
Addr MDPA no MDPA 0x3BC LPT1 n/a Monochrome Display and Printer Adapter (MDPA) 0x378 LPT2 LPT1 Primary Printer Adapter 0x278 LPT3 LPT2 Secondary Printer Adapter Name MDPA no MDPA LPT1 0x3BC 0x378 LPT2 0x378 0x278 LPT3 0x278 n/a
Port R/W IOAddr Bits Function
---------- ------ ----- -----------------
Data Out W Base+0 D0-D7 8 LS TTL outputs
Status In R Base+1 S3-S7 5 LS TTL inputs
Control Out W Base+2 C0-C3 4 TTL Open Collector outputs
" " " C4 internal, IRQ enable
" " " C5 internal, Tristate data [PS/2]
Data Feedback R Base+0 D0-D7 matches Data Out
Control Feedbk R Base+2 C0-C3 matches Control Out
" " " C4 internal, IRQ enable readback
The Feedback registers are for diagnostic purposes (except in
bidirectional ports, where Data Feedback is used for data input; and the IRQ
enable C4).
<= in DB25 Cent Name of Reg
=> out pin pin Signal Bit Function Notes
------ ---- ---- -------- ---- -----------------------------
=> 1 1 -Strobe C0- Set Low pulse >0.5 us to send
=> 2 2 Data 0 D0 Set to least significant data
=> 3 3 Data 1 D1 ...
=> 4 4 Data 2 D2 ...
=> 5 5 Data 3 D3 ...
=> 6 6 Data 4 D4 ...
=> 7 7 Data 5 D5 ...
=> 8 8 Data 6 D6 ...
=> 9 9 Data 7 D7 Set to most significant data
<= 10 10 -Ack S6+ IRQ Low Pulse ~ 5 uS, after accept
<= 11 11 +Busy S7- High for Busy/Offline/Error
<= 12 12 +PaperEnd S5+ High for out of paper
<= 13 13 +SelectIn S4+ High for printer selected
=> 14 14 -AutoFd C1- Set Low to autofeed one line
<= 15 32 -Error S3+ Low for Error/Offline/PaperEnd
=> 16 31 -Init C2+ Set Low pulse > 50uS to init
=> 17 36 -Select C3- Set Low to select printer
== 18-25 19-30, Ground
33,17,16
Note: Some cables, ports, or connectors may not connect all grounds.
Centronics pins 19-30 and 33 are "twisted pair return" grounds, while 17 is
"chassis ground" and 16 is "logic ground". "<= In" and "=> Out" are
defined from the viewpoint of the PC, not the printer. The IRQ line (-Ack/S6+)
is positive edge triggered, but only enabled if C4 is 1. Here's the same data
grouped for ease of reference by Control Out and Status In registers and pins.
(Data Out is straightforward in previous table). <= in DB25 Cent Name of Reg => out pin pin Signal Bit Function Notes ------ ---- ---- -------- ---- ------------------------------ => 17 36 -Select C3- Set Low to select printer => 16 31 -Init C2+ Set Low pulse > 50uS to init => 14 14 -AutoFd C1- Set Low to autofeed one line => 1 1 -Strobe C0- Set Low pulse > 0.5 us to send <= 11 11 +Busy S7- High for Busy/Offline/Error <= 10 10 -Ack S6+ IRQ Low Pulse ~ 5 uS, after accept <= 12 12 +PaperEnd S5+ High for out of paper <= 13 13 +SelectIn S4+ High for printer selected <= 15 32 -Error S3+ Low for Error/Offline/PaperEnd
Wait for not +Busy (+Busy low)
Set Data Out bits
at least 0.5 uS delay
Pulse -Strobe low for at least 0.5 uS
hold Data Out for at least 0.5 uS after end of -Strobe pulse
Some time later, printer will pulse -Ack low for at least 5 uS
Printer may lower +Busy when it raises -Ack at end of pulse
Set other Control outputs or check Status inputs as desired.
AH = 0: print the character in AL AH = 1: reinitialize the port, return status in AH AH = 2: return status in AHBIOS operation notes follow.
The BIOS normally keeps the Control register value as 0x0C:
C5 = 0 => output enabled (for bidirectional only)
C4 = 0 => IRQ disabled
C3 = 1 => -Select pin low (Printer Selected)
C2 = 1 => -Init pin high (Printer not being initialized)
C1 = 0 => -AutoFeed pin high (No Auto Feed)
C0 = 0 => -Strobe pin high (No Stobe)
The BIOS prints a character (function AH = 0) as follows:
__________________________________ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | | | | | not used |___ 1 = "Time Out" (software) | | | | |________________ 1 = "I/O Error" (inv C3+; -Error pin low) | | | |____________________ 1 = "Selected" (C4+; +SelectIn pin high) | | |________________________ 1 = "Paper Out" (C5+; +PaperEnd pin high) | |____________________________ 1 = "Acknowledge" (inv C6+; -Ack pin low) |________________________________ 1 = "Not Busy" (C7-; +Busy pin low)The high 5 bits of this are essentially the Status In register from the printer port, with bits 6 and 3 inverted (ie: XORed with 0x48). The low bit is generated by BIOS software after a timeout. In the original PC, timeout delays were generated by delay loops.
Different Parallel Ports on NSC Parts -------------------------------------------------------- PC87311 Bidirectional Parallel Port (16450 UARTS) PC87312 Bidirectional Parallel Port (16550 UARTS) PC87322 Enhanced Parallel Port (EPP) (16550 UARTS)* PC87332 Enhanced Capabilities Port (ECP) also EPP 1.7 and 1.9 (16550 UARTS)* *Floppy controller signals can be redirected out the parallel port pins via an internal multiplexor. This feature is used in some sub-notebooks with external floppy drives
Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D0 2 => 15 S3+ direct
D1 3 => 13 S4+ direct
D2 4 => 12 S5+ direct
D3 5 => 10 S6+ direct
D4 6 => 11 S7- inverted
S7- 11 <= 6 D4 inverted
S6+ 10 <= 5 D3 direct
S5+ 12 <= 4 D2 direct
S4+ 13 <= 3 D1 direct
S3+ 15 <= 2 D0 direct
Gnd 25 === 25 Gnd (ground)
Mode 1B: nibble mode, using Data Out to Status In connection This version
works with all parallel ports; bit positions matched.
Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D3 5 => 15 S3+ direct
D4 6 => 13 S4+ direct
D5 7 => 12 S5+ direct
D6 8 => 10 S6+ direct
D7 9 => 11 S7- inverted
S7- 11 <= 9 D7 inverted
S6+ 10 <= 8 D6 direct
S5+ 12 <= 7 D5 direct
S4+ 13 <= 6 D4 direct
S3+ 15 <= 5 D3 direct
Gnd 25 === 25 Gnd (ground)
Mode 1C: nibble mode, using Data Out to Status In connection; Controls
wired for additional interfaces. This version works with all parallel ports.
Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D3 5 => 15 S3+ direct
D4 6 => 13 S4+ direct
D5 7 => 12 S5+ direct
D6 8 => 10 S6+ direct
D7 9 => 11 S7- inverted
S7- 11 <= 9 D7 inverted
S6+ 10 <= 8 D6 direct
S5+ 12 <= 7 D5 direct
S4+ 13 <= 6 D4 direct
S3+ 15 <= 5 D3 direct
C0- 1 <=>* 1 C0- direct
C1- 14 <=>* 14 C1- direct
C2+ 16 <=>* 16 C2+ direct
C3- 17 <=>* 17 C3- direct
Gnd 25 === 25 Gnd (ground)
* Note: Control Out bits on receiver set high (including inversion, ie:
C0,C1,C3=0; C2=1). Control feedback on receiver can read control out from
sender. Can use some lines each way, and could switch C0 - C2 and C1 - C3 for
symmetry if we want two lines each way, or other variations. Mode 2: 8 bits,
using bidirectional parallel port This version works only with bidirectional
parallel port whose Data Out can be tristated; the receiving side must tristate
its Data Out port to use its feedback register as an 8 bit input port.
Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D0 2 <=>* 2 D0 direct
D1 3 <=>* 3 D1 direct
D2 4 <=>* 4 D2 direct
D3 5 <=>* 5 D3 direct
D4 6 <=>* 6 D4 direct
D5 7 <=>* 7 D5 direct
D6 8 <=>* 8 D6 direct
D7 9 <=>* 9 D7 direct
C0- 1 => 13 S4+ inverted
C1- 14 => 12 S5+ inverted
C2+ 16 => 10 S6+ direct
C3- 17 => 11 S7- direct
S4+ 13 <= 1 C0- inverted
S5+ 12 <= 14 C1- inverted
S6+ 10 <= 16 C2+ direct
S7- 11 <= 17 C3- direct
Gnd 25 === 25 Gnd (ground)
* Note: bidirectional cards only; receiving side must tri-state with C5=1
If a two bidirectional ports are left connected in this fashion, and they are
both enabled (eg: after powerup or reset) with different data outputs, then the
74LS374 driver chips could be "fighting". Just to be careful, when I created a
cable like this (actually, a DB25 jumper box usually sold for RS-232 jumpering,
along with straight through 25 line DB-25 cables), I used 8 10K resistors
between the corresponding Data lines, to limit current in this case. (Actually,
a DIP resistor pack fit perfectly on the PC board inside the DB-25 jumper box).
The resistors are large enough to keep TTL output from overstressing another one
if both enabled, but when one is disabled and the other enabled, the resistors
are low enough to allow the TTL output to drive a TTL input well enough. Mode
3A: 8 bits, using Open Collector Control Outputs as inputs This version uses 4
control outputs as inputs, plus 4 status inputs.
Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D0 2 =>* 1 C0- inverted
D1 3 =>* 14 C1- inverted
D2 4 =>* 16 C2+ direct
D3 5 =>* 17 C3- inverted
D4 6 => 13 S4+ direct
D5 7 => 12 S5+ direct
D6 8 => 10 S6+ direct
D7 9 => 11 S7- inverted
C0- 1 <=* 2 D0 inverted
C1- 14 <=* 3 D1 inverted
C2+ 16 <=* 4 D2 direct
C3- 17 <=* 5 D3 inverted
S4+ 13 <= 6 D4 direct
S5+ 12 <= 7 D5 direct
S6+ 10 <= 8 D6 direct
S7- 11 <= 9 D7 inverted
Gnd 25 === 25 Gnd (ground)
* Note: Control outputs used as inputs must be programmed high: C0, C1, C3
= 0 and C2 = 1 Mode 3B: 8 bits, using Open Collector Control Outputs as inputs
This version uses 3 control outputs as inputs, plus 5 status inputs; remaining
control output is bidirectional - if left high by default, either side can pull
low (remember inverted logic).
Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D0 2 =>* 1 C0- inverted
D1 3 =>* 14 C1- inverted
D2 4 =>* 16 C2+ direct
D3 5 =>* 15 S3+ direct
D4 6 => 13 S4+ direct
D5 7 => 12 S5+ direct
D6 8 => 10 S6+ direct
D7 9 => 11 S7- inverted
C0- 1 <=* 2 D0 inverted
C1- 14 <=* 3 D1 inverted
C2+ 16 <=* 4 D2 direct
S3+ 15 <=* 5 D3 direct
S4+ 13 <= 6 D4 direct
S5+ 12 <= 7 D5 direct
S6+ 10 <= 8 D6 direct
S7- 11 <= 9 D7 inverted
C3- 17 <=> 17 C3- direct (OC shared)
Gnd 25 === 25 Gnd (ground)
* Note: Control outputs used as inputs must be programmed high: C0, C1, C3
= 0 and C2 = 1 [A future version of this document may sketch out the code to
send and receive data through these connections]
Dn Out ------+
|+
Sourcing Load (up to 2.6 mA @ 2.4 v)
|-
Ground ------+
If you have an external +5 volt supply, you have two options: use the Data
Out pins to sink up to 24 mA from your +5 volt supply, or use buffer chips to
control (source or sink) more current (or higher voltages). I have used an
exteranl 5 Volt supply (regulated wall wart) plus optocoupled solid state relays
as the "load", to control AC voltages (keep the high AC voltages away from any
of this logic level stuff, obviously).
+------------------------------- (+5 v)
|+
Sinking Load (up to 24 mA @ 4.2v)
|- Power Supply
Dn Out ------+
Ground -------------------------------------- ( Gnd)
Use limiting resistors if you need to limit the current. If the load were
an LED (or optocoupler) through which you wished to put 20 mA, do the
calculations. The Dn Output will probably be around 0.7 volts, so you have about
4.3 volts of drop; the LED will drop about 1.9 v (check specs!), leaving 2.4 V
to be dropped by a resister at 20 mA: 120 ohms. Test and measure, adjust to fit.
You can also use the Control Out pins. They can't source much of anything (about
1 mA through the 4.7K resistors to +5), and can only sink about 7mA. (The LS TTL
gate actually sinks 8 mA, but one is taken up by the 4.7 K resistor to +5).
Again, check on clones with different electical specs. This can control TTL
inputs fine, and might be able to run an optocoupler or solid state relay in
sink mode (depends on the device). In one application, I used two 74ACT374
latches, which can source 48 mA or sink 64 mA. I connected the 8 inputs of each
to the Data Out, and the latch clocks to two Cn outputs. In software, I put out
8 bits of data on the Data Out port, pulsed a Cn bit to latch it into one
74ACT374, put the next 8 bits out on Data Out, and used the other Cn bit to
latch it into the other 74ACT374 - voila, 16 bits of 64mA output control. Of
course, this took a separate +5 V power supply ($5 surplus regulated wall wart).
If you can still find an old TTL parallel port (especially with sockets), you
can substitute the 74ACT374 chip for the original 74LS374 and get better drive
capability. The back of magazine suppliers were selling *fully socketed* TTL
based parallel ports for about $15 a few years back; by cutting a trace and
soldering a jumper you could make them bidirectional; by plugging in a $1 chip
you could make them source/sink 48/64 mA. You might still find such TTL parallel
port cards in old PCs. Typically, one designed for the original PC will still
work fine on the ISA bus of your 486DX2-66, so don't worry about that.
Cn Out ------+ (Program output high; read feedback)
|
switch
|
Ground ------+
Another simple method would be to use up to 5 pullup resistors (4.7K) from
the Status inputs to +5 volts, and use switches to pull these down to ground.
One disadvantage of this is that it uses an external +5 supply. TTL inputs tend
somewhat to float high, so you *might* get by without the pullup resistors, but
you are pushing it.
4.7K
Sn In -------+-^^^^^--- (+5 v) (Read status register)
|
switch
|
Ground ------+---------- (gnd)
You could use this same scheme for 8 inputs on the data lines of a
bidirectional printer port - but you have to be sure that the outputs are
tristated beforehand, or your switches may damage the 74LS374 (or equiv). This
latter may be a problem after booting or rebooting. One approach is to use
current limiting resistors in series "just in case". You should ideally still
have pullup resistors too. (The 1K value is chosen for LS TTL, to keep the 2.4 V
output at no more than 2.4 mA sourcing).
1K 4.7K
Dn Out --------^^^^^-----+----^^^^^------ (+5v)
|
Switch
|
Ground ------------------+--------------- (Gnd)
10 K
S4 ------------X X X X--^^^^^--+--- (+5)
S5 ------------X X X X--^^^^^--+
S6 ------------X X X X--^^^^^--+ (these pullups optional?)
S7 ------------X X X X--^^^^^--+
| | | |
C3 ------------+ | | | Scan one Cn low at a time, read Sn each time
C2 --------------+ | |
C1 ----------------+ |
C0 ------------------+
Alternate scheme. Use Dn's for scanning output rows, through diodes which
will isolate them from each other if two keys in the same column are pressed.
(Otherwise we have drivers fighting, and indeterminate voltage levels).
Germanium small signal diodes have less voltage drop. Use the Cn pins as inputs
(with existing pullups) - program Control Out for high TTL levels, and read the
feedback register for input (counting inversions). No extra power supply is
needed. The diode between TTL output low and TTL input low will push the TTL
noise margins, but you can usually get by with it. This scheme could be expanded
up to 8x4 (8 Dn outputs, 4 Cn used as inputs). If we know that only one key (or
one key per column) will be pressed at a time, the diodes can be omitted.
1N914
D0 ----|<|-----X X X X (Set all Cn high),
D1 ----|<|-----X X X X Scan one Dn low at a time, read all Cn
D2 ----|<|-----X X X X
D3 ----|<|-----X X X X
| | | |
C3 ------------+ | | |
C2 --------------+ | |
C1 ----------------+ |
C0 ------------------+
Note that if we press three switches in the matrix which form 3 corners of
a box, it will appear as if all 4 corners are pressed; this is true of any such
matrix, unless each switch has its own diode. I hope to have some results to
share in a later revision of this doc.
+5 +5
/ \
---H / external resistor
\ \
|_____ ___________/
| out | out
/ /
---L ---L
\ \
Gnd Gnd
Totem Pole Open Collector
Regular TTL outputs basically consist of a two "stacked" transistor in
series between +5 volts and ground, with the output coming from the connection
between them. This is called a "totem pole output". At any given time one of
these transistors is conducting and the other is not. To pull the output "high",
the transistor from +5 to the output conducts (H), which "sources" positive
current from the output to ground (that is, an external device between the
output and ground will get power). To pull the output low, only the lower
transistor (L) conducts, "sinking" current to ground; an external device between
+5 volts and the output can be energized. Current flows into the chip for low,
out of it for high.
+5
/ |
---H on V
\ -->
|________ TTL output on = 1 = high, "sourcing" current
| out \
/ / |
---L off \ V
\_________/
Gnd
+5_________
/ \
---H off / |
\ \ V
|________/ TTL output off = 0 = low, "sinking" current
| <-- out
/
---L on |
\ V
Gnd
The 0 / pull low current capacity (sinking) is larger than the 1 / pull
high capacity (sourcing). If you want to drive something like an LED, or a solid
state relay, you can get more current from the TTL outputs by connecting it
between +5 and the gate output (second picture) - *if* it's electrically
isolated from ground. You still have to check the current and voltage ratings,
tho. One key here is that the chip is always trying to pull either high or low,
and the currently conducting transistor has voltage and current limits, beyond
which it can be damaged. It is not good design to connect two such outputs which
may have different states - one pulling high and one low - because this will
exceed the current specs. However, if you do, the one pulling low will "win",
since TTL can sink (pull low) more strongly than it can source (pull high). And
there is some slack in the specs, so this does not always immediately damage the
chip; we'll get back to this. These are the type of outputs on the DATA lines on
the original IBM parallel port. (Well, not exactly, but I'll get back to that
too). Another type of output is the "open collector". In this case, there is a
transistor from the output pin to ground, but none to +5 volts. The two states
are 0, "conducting to ground" (pulling low), and 1, "not conducting" (floating,
not pulled either way). Externally, you can connect a resistor of proper value
between the line and +5 volts to pull the line high when the chip output is
floating. The value is chosen such that when the output is conducting to ground,
it overpowers the external resistor and the line goes low. The advantage of this
scheme is that you can connect multiple open collector outputs together (or even
slip in one totem pole). Every output that is floating is ignored (and the
resistor will pull the line high if and only if all outputs are floating);
multiple outputs pulling low cause no conflict. This is the type of output used
for CONTROL lines in the original IBM parallel port. Since each parallel port
control output line has a corresponding feedback bit that can be read (mainly
for diagnostics, to see if the line really goes high or low), it is possible to
program these CONTROL outputs "high" (really floating), and then allow external
signals control the high or low state of the line. An external open collector
output, or a totem pole one, is capable of pulling the line high (reinforcing
the pullup resistor) or low (overpowring it) without exceeding current specs. In
this way you can use the control lines as inputs. If there is no external
signal, it will read high. However, you must program the CONTROL outputs high
(taking into account any logical inversions between the register bits and the
electrical outputs); if the open collector output is low (conducting to ground),
the external signal won't be able to pull it high (or at least not without
exceeding the specs). The same thing can be done with totem pole outputs -
program them high, and let external logic pull them high (no problem, both
pulling up) or low (overpowering the attempt to pull high), but in this case you
are overloading the H transistor, rather than a pullup resistor, and exceeding
spec, with possible unreliability or damage. However, this has been successfully
done with the data outputs of a conventional parallel port, and some people
claim not to have seen any damage yet. Don't blame me if you do it and something
dies. A third type of gate is a totem pole in which both high and low
transistors can be non-conducting at once, creating a third, floating state
(this is often called a tri-state output). When it is in this third state, the
line is not being pulled high nor low by this device, and thus can be safely
controlled by some other device. No pullup resistor is used. The 74LS374 chip
used for the standard parallel port DATA outputs actually has tristate ability,
but as described elsewhere the third state is not used, and it is always trying
to pull high or low - thus my initial description of the DATA lines as totem
pole drivers. The way true bidirectional parallel ports work is to allow the
software to selectively put the DATA outputs into the third, undriven state.
Then you can use the data feedback register to read whatever highs or lows are
put onto the data lines externally. Non-TTL logic, like CMOS, has the
equivalents of these, but with a different type of transistor, and different
voltage and current values. If your parallel port uses a single chip or
otherwise differs from the original IBM parallel port, the above electrical
description cannot be guaranteed, but it is probably pretty analogous. Let me
know if you have specific knowledge about the electical specs of your single
chip parallel port, for future versions of this document. Note again that high
and low in this description are electrical levels, as would me measured by a
voltmeter on the pins; high is associated with TTL logic 1, but whether a given
CONTROL output line is high when the corresponding register bit is 1 or 0 varies
with the line, as is described elsewhere in this document. The DATA lines are
straight through, with no inversions, so a 1 bit produces a high output.