Parallel Port Miscellanyby Charles Lepple
Parallel port documentation for IBM PC compatibles can be inconsistent. Most sources quote other sources, and little information is based on first-hand experience. This document is meant to remedy this shortfall.
The PC parallel port outputs TTL-compatible logic signals, although in most computers, the signal levels are much closer to 5 volts than ordinary TTL circuits generate.
There are five basic types of parallel ports: standard, PS/2, bidirectional, EPP and ECP. My personal experience so far has only been with the standard and bidirectional parallel ports, although I may be able to provide some EPP data in the future. The IEEE-1284 standard, which covers all of the common parallel port de facto standards, recommends that the EPP and ECP be backwards compatible with legacy hardware, so enhancements will not conflict with predefined functionality. The difference is that the standard port provides eleven outputs and five inputs (a state which caters towards output-only devices such as parallel printers), where the enhanced parallel ports (EPP) provide an eight-bit wide bidirectional data path, plus some enhancements associated with bidirectional communication. The ECP is in a class of its own, providing protocols for multiple devices, ultra-fast and efficient transmission with compression, et cetra.
The connector on the back of the computer is a male 25 pin job. You need a female 25 pin connector to interface. You can use an IDC connector (crimps onto ribbon cable), or you can be sensible and get some wire and solder it to a DB-25F connector (<$3 at Radio Shack). I find that UTP wire (4 twisted pairs, approx. 28 gauge) works nicely. You will need several doubled lengths, fastened at regular intervals.
|Pins on DB-25 on computer side|
These pins have special meaning if you are planning to use the port through special interfaces such as the BIOS or your OS's printer devices. Usually, one uses direct port output and ignores the services tailored to printer-type devices (unless, of course, you are building a printer-like device).
In the names above, a leading asterisk denotes a signal which the printer interprets as "active low".
In case you're interested, here are the meanings of the signal names. "*Strobe" is the signal which indicates to the printer that the data is valid. "*Ack" is acknowledge, "Busy" is obvious, "PE" indicates a "paper empty" condition, "Select" (the incoming signal) would normally mirror the "online" light on a printer, indicating that the printer is ready, "*Select" goes high to prevent a printer from acting on data, but printers usually have a dip switch to override this signal. "*AutoFd" has to do with whether a line feed is added after a carriage return, "*Fault" indicates a general error, "*Error" is obvious, and "*Init" resets the printer.
Port address assignments are a bit unusual. The BIOS searches in a predetermined order, and assigns numbers (in the range 0-2 in a usual setup) only to ports which exist. Restated, if you have a port at 0x3BC and a port at 0x278, they are numbered 0 and 1 respectively, regardless of the fact that there is no port at 0x378 (which is usually assigned 0 or 1, depending on the existence of a port at address 0x3BC). DOS device names are formed by appending the BIOS number, plus one, to "LPT". LPT1 is also designated "PRN" for convenience.
The rationale is this: address 0x3BC is reserved for parallel ports integrated into the motherboard or on a display adapter (usually only on obselete ones such as the Hercules Graphics Card or IBM's veritable Monochrome Display Adapter). Multifunction add-on boards usually use the next two sets of addresses.
If you program for an operating system which allows access to the BIOS data tables (ie DOS, or a DOS emulator), you can examine memory at segment 0x40, offsets 0x8, 0xA and 0xC, which are hex words with the base port addresses of BIOS printers numbers 0, 1 and 2 respectively.
To test if the port exists, write a zero to the first address given. If it returns zero, you might have a parallel port. If it returns anything else, you either don't have a parallel port at that address, or it is too broken to use. A hex value of "FF" usually means that you've got a wrong number and nobody lives there. This is because the TTL buffers used on the address busses interpret a lack of a device as a "high" value (hence 0xFF, or all high bits).
These are the pins controlled by the three port locations. The "base" value is the first port listed in the list above.
|Dir.||bit 7||bit 6||bit 5||bit 4||bit 3||bit 2||bit 1||bit 0|
Where "n/c" stands for "no connection" and "I.E." stands for "interrupt enable". The interrupt occurs on the negative-going transition of the *Ack pin if bit 5 of (base+2) is on. The interrupt number is the IRQ number plus 8, and the IRQ is listed in the table above.
When you read from (base+0), you get either zero or what you wrote before, depending on the port. When you read from (base+2), you usually get what you wrote before. In any case, the output bits are all latched, and the input bits are not debounced. To keep track of the status of the output ports, keep their values in global variables in your program. This way, you do not need to read the ports (which might return zero on some machines) to find what has been latched at the outputs.
Here are some miscellaneous points to keep in mind.
- You need an external power supply. Your computer would prefer it to be in the vicinity of 5 volts.
- Use buffers so as not to damage the port. Some buffers are more sensible than others. For instance, the 74LS54x series has inputs on one side, and outputs on the other. The LS540 inverts, and the LS541 does not.
- Nothing is better than experimentation. Intelligent
experimentation is more effective, though. Be a rebel and use
DEBUG in DOS, or write a PERL script to write to
/dev/portdevice in Linux.
- If you do use an advanced operating system such as Linux or a flavor of BSD, there are calls to allow access to ports and also to access the ports individually. However, direct port access in a multi-user O/S usually requires superuser priveledges, and as such is a possible security hole. Write a device driver, using the printer driver as an example. For instance, in Linux, one need only to make the "lp" driver a module, and then recompile and insert it into the kernel while it is running. This allows for easier development when you do not have root access to try a standalone program.
- Update: You may want to check out Tim Waugh's
as a nice structured alternative to directly frobbing
/dev/portor other such silliness. I no longer use a PC as my primary desktop machine, so I have not tried this library myself. YMMV.
- Svein Erlang Seldal has written a kernel driver to talk to TI TMS320C31 DSKs over the parallel port. You may wish to take a look at his code. The home page is here.
Extended features of the EPP
The EPP uses eight control ports as opposed to the three ports used by standard parallel ports. The first three are the same as those used by the standard port, and the next is used as an address port to send a device address out over the port. The next four ports can be written to as a double-word, word or byte port, and the port's driver chip sends four, two or one bytes with corresponding strobe signals. This allows for much faster transfer than if the program must manually pulse *Strobe low then high after every character. Unfortunately, there is very little documentation available for this version. Maybe next time.