[comp.sys.ibm.pc] HELP! Interrupts on COM ports

franke@rwthinf.UUCP (Christian Franke) (07/18/89)

I've written a interrupt driver for the COM{12} ports of an AT.
If the receiver side uses interrupts and the transmitter side uses polling,
everything is OK.
If the transmitter uses interrupts also, the following problem occurs:

When the transmitter and the receiver interrupts occur simultaneously, then
sometimes the transmitter interrupt is lost: The IIR register of the
8250 does not report "Transmitter empty interrupt" after the
"Receiver data available interrupt" has been processed.
Both (8250 internal) interrupts should occur during the same hardware
interrupt cycle of the 8259.
After this situation, the LSR of the 8250 correctly reports 
"transmitter ready" (bit 5).

Is that a problem with the edge-sensitive mode of the 8259? 

Here is a fragment of the interrupt routine (MS-C 5.1):

--------------------------------------
/*	8250 Communikations Controller Port Offsets			*/
#define THR	0xf8	/* Transmitter holding register		w/o	*/
#define RBR	0xf8	/* Receiver buffer register		r/o	*/
#define IER	0xf9	/* Interrupt enable register			*/
#define IIR	0xfa	/* Interrupt identification register		*/
#define LCR	0xfb	/* Line control register			*/
#define MCR	0xfc	/* Modem control register			*/
#define LSR	0xfd	/* Line status register				*/
#define MSR	0xfe	/* Modem status register			*/

/*	8259 Interrupt Controller Port Numbers				*/
#define ICC	0x20	/* Control word register			*/
#define ICM	0x21	/* Interrupt mask register			*/

#define COMx	0x0300	/* Port base address				*/
#define IRQx	4	/* Hardware interrupt number			*/

/*
	COM interrupt handler routine
*/	

static void interrupt far ComIntHandler(void)
{
    register unsigned char ch;
	/* Determine interrupt source */
	for (;;) switch (inp(COMx+IIR)) {
	    case 0x6:
	    	/*
		 * Receiver line status interrupt
		 */
		ch = inp(COMx+LSR); /* get status, clear interrupt */
		/* .... */
	    	break;
		
	    case 0x4:
	    	/*
		 * Receiver data available interrupt
		 */
		ch = inp(COMx+RBR); /* get character, clear interrupt */
		/* ... queue data ... */
	    	break;
		
	    case 0x2:
	    	/*
		 * Transmitter empty interrupt
		 * (interrupt cleared by read of IIR)
		 */
		if (/* Data available in queue */)
		 	/* Send next character from queue */
		 	outp(COMx+THR,/* Next char in queue */);
	    	break;

	    case 0x0:
	    	/*
		 * Modem status interrupt
		 */
		ch = inp(COMx+MSR); /* get status, clear interrupt */
		/* ... */
	    	break;

	 /* case 0x1: */
	    default:
	    	/*
		 * No interrupt from COM port
		 */
		outp(ICC,0x20); /* Say 8259: End of Interrupt */
		return;
	}
	/*NOTREACHED*/
}
------------------------------

Perhaps someone can help me.

Thanks in advance

	Christian Franke

	Aachen University of Technology
	Lehrstuhl fuer Informatik I
	Ahornstrasse 55
	D-5100 Aachen
	Federal Republic of Germany
	Tel.: 0241 / 80-3586

	UUCP: franke@rwthinf.uucp ({...mcvax}!unido!rwthinf!franke)

news@crdgw1.crd.ge.com (USENET News System) (07/18/89)

If the receiver side uses interrupts and the transmitter side uses polling,
everything is OK.
If the transmitter uses interrupts also, the following problem occurs:
From: dixon@sagittarius.crd.ge.com (walt dixon)
Path: sagittarius!dixon

>When the transmitter and the receiver interrupts occur simultaneously, then
>sometimes the transmitter interrupt is lost: The IIR register of the
>8250 does not report "Transmitter empty interrupt" after the
>"Receiver data available interrupt" has been processed.
>Both (8250 internal) interrupts should occur during the same hardware
>interrupt cycle of the 8259.
>After this situation, the LSR of the 8250 correctly reports
>"transmitter ready" (bit 5).
>
>Is that a problem with the edge-sensitive mode of the 8259?

This is a common mistake in dealing with the 8250.  The documentation
is not particularly clear,  so one must read between the lines.  Your
interrupt service routine must loop on the interrupt pending bit.  So
long as this bit is clear,  read the IIR and determine the interrupt source.
When the bit goes high,  send an EOI to the 8259 to clear the interrupt.

Walt Dixon		{arpa:		dixon@crd.ge.com	}
			{us mail:	ge crd			}
			{		po box 8		}
			{		schenectady,  ny 12345	}
			{phone:		518-387-5798		}

Walt Dixon dixon@crd.ge.com

franke@rwthinf.UUCP (Christian Franke) (07/26/89)

In article <1240@crdgw1.crd.ge.com>, news@crdgw1.crd.ge.com (USENET News System) writes:
> 
> This is a common mistake in dealing with the 8250.  The documentation
> is not particularly clear,  so one must read between the lines.  Your
> interrupt service routine must loop on the interrupt pending bit.  So
> long as this bit is clear,  read the IIR and determine the interrupt source.
> When the bit goes high,  send an EOI to the 8259 to clear the interrupt.
> 
> Walt Dixon		{arpa:		dixon@crd.ge.com	}
> 			{us mail:	ge crd			}
> 			{		po box 8		}
> 			{		schenectady,  ny 12345	}
> 			{phone:		518-387-5798		}
> 
> Walt Dixon dixon@crd.ge.com

Which "interrupt pending" bit do you mean? 
Bit 5 of LSR, bit 0 of IIR or a bit in the 8259?


	Christian Franke

	Aachen University of Technology
	Lehrstuhl fuer Informatik I
	Ahornstrasse 55
	D-5100 Aachen
	Federal Republic of Germany
	Tel.: 0241 / 80-3586

	UUCP: franke@rwthinf.uucp ({...mcvax}!unido!rwthinf!franke)

franke@rwthinf.UUCP (Christian Franke) (07/31/89)

In article <1137@rwthinf.UUCP>, I [franke@rwthinf.UUCP (Christian Franke)]
wrote:
> 
> I've written a interrupt driver for the COM{12} ports of an AT.
> If the receiver side uses interrupts and the transmitter side uses polling,
> everything is OK.
> If the transmitter uses interrupts also, the following problem occurs:
> 
> When the transmitter and the receiver interrupts occur simultaneously, then
> sometimes the transmitter interrupt is lost: The IIR register of the
> 8250 does not report "Transmitter empty interrupt" after the
> "Receiver data available interrupt" has been processed.
> Both (8250 internal) interrupts should occur during the same hardware
> interrupt cycle of the 8259.
> After this situation, the LSR of the 8250 correctly reports 
> "transmitter ready" (bit 5).
> 
> [remaining stuff deleted]
>

Thanks to all who answered. I've found the solution last week.

The behaviour seems to be a problem in some COM12/LPT12 cards from 
taiwan. These cards don't have a real 8250 for serial i/o 
but a custom chip named CTC83747 for serial and parallel i/o.
I could not reproduce the error with our V24/V11 card, which has
a fast 8250 (up to 115200 baud) on it.

With a special test routine, I was able to trace the error:
The following situation occurs sometimes when transmitter & receiver
interrupt occur nearly simultaneously: 


	Action		Data		Comment
=========================================================================
ComInterrupt:				Start of interrupt routine
	Read LSR	**0****1	Transmitter busy, receiver ready
	Read IIR	****0100	Receiver Interrupt (ok)
	Read RBR	********	Received character read (ok)
	Read LSR	**1****0	Transmitter changed to ready
	Read IIR	****0000	Modem status interrupt (disabled!)
					should be ****0010 !
	Read MSR	****0000	No modem status changes !
	Read IIR	****0001	No interrupt pending now,
					transmitter interrupt lost.
	Write ICC	00100000	Say 8259: EOI 
	RTI				End of interrupt routine

The LSR reads are not necessary to reproduce this error.
The IER is set to 00000011 (only transmitter & receiver interrupt enabled).
The error does not depend on the baud rate (checked with 300-19200 Baud).

In order to overcome this problem, it is necessary to loop on the
Transmitter Empty bit in the LSR when the IIR says "No interrupt".


Regards,

	Christian Franke

	Aachen University of Technology
	Lehrstuhl fuer Informatik I
	Ahornstrasse 55
	D-5100 Aachen
	Federal Republic of Germany
	Tel.: 0241 / 80-3586

	UUCP: franke@rwthinf.uucp ({...mcvax}!unido!rwthinf!franke)