One of a microcontroller's primary functions is to provide real-time signals to a device in order to maintain control over a system. In an automobile, for example, a microcontroller may generate the signals to actuate the anti-lock braking device to stop the car when the brake pedal is depressed. In order to process and generate such real-time signals, a microcontroller relies heavily on its interrupt subsystem.
When the central processing unit of a microcontroller is executing code, an internal peripheral or external device may request assistance from the processor, or in other words, interrupt the processor. Typically, the processor responds by halting execution of the next instruction and servicing the device that requested the interrupt. Upon completion of the interrupt service routine, the processor resumes normal program flow.
There may be several interrupt sources that require servicing - the completion of an A/D conversion, a timer overflow, the triggering of an external interrupt pin, etc. Naturally, some sources will have higher priority than others. Hence, they need to be handled in an efficient manner. The interrupt subsystem is responsible for prioritizing interrupts and ensures that interrupts with a higher priority are serviced before interrupts of a lower priority. It consists of the interrupt control unit (ICU) and the peripheral transaction server (PTS). This document discusses and gives example programs on the ICU.
An interrupt on the 8XC196KC/KD may be processed in one of two ways: software interrupt service routines through the Interrupt Control Unit or microcoded hardware interrupt processing through the Peripheral Transaction Server.
There are sixteen interrupts available which may be handled by software interrupt service routines. Of the sixteen, fifteen may be masked (disabled). The Nonmaskable Interrupt (NMI) is used to implement critical interrupt routines. If the NMI pin is not used in an application, it should be tied to Vss to prevent spurious interrupts from occurring.
There are two special interrupts which are handled by the interrupt controller directly. These are the Unimplemented Opcode and Software Trap Interrupts (See Table 1). The Unimplemented Opcode interrupt prevents random software execution during hardware and software failures. The Software Trap interrupt serves as a useful debugging tool.
As mentioned above, interrupts have different priorities. When interrupts are detected by the Interrupt Controller, a priority encoder in hardware determines the priority of all current and subsequent requests. The Interrupt Controller then selects the corresponding vector location in Special-Purpose memory. This vector location contains the starting address of the corresponding interrupt service routine. In addition, a transition detector in hardware sets corresponding bits in special function registers (SFRs), INT_PEND and INT_PEND1, to indicate that an interrupt is pending. These bits are set even if individual interrupts are masked. The bits are cleared when the program vectors to the interrupt service routine.
|Number||Interrupt Vector||KC/KD Vector Location||Target Board Vector Loc.||Priority|
|Special||TRAP Instruction||2010h||reserved for RISM||-|
|INT15||NMI (Non Maskable)||203Eh||reserved for RISM||15|
|INT14||HSI FIFO Full||203Ch||D1C0h||14|
|INT10||HSI FIFO 4||2034h||D140h||10|
|INT09||Receive||2032h||reserved for RISM_isr||9|
|INT03||High Speed Outputs||2006h||D060h||3|
|INT02||HSI Data Available||2004h||D040h||2|
|INT01||A/D Conversion Complete||2002h||D020h||1|
Overview of Programming Interrupts
Handling interrupts through software service routines can be very easy. By setting and/or clearing individual bits in the special function registers, interrupts may be enabled and/or disabled. Program flow may be controlled by reading the SFRs as well. Table 2 lists the SFRs typically associated with programming interrupts.
|INT_MASK, INT_MASK1||Enable/Disable each maskable interrupt|
|INT_PEND, INT_PEND1||Bits in this register are set to indicate that an interrupt is pending|
|IOC1||Select the source of INT00, INT02, and INT07|
|IOS1||Contains flags that indicate which events triggered interrupts|
In addition to the SFRs listed in Table 2, there are other SFRs that may require programming. These, of course, depend on the peripherals being used and which interrupts need to be serviced. Programs 1 and 2 demonstrate how to generate a simple program to handle interrupts in assembly language. For bit descriptions of each SFR, refer to the 8XC196KC/KD User's Manual or ApBUILDER software.
Program one illustrates how to handle the HSI FIFO 4 interrupt (INT07) with a simple interrupt service routine. Before programming, it is important to determine which special function registers will be used to ensure that a peripheral and its associated interrupts will work properly. To determine which SFRs need to be used, consult the user's manuals or ApBUILDER software. In program one, the additional SFRs which require programming are hsi_mode and ioport1 (ioport1 on the target evaluation board is connected to LEDs)
The HSI FIFO 4 interrupt is generated when the HSI FIFO contains four entries. Events will be registered by positive-edged signals through High Speed Input 0. As a result of the interrupt being generated, the code contained in the interrupt service routine is executed. In this particular program, the interrupt service routine loads a value of FFh into input/output register 1 (illuminates all LEDs on target and evaluation boards).
NOTE: When using the target board, the interrupt vectors have different locations because the RISM code is located in the special-purpose memory space. To work properly, code for the target board should reflect the change in interrupt vector locations. The evaluation board requires no changes.
The following listing shows the assembly language code for program one. A line by line discussion of the program follows:
Program 1 Listing: The following code can be found in BTBEVAL.EXE (HSI4EVL.A96) for evaluation boards and BTBDEVEL.EXE (HSI4TGT.A96) for Project Builder boards on the Intel Bulletin Board Service in the MCS(R)96 Family/General section.
(1) $include (80c196kd.inc) (2) cseg at 2034h (3) dcw hsi4_isr (4) cseg at 2080h (5) di (6) ldb wsr, #0 (7) ldb ioc0, #01H (8) ldb wsr, #0 (9) ldb hsi_mode, #0FDH (10) ldb int_mask1, #04H (11) ei (12) loop: (13) br loop (14) hsi4_isr: (15) pusha (16) ldb ioport1, #0FFh (17) popa (18) ret (19) endLine1: The file, 80C196KD.INC, includes all the instructions necessary to equate register names with their appropriate addresses in memory. This file is included with the Project Builder Kit
Line2-3: The interrupt vector is set up in these two lines. The HSI FIFO Fourth Entry interrupt is associated in hardware with location 2034h (see Table 1). When the interrupt is serviced, the command "dcw hsi4_isr" will force the CPU to jump to the hsi4_isr loop. This loop contains the interrupt service routine.
NOTE: On the target board, "dcw" must be replaced by "br".
Line4: Upon reset, the processor fetches code from location 2080h.
NOTE: On the target board, code should start at location 0C000h
Line5: When using ISRs to service interrupts, it is good programming practice to globally disable all interrupts during initialization with di. This will prevent any unwanted interrupts from occuring during initialization.
Line6-9: Set window select register = 0. The 8XC196KC/KD employs horizontal windowing to make up for a lack of special function register address space. Although it is not necessary to reload the window select register in Line 7, it serves as a reminder to which horizontal window this register may be written. (When reading or writing to register locations, a different horizontal window might be used, and hence, the window select register must change). A value of 01h is loaded into the IOC0 SFR in order to set the 0th bit of this register. The 0th bit is the HSI0 enable bit. A value of 0FDh is loaded into the HSI_MODE register to select that only positive edges trigger an event.
Line10: By loading a 04h in the INT_MASK1 register, we enable the HSI FIFO fourth entry interrupt.
Line11: The ei command is the global interrupt enable command. Individual bits in the INT_MASK and INT_MASK1 registers still must be set to enable each interrupt.
Line12-13: This is the main loop. User code is usually placed in between lines 10 and 11, but for simplicity, code is omitted.
Line 14-18: This is the software interrupt service routine. Line 14 is the name, or label, of the ISR. This MUST match the name specified by the dcw command in line 3. Since serving an interrupt requires that the processor halt the execution of the next instruction, the pusha command saves all flags and registers (if applicable) so that these values are unchanged when code within the routine is executed. The popa command in line 17 restores the flags and registers when the interrupt service routine has finished. Any user code may be entered between lines 15-17, but line 15 simply contains a command to load a value into the ioport1 register. The ret command in line 19 instructs the processor to resume normal program flow.
Line20: The end instruction must conclude every assembly language program.
The SFRs associated with programming the EXTINT and EXTINT1 interrupts are wsr, int_mask, int_mask1, and ioc1. One additional register used for output purposes is ioport1.
Since much of the programming techniques are similar, a line by line discussion of program 2 is omitted.
Program 2 Listing: The following code can be found in BTBEVAL.EXE (INTEVL.A96) for evaluation boards and BTBDEVEL.EXE (INTTGT.A96) for Project Builder boards on the Intel Bulletin Board Service in the MCS96 Family/General section.
(1) $include (80c196kd.inc) (2) cseg at 200Eh (3) dcw extint_isr (4) cseg at 203Ah (5) dcw extint1_isr (6) cseg at 2080h (7) di (8) ldb wsr, #00h (9) ldb ioc1, #02h (10) ldb int_mask, #80h (11) ldb int_mask1, #020h (12) ei (13) loop: (14) br loop (15) extint_isr: (16) pusha (17) ldb wsr, #00h (18) ldb ioport1, #00h (19) popa (20) ret (21) extint1_isr: (22) pusha (23) ldb wsr, #00h (24) ldb ioport1, #0FFh (25) popa (26) ret (27) endIn program 2, two interrupt vectors are needed since there are two interrupt sources (lines 2-5). When a positive-edged signal on the EXTINT pin is detected, the interrupt controller associates that interrupt with vector location 200Eh (or D0E0h for target board). Line 4 contains the command to jump to the corresponding interrupt service routine. Likewise, when a positive-edged signal is detected on EXTINT1, vector location 203Ah (or D1A0h for target board) is associated with the starting address for the EXTINT1 ISR. Remember to change "dcw" in lines 3 and 5 to "br" if the target board is used.
Interrupt service routines, once again, may execute any user code. In lines 15-20, the ISR is used to turn the LEDs off. In lines 21-25, the ISR illuminates the LEDs.
ext_int_isr: pusha ; Save flags and registers (including int_mask & int_mask1) ldb int_mask1, #10000000b ; Bit 7 = 1 enables the EXTINT1 mask register only . ; User ISR code belongs here . popa ; Restore flags and registers ret ; Return from ISR
There are also certain instructions that prevent interrupts from being acknowledged until after the next instruction is executed. These are di, ei, popa, popf, pusha, and pushf.
The execution of any of the following also inhibit interrupts from being acknowledged until after the next instruction is executed:
Interrupt latency is the total delay between the time that the interrupt is acknowledged and the time that the interrupt service routine is executed. An interrupt is acknowledged only after the current instruction is finished executing. If the interrupt was not acknowledged at least 4 state times before the current instruction, the interrupt might not be acknowledged until after the next instruction. (Instructions are prefetched and prepared a few state times before they are actually executed). If this is the case, a delay equal to the number of state times of the next instruction will be incurred (NORML, the longest instruction, is 39 state times). When an interrupt is acknowledged, the process of obtaining the vector and forcing the call to the proper address takes a total of 11 state times (13 if the stack is located in external RAM assuming zero wait states). Therefore, the maximum latency for standard interrupts is 4+13+39 = 56 state times.
* Legal Information © 1999 Intel Corporation