RS232 I/O and IRQ’s
- I/O and IRQ’s, introduction
- PC I/O and IRQ use
- Register to port conversion map
- Using interrupts on a PC
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.
Device | I/O address range | IRQ |
---|---|---|
COM1 | 0x3F8 – 0x3FF | 4 |
COM2 | 0x2F8 – 0x2FF | 3 |
COM3 | 0x3E8 – 0x3EF | 4 |
COM4 | 0x2E8 – 0x2EF | 3 |
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 address | Value |
---|---|
0000:0400 | COM1 base I/O port |
0000:0402 | COM2 base I/O port |
0000:0404 | COM3 base I/O port |
0000:0406 | COM4 base I/O port |
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 port | Read (DLAB=0) | Write (DLAB=0) | Read (DLAB=1) | Write (DLAB=1) |
---|---|---|---|---|
base | RBR receiver buffer | THR transmitter holding | DLL divisor latch LSB | DLL divisor latch LSB |
base+1 | IER interrupt enable | IER interrupt enable | DLM divisor latch MSB | DLM divisor latch MSB |
base+2 | IIR interrupt identification | FCR FIFO control | IIR interrupt identification | FCR FIFO control |
base+3 | LCR line control | LCR line control | LCR line control | LCR line control |
base+4 | MCR modem control | MCR modem control | MCR modem control | MCR modem control |
base+5 | LSR line status | factory test | LSR line status | factory test |
base+6 | MSR modem status | not used | MSR modem status | not used |
base+7 | SCR scratch | SCR scratch | SCR scratch | SCR scratch |
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 interrupt | Software interrupt | Default use |
---|---|---|
0 | 0x08 | Clock |
1 | 0x09 | Keyboard |
2 | 0x0A | Secondary PIC cascade |
3 | 0x0B | COM2 and COM4 |
4 | 0x0C | COM1 and COM3 |
5 | 0x0D | LPT2 / harddisk on the XT |
6 | 0x0E | Floppy disk |
7 | 0x0F | LPT1 |
8 | 0x70 | Real time clock |
9 | 0x71 | Generates software interrupt 0x0A |
10 | 0x72 | – |
11 | 0x73 | – |
12 | 0x74 | – |
13 | 0x75 | Mathematic co-processor |
14 | 0x76 | IDE harddisk |
15 | 0x77 | – |
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.
At any rate, I am convinced
that He [God] does not play dice. ALBERT EINSTEIN
|