Interrupt Handling Part 1 (PIC Microcontroller)

The subroutines discussed in topic 6 are predictable events in that they are called up whenever the program dictates. Real-time situations, defined as where the processor interacts in concert with external physical events, are not as simple as this. Very often something happens beyond the CPU which necessitates precipitate action from the processor. The vast majority of MPU/MCUs have the capability to deal with a range of such events that disrupt their smooth running. In the case of a microcontroller, requests for service may come from an internal peripheral device, such as a timer overflowing, or the completion of an analog to digital conversion, or from a source entirely external to the device in the outside world. At the very least, on reset (a type of external hardware event) the MCU must be able to get (vector) to the first instruction of the main program. In the same manner an external service request or interrupt when answered must lead to the start of the special subroutine known as an interrupt service routine.

In this topic we will be examining how the PIC16F84 handles interrupts originating both internally and externally. The other mid-range PICs handle interrupts in a similar manner, but have a different mix of internal peripheral devices, such as an analog to digital converter, which will be discussed in Part 3 of the text. After reading this topic you will:

• Appreciate the need for interrupt handling.

• Appreciate the concept of a vector table as a jumping-off point for reset and interrupt events.


• Follow the sequence of events when the PIC recognizes an interrupt request.

• Understand the principle of latency.

• Have an understanding of the concept of the global interrupt mask.

• Understand the operation of the local interrupt mask and flag pairs and how this is implemented in the INTCON and EECON1 file registers corresponding to the various source of interrupts.

• Be able to write a simple interrupt handler involving the following principles:

- Context switching.

- Determination of interrupt source.

- Return via the retfie instruction.

A simple example of a time-sensitive requirement is shown in Fig. 7.1. Here we wish to measure the elapsed time between R points of an electrocardiogram (ECG) signal; by definition an external real-time event. The time resolution is to be 0.1 ms and the maximum peak-peak duration is likely to be no more than 1.5 seconds. In order to measure this time a free-running 16-bit counter clocked at 10 kHz can be used as the time base. As we shall see in topic 13, the mid-range PICs have an internal 8-bit counter at File 01 and Fig. 7.1 shows File 3Fh used as an extension byte to give a total 16-bit count. The details of this configuration are discussed in Program 13.2.Here we will assume that the state of the count can be read at any time from these two specified file registers. If the count at the last R point is stored in two spare file registers, then subtraction of the count at the current R point will give the required beat-to-beat duration.

Detecting and measuring an external event.

Fig. 7.1 Detecting and measuring an external event.

The next problem is how to detect the signal peak, as by definition the patient’s ECG signal is not synchronized to the MCU! One technique is to continually read this signal and perform a peak-detection algorithm to determine the R point. Now this polling technique will have to be carried out 10,000 times each second in order to keep to the specified resolution and taking a nominal human heartrate of 60 beats per minute, 99.99% of the time no peak will be detected. Essentially, this means that the processor will spend the vast majority of its processing power just looking out for one event in 10,000.

The alternative approach is to use external hardware who’s task is to find the peak signal. That peak-picking hardware could be an analog circuit or even a MCU with an analog to digital converter dedicated to this one task – see Example 14.4. Whatever the implementation, the peak-picker sends a signal to the main processor when a R point has been detected. This signal interrupts the MCU which must drop whatever it is doing and read the counter within 100 us if a counter tick is not to be missed.

In the situation where external processes happen in their own good time and are in no way synchronized to the processor, there has to be some way for certain events to interrupt the process and direct it to attend to their immediate need. Polling a series of outside events is adequate where nothing much happens quickly outside and/or there are few parameters to monitor and little processing to do. The possibility of missing anything important can be reduced by increasing the polling rate, but there comes a time when the MPU does little else but read peripheral data. This resource burnout is especially a problem when there are many signals to poll in a short period of time.

The downside of interrupt-driven real-time monitoring is additional hardware complexity and the greater intricacy of the hardware-software interface. If you are confused, consider the telephone system. It would be possible to have a telephone network where the subscriber would pick up the phone every, say, 5 minutes and ask “Is there anyone there?”. Apart from the bother (processing overhead) of doing this,2 the caller may have got bored and hung up. You could reduce the chance of this happening by increasing the polling rate to, say, once per minute. But you could then end up spending all your time on the phone and, depending on how popular you are, getting only a few hits a day. That is, 99% of your effort is wasted.

This is obviously ridiculous, and in practice an interrupt-driven technique is used so that you only respond when the bell/buzzer sounds. Highly efficient, but at the cost of a lot more complexity for the phone company, as the signalling side of the system can be more demanding than the speech side. There is another problem too, in that you (cf. the processor) have no idea when the phone will ring. And it surely will be at the most inconvenient time. Thus you have to (unless you have an iron will) break off what you are doing at the drop of a hat. For example, if you happen to be in the middle of solving a problem in your head you should save your partial results before responding, so, when finished, you can return to where you left off.

Keeping this apparent randomness (at least as seen by the MCU) in mind the following phases can usually be identified, although the minutiae of the response to an interrupt request varies considerably from processor to processor.

1. Finishing the current instruction.

2. Automatically saving, at the very least, the state of the Program Counter (PC), which is needed to get back. Some processors also automatically save the Status register and other internal registers at this point.

3. Entering the appropriate interrupt service routine.

4. Executing the defined task.

5. Restoring the processor state and returning to the point in the background program where control was first transferred.

Essentially signalling an interrupt causes the PIC to drop whatever it is doing, save its position in the interrupted background program and go to a special subroutine known as an Interrupt Service Routine (ISR). This foreground program is just a subroutine entered at the behest of an external happening.

The mid- and upper-range PIC core can be interrupted by a range of events. For example, the PIC16F84 will respond to service requests from four sources.

1. An external signal at pin 6 (see Fig. 4.2 ) which is labelled INT in this context, but doubles as the PortB bit0 RB0 pin. The request may be activated optionally by either a rising edge _/ or a falling edge ^ at this input.

2. An input change at any of the top four PortB (File 6) pins since the last read of this port.

3. By the Timer counter TMR0 (File 1) overflowing FF — 00h.

4. When an internal Data EEPROM write-to action has been completed.

We will look at how each of these can request an interrupt service later in the topic. However, the PIC’s response to an interrupt is functionally identical from whatever source it comes from; so for the moment for simplicity we will assume that some event (maybe the peak-picker in Fig. 7.1) wants service and has pulsed the INT pin.

The PIC’s response to such an event is shown in a simplified manner in Fig. 7.2. Essentially the sequence is:

Responding to an interrupt request.

Fig. 7.2 Responding to an interrupt request.

3. If both the interrupt flag is set and bit 7 of the INTCON special purpose register (see Fig 7.4) is clear, the next three instruction cycles are involved in moving execution to the interrupt service routine, although the first of these may be the final cycle of a 2-cycle instruction otherwise a dummy cycle, plus two more cycles to flush the pipeline. This 3 to 4-cycle delay from the instant of the hardware INT signal and beginning the execution of the first instruction of the ISR is known as latency. It is impossible to be more precise due to the time-random nature of the external request signal which can occur anywhere in the instruction cycle.

4. During this latency period the PIC does three things:

(a) Bit7 of the Interrupt Control register (INTCON at File 0Bh) is zeroed. This bit is labelled in Fig. 7.4 as General Interrupt Enable (GIE). Once GIE is cleared all further requests for interrupts from whatever source are locked out, so an interrupt service process cannot be further interrupted. GIE is an example of an Interrupt mask as it is able to mask out interrupt activity. After reset GIE is cleared, so by default interrupt activity is disabled.

(b) The state of the 13-bit Program Counter is pushed into the hardware stack in exactly the same manner as for a call instruction – see Fig. 6.3.As for subroutines, this is to allow the processor to return to the interrupted background program after the interrupt service routine. As the mid-range PICs have an 8-deep hardware stack, subroutines nested to depth of seven can be called from an ISR.

(c) The first instruction of the ISR is always in location 004h in the Program store. Thus the final step of the sequence is to overwrite the PC with this instruction address, known as the Interrupt vector. If the interrupt handling software is elsewhere in Program memory then this entry instruction can of course be a goto instruction; see Program 7.1.

5. Like a subroutine, an ISR must be terminated by a Return instruction. However, in this case not only has the PC to be pulled out of the hardware stack to move execution back to the interrupted program but the GIE bit in the INTCON register must be set to re-enable the interrupt capability. This counteracts the resetting of this bit in 4(a) above on entry to the ISR. The Return instruction relevant to this situation is retfie (Return From Interrupt and Enable). Thus on reentry to the background program any pending or future interrupts can be serviced.

An ISR differs from a subroutine in more subtle ways than the use of the retfie instruction of item 5 above. Some of these differences relate to the logic of the interrupt system and some are due to the pseudo random nature of the interrupts. Discussing the former first, let us examine the logic circuitry relating to the interrupt process.

The flag:mask pair.

Fig. 7.3 The flag:mask pair.

Each of the four PIC16F84 interrupt sources interact with the processor via two associated control register bits, as shown in Fig. 7.3. The flag bit is set when the related source device requests service. For example, if the Timer 0 overflows FFh — 00h then bit 2 of the INTCON register, labelled T0IF (Timer 0 Interrupt Flag) is set to 1. If the local mask bit is 1 (bit 5 of INTCON labelled T0IE for Timer 0 Interrupt Enable) then the request will go forward to the next layer of interrupt logic. Note that the state of the mask bit does not affect the setting of the associated interrupt flag. Thus if the mask bit is zero, a polling technique can still be used to determine if an event has occurred by checking the state of the appropriate interrupt flag.

The local mask bit can be written to in the normal way by software. On reset it is zeroed and thus the interrupt from the affiliated source disabled. To set it to one, use the bsf instruction. For example, bsf INTCON,5 to set the T0IE mask. The interrupt flag can also be written to by software, as well as being externally set by the requesting device. The ISR must clear it, eg. bcf INTCON,1, before return to cancel the request otherwise an endless series of interrupts will occur. This is because on return the interrupt flag will still be set and another interrupt will immediately be set in train.

As there are four sources of interrupt, each flag:mask AND gate must be ORed to give a composite request signal, which when active initiates the CPU’s interrupt response. In Fig. 7.4 this ORing process is further gated with the Global mask bit GIE, which is located in bit 7 of INT-CON. However, the raw, i.e. pre-globally masked, request signal is used to awaken the processor if it is in a power-down or sleep state. As we will see in topic 10 the current consumption of the device can be considerably reduced to typically 1 nA if processing is stopped and the PIC is put in a state of suspended animation. For example, monitoring the temperature profile at the bottom of a lake over a period of a year at one hour intervals using a battery-powered data logger requires processing for a tiny proportion of the time. Placing the PIC in this power-down mode after each sample has been taken and stored will reduce the necessary battery capacity. The sleep instruction initiates this mode. An interrupt from an outside source, in this case a low-power hourly oscillator, is used to wake the PIC up. As shown, this awakening is independent of the setting of the General mask.

The Timer 0, External and Port B Interrupt flags are located in the INT-CON register at bits 2, 1, 0 respectively. These peripherals are common across all mid-range PICs and appear in the same location for these devices. That for the internal Data EEPROM is separately located in the EECON1 Special Purpose Register (SPR) in Bit 4 – see Fig. 15.2. Bit EEIF is set whenever a write-data action has been completed.

The Data EEPROM is peculiar to the PIC16F83/4 devices. Other PICs substitute alternative flags for their specialized peripheral devices. For example, the PIC16C71 uses bit 1 of its ADCON0 (A/D CONtrol0) as the ADIF flag to show that the internal A/D converter has finished its conversion. More sophisticated PICs have more than one interrupting device beyond the three standard ones – INT, Timer0 and PortB. For instance, the PIC16C74 has eight (plus the standard three) interrupt sources, including two additional timers, a multichannel A/D converter and two serial ports. In this case each such peripheral has its own interrupt flag together in a Peripheral Interrupt Register, as shown in Fig. 14.10(b).

The PIC 16F84's interrupt logic.

Fig. 7.4 The PIC 16F84′s interrupt logic.

The INTCON register also holds the four local mask bits corresponding to the PIC16F84′s standard peripherals, besides the Global mask. The programmer can selectively disable or re-enable one or more interrupting source as desired. Thus if it is undesirable for Timer 0 to interrupt a section of code dealing with, say, multiple-precision arithmetic (see Ex-ample 7.2) then T0IE canbe cleared for the duration of that routine. Other PIC devices replace the EEIE mask by one appropriate to their additional peripheral. Thus the PIC16C71 has ADIE (Analog to Digital Interrupt Enable) as bit 6 of INTCON. PICs with more than one additional peripheral use this bit to enable all these extra requests as a single group, called PEIE (PEripheral Interrupt Enable). However, all these extra devices have their own local masks together in a Peripheral Interrupt Enable register, giving three layers of mask – see Fig. 14.10(b).

As there is only one common interrupt vector, i.e. at 004h, then one of the first tasks the ISR has to do is check which peripheral is calling for help. All interrupt flags can be read, so these can be polled in turn until the one that is set is found. Based on this approach a typical polling sequence could be:

tmp18-402

The order of polling gives a priority level if more than one interrupt request should coincide. Thus if both the external hardware and Timer0 interrupts are active, the former will be processed first. In this case, on return the pending Timer 0 interrupt requests will then be processed – unless another higher-priority interrupt request has occurred. In all instances the appropriate interrupt flag should be cleared, otherwise the interrupt will be generated indefinitely!

Where masks are set, this same polling technique can be used to check on the status of events without using the PIC’s interrupt processes. For example, when a byte is written to the Data EEPROM the program typically checks the state of EEIF (bit 4 of EECON1) until it is set, then clears it and continues on.

shows additional logic particular to the external INT pin. INTF is set on a falling edge. By interposing an XOR gate as a programmable inverter, the active edge on the INT pin can be controlled from bit 6 of the Option register - see also Fig. 13.2. If INTEDG is 0 then INTF will be set on a falling edge at INT whilst a rising edge is active when INTEDGE is 1, which is the default on reset.

Figure 7.4 shows additional logic particular to the external INT pin. INTF is set on a falling edge. By interposing an XOR gate as a programmable inverter, the active edge on the INT pin can be controlled from bit 6 of the Option register – see also Fig. 13.2. If INTEDG is 0 then INTF will be set on a falling edge at INT whilst a rising edge is active when INTEDGE is 1, which is the default on reset.

Next post:

Previous post: