Subject: Re: interrupting parallel port lossage
To: None <bakul@netcom.com, bde@zeta.org.au>
From: Bruce Evans <bde@zeta.org.au>
List: port-i386
Date: 03/23/1995 21:43:39
>> Some printers raise *ACK before lowering BUSY.  This isn't related to
>> the current problem, but causes very slow printing if the interrupt
>> handler gets control while BUSY is still low.

>Then they are violating the Centronics interface.  After a

I should have said `assert *ACK' ...

>Then they are violating the Centronics interface.  After a
>long search I found at least a timing diagram in the good
>old Art of Electronics, Second ed.  (page 731)  That might
>be of some help:

Thanks!  I don't have a really good reference for this, and
don't trust any.  Isn't Centronics only slightly more standard
than RS232?

>			    A  B  C  D
>			     ________                    _ _ _ _ _
>	DATA    ------------<________>------S S---------<_ _ _ _ _
>		_______________    _________   ____________
>	*STROBE                \__/         S S            \_
>				  __________   _________
>	BUSY    _________________/          S S         \________
>		____________________________   ____         ____
>	*ACK                                S S    \_______/
>						   E    F   G

>A->B == DATA out to *STROBE low time = 0.5 us min.
>B->C == *STROBE low to *STROBE high time = 0.5 us min.
>C->D == *STROBE high to DATA tri-state == 0.5 us min.

Do you think the software needs to delay for C->D?  I don't think so.
If it returns from an interrupt handler, a relatively huge delay is hard
to avoid.  If it polls BUSY and/or *ACK, it should see valid states
because these signals are already stable enough.

>E->F == *ACK low to BUSY low == 7 us min.
>F->G == BUSY low to *ACK high = 5 us min.

This is worse than I thought.  I thought F <= E for "good" printers.
Many printer manuals hint that F == E (approximately) but don't specify
exact enough timing.  The PC interface has the interrupt line connected
to **ACK, so the interrupt is acknowledged soon after *ACK is asserted
(if interrupts are enabled; there is another problem here with the
shortness of the F->G strobe.  Many U*ix's _often_ disable interrupts
for _much_ longer than 5us.  Timeouts are required to recover from lost
interrupts).  Fast x86 systems probably reach the interrupt handler in
less than 7us and see *BUSY still asserted.  Waiting a long time for it
to become asserted is not acceptable.  However, waiting only 7us is
probably acceptable.  Perhaps the "good" printers bend the spec so that
the PC interface works better.

Does the software have to worry about *ACK?  I think only *BUSY matters
for sending data to the printer, and *ACK is specified so that
interrupts and hardware latches can work.

>Notice that BUSY must be _low_ before outputting the DATA
>and must go =high= some time soon after *STROBE goes low.

>So one more thing the driver can do is check that BUSY is
>really low *before* outputting and right after setting
>*STROBE low, check BUSY goes high (via a timed loop;
>breakout after 5 us or BUSY hight).

This only works if you disable interrupts and the cpu is
sufficiently fast.  Otherwise an interrupt or cpu slowness
may add an unknown amount of time to the 5 us and *BUSY
may go up and down while you're not looking.  Disabling
interrupts isn't nice and depending on particular cpu and
hardware speeds is the cause of half the problems that we
are discussing.

>To guard against errant printers, lptintr() should check
>BUSY is low in a timed loop (breakout 5 us or BUSY low).
>Normal printers won't cause any slow down.

I think such checks should be left to a special test mode.
It would be convenient to run them when the system boots,
but you can't even rely on the printer to be turned on at
boot time.

>I also noticed that the printer is never reset.  Normally I

I think it is reset at boot time (if it is turned on :-).

Bruce