Home     Interfacing     Software     About     Sitemap   
 EN   NL   
Quick links

RS232 I/O and IRQ’s

I/O and IRQ’s, introduction

Serial communication is performed by writing output-, and reading input registers on a UART. A UART (universal asynchronous receiver / transmitter) is an IC capable of converting parallel information to serial data, transmitting it over a line and receiving it on the other end where the data is translated back to parallel again.

The UART registers are on PC compatible computers available as I/O ports starting at a specified port number. A UART is capable of calling attention of the running software by generating a processor interrupt. In that way, it is not necessary to check continuously the state of the serial communication device in a communication program.

PC I/O and IRQ use

On PC’s the register set of a UART is mapped in the I/O map of the processor. The twelve registers of the UART are accessible with 8 I/O bytes. To achieve this, read-only and write only registers are accessible using to the same PC I/O port when possible. In two situations, a bit (the divisor latch access bit) in one register is used to swap different registers on a specific port.

Four serial communication devices have been predefined on a PC. The UARTs for these devices have default addresses assigned on which its registers are accessible. The devices are named COM1 through COM4. A default interrupt line number is also assigned to each device. Because only a few IRQ lines are available on PC systems, only two interrupt lines are used for four devices. The software must have the intelligence to detect which UART needs attention when an interrupt occurs if more than one UART share the same interrupt.

DeviceI/O address rangeIRQ
COM10x3F8 – 0x3FF4
COM20x2F8 – 0x2FF3
COM30x3E8 – 0x3EF4
COM40x2E8 – 0x2EF3
Default I/O addresses and IRQ’s on a PC system

Please note that the table lists only the default I/O addresses on IBM XT and AT compatible systems. On a PS2 system, other addresses are used. These values are only recommendations. If other hardware present in the computer makes it necessary, it is possible to move an UART to another I/O address or IRQ.

The actual I/O addresses used are stored in a table in the BIOS data area. This table starts at memory address 0000:0400 and contains important device information. Unfortunately, only the I/O port addresses of each UART is stored. No information is present about the IRQ used by a specific UART. This makes the table only partially useful for identifying the serial ports.

Segmented memory addressValue
0000:0400COM1 base I/O port
0000:0402COM2 base I/O port
0000:0404COM3 base I/O port
0000:0406COM4 base I/O port
I/O addresses in the BIOS data area

Register to port conversion map

As said, eight I/O bytes are needed for each UART to access its registers. The following table shows, where each register can be found. The base address used in the table is the lowest I/O port number assigned. The switch bit DLAB can be found in the line control register LCR as bit 7 at I/O address base + 3.

I/O portRead (DLAB=0)Write (DLAB=0)Read (DLAB=1)Write (DLAB=1)
baseRBR receiver bufferTHR transmitter holdingDLL divisor latch LSBDLL divisor latch LSB
base+1IER interrupt enableIER interrupt enableDLM divisor latch MSBDLM divisor latch MSB
base+2IIR interrupt identificationFCR FIFO controlIIR interrupt identificationFCR FIFO control
base+3LCR line controlLCR line controlLCR line controlLCR line control
base+4MCR modem controlMCR modem controlMCR modem controlMCR modem control
base+5LSR line statusfactory testLSR line statusfactory test
base+6MSR modem statusnot usedMSR modem statusnot used
base+7SCR scratchSCR scratchSCR scratchSCR scratch
UART register to port conversion table

For a description of each individual register:
RBR, THR, IER, IIR, FCR, LCR, MCR, LSR, MSR, SCR, DLL, DLM.

Using interrupts on a PC

The interrupt mechanism present on PC’s is controlled by an interrupt management chip, the programmable interrupt controller PIC. The chip used on XT’s is a 8259A device capable of handling 8 hardware interrupts. When an interrupt occurs on one of the input lines, the processor’s INTR line is activated by the PIC. The PIC is responsible of handling the priority when two or more interrupts occur at nearly the same time.

To be able to use more hardware in combination with the computer, a second interrupt controller was added to the AT compatible systems. To make this work, the secondary controller uses one interrupt line on the existing one. This means that in the AT configuration, only 7 interrupt lines on the first controller can be used and 8 on the second. This makes a total of 15 possible hardware interrupts which is enough for most situations. To stay backward compatible with older applications, the hardware line of IRQ 2 on XT systems was redirected to IRQ 9 on the second. BIOS then redirects a hardware interrupt on line 9 to the handler of IRQ 2. In this way, the interrupt service routine present for IRQ 2 is called, even if the occurring interrupt is the IRQ 9.

The primary PIC is accessible at I/O port 0x20 and 0x21, the secondary at 0xA0 and 0xA1. These ports must be used for two different reasons by an application accessing hardware using interrupts. One is, that the PIC must be told that an interrupt on a specific line may be honored and sent to the processor. The other use is to reset the interrupt when the software has finished performing all necessary actions.

Priority can be an important issue when performing serial communications. The amount of interrupts occurring when communicating can be pretty high. If no buffering is used, each single incoming byte will be announced by a trigger signal on the interrupt line. When buffering is present (as on most UARTs used today) this will decrease to about one interrupt every fourteen bytes. Still a high amount of interrupts compared to the number of information coming in. This number will double, when also interrupt driven sending is used, not even mentioning the interrupts when modem signals are checked using interrupts.

Interrupt service routines

The piece of software started when an interrupt occurs is called an interrupt service routine, or ISR. BIOS maintains a table of the
starting address of all possible routines in the address range 0000:0000 to 0000:0400. A total of 256 routines are available (most are called by software only). Default, the hardware interrupts are redirected by this table to a small BIOS routine which clears the interrupt and then exits. To make your software interrupt aware, this default routine must be replaced by your own software.

Changing the address of an ISR can be done by changing bytes directly on the memory location in the table, or better, using a DOS software interrupt designed for it. Please refer to your compiler documentation what’s the best way to do this. The following table shows the offset in the table of the hardware interrupts.

Hardware interruptSoftware interruptDefault use
00x08Clock
10x09Keyboard
20x0ASecondary PIC cascade
30x0BCOM2 and COM4
40x0CCOM1 and COM3
50x0DLPT2 / harddisk on the XT
60x0EFloppy disk
70x0FLPT1
80x70Real time clock
90x71Generates software interrupt 0x0A
100x72
110x73
120x74
130x75Mathematic co-processor
140x76IDE harddisk
150x77
ISR number for each hardware interrupt

The appropriate table entry must contain the segmented starting address of the function in the application program handling the interrupts. This function must end with a call to the IRET function. This means, that a normal function inside your program cannot be used as an interrupt service routine. In C/C++ for example, the keyword interrupt must be used in front of the function declaration to generate the necessary assembly instructions for this. Refer to your own compiler manual for details.

When an interrupt occurs, the software must check the IIR interrupt identification register to see which event caused the interrupt to occur. If more than one UART share the same IRQ level, be sure to check the IIR register of all the UARTs used in your application program with the same IRQ. See the programming examples for details.

The priority scheme

The PIC maintains a priority scheme, where lower IRQ numbers have a higher priority than the higher ones. It honors new interrupts when the processor is busy processing another one, as long as the IRQ number of the new interrupt is lower than the currently occurring one. Therefore, playing around with the interrupt numbers assigned to different devices in your computer can decrease or increase the maximum allowed speed of serial communications. Be aware, that the system assumes most hardware to exist on a particular interrupt level, so look out what you are doing. Changing the interrupt level of hard-disks, floppy drives etc. is not a good idea in general, but changing the interrupt level of a network card may produce good results.

Enabling interrupts

An interrupt is not occurring, unless the PIC is told that it is allowed to pass an interrupt through. This means, that the PIC must be programmed to allow an UART to perform interrupt driven communication. For this reason, the PIC’s interrupt mask register IMR can be used. This register is present at I/O port 0x21 for the first, and 0xA1 for the second PIC controller.

The eight bits of the IMR mask register each control the behaviour of one interrupt line. If a bit is set to zero, the accompanying interrupt will be passed through to the processor. The IRQ 2 is a somewhat special case on AT class computers. To make this interrupt occur, both the IRQ 2 and IRQ 9 bits must be cleared on AT computers. the IRQ 2 bit will already be cleared in most circumstances to let other interrupts on the secondary PIC occur. The bit of IRQ 9 must also be cleared, which is not compatible with the original way of enabling the IRQ 2 on a XT computer.

Because of this difference with the XT computer, older software written for the XT and using IRQ 2 won’t be able to use this IRQ. Designers tried to make the AT PIC configuration as compatible as possible by redirecting to IRQ 2, adding extra’s to the BIOS software etc, but they forgot this little IMR register which controls the visibility of the interrupt to the
software.

Changing the IMR is easy. First read in the byte on I/O address 0x21 or 0xA1, using the function present in assembly or in your compiler. Then clear the bit and write the information back to the same location. Be sure to set the same bit when exiting the application. Otherwise, when new characters are received on the line when the application is not working anymore, the PIC will trigger the software interrupt routine on your machine which may lead to strange behaviour of the computer, including a complete crash.

The most important situation that must be taken care of is pressing the Ctrl-C button. In most applications, pressing this key will stop the program immediately, without restoring the IMR state, and even more important, the interrupt service routine address. The interrupt service routine is the function called when an interrupt occurs. This is a piece of software inside your application, but when the program is exited, other code will be present on the same memory location. If the interrupt service routine starting address is not changed in the BIOS table, the BIOS will still perform a call to the same memory location when an interrupt occurs after the program has exited. Should I explain further?

Acknowledging interrupts

The PIC will prevent new interrupts of the same or lower priority, as long as the software has not finished processing the previous one. This means, that the software must signal the PIC that new interrupts may occur, otherwise the computer will eventually hang.

Clearing the interrupt state of the PIC can be done by writing a non-specific end of interrupt command to the PIC’s register available at address 0x20 for the first, and 0xA0 for the second controller. This command consists of the byte value 0x20. If an interrupt has occurred on the second PIC, it is not necessary to reset both the state of the first and the second controller. Only the second controller needs an end of interrupt command. The BIOS has already cleared the state on the first controller before calling the interrupt service routine.

Complex problems have simple, easy-to-understand wrong answers.
GROSSMAN'S MISQUOTE OF H.L.MENCKEN
  Aug. 2021
   Copyright © 1997-2021 Lammert Bies, All rights reserved