Interrupt Synchronization (Microcontrollers)

11.6

In this section,

we consider interrupt hardware and software. Interrupt software can be tricky, so some companies actually have a policy never to use interrupts but instead to use the gadfly technique. At the other extreme, some designers use interrupts just because they are readily available in microcomputers like 6812 systems. We recommend using interrupts when necessary, but using simpler techniques whenever possible.

The hardware or I/O interrupt is an architectural feature that is very important to I/O interfacing. Basically,

it is invoked when an I/O device needs service, either to move some more data into or out of the device or to detect an error condition. Handling an interrupt stops the program that is running, causes another program to be executed to service the interrupt, and then resumes the main program exactly where it left off. The program that services the interrupt (called an interrupt handler or device handler) is very much like a subroutine, and an interrupt can be thought of as an I/O device tricking the computer into executing a subroutine. An ordinary subroutine called from an interrupt handler is called an interrupt service routine. However, a handler or an interrupt service routine should not disturb the current program in any way. The interrupted program should get the same result no matter when the interrupt occurs.

I/O devices may request an interrupt in any memory cycle.

However, the data operator usually has bits and pieces of information scattered around and is not prepared to stop the current instruction. Therefore, interrupts are always recognized at the end of the current instruction, when all the data are organized into accumulators and other registers (the machine state) that can be safely saved and restored. The time from when an I/O device requests an interrupt until data that it wants moved is moved, or the error condition is reported or fixed, is called the latency time. Fast I/O devices require low latency interrupt service. The lowest latency that can be guaranteed is limited to the duration of the longest instruction, because the I/O device could request an interrupt at the beginning of such an instruction’s execution.


The condition code register,

accumulators, program counter, and other registers in the controller and data operator, the machine state, and these nine bytes are saved and restored whenever an interrupt occurs. After completion of a handler, the last instruction executed is return from interrupt (RTI). It pulls the top nine bytes from the stack, replacing them in the registers the interrupt took them from.
Interrupt techniques can be used to let the I/O system interrupt the processor when it is DONE, so the processor can be doing useful work until it is interrupted. We first look at steps in an interrupt. Then we consider interrupt handlers and the accommodation of critical sections.
Interrupt Request Path
Figure 11.9. Interrupt Request Path
After port and counter/timer control registers are properly initialized, a falling edge on the counter/timer bit 0 can request an interrupt. See Figure 11.9. The six-step sequence of actions that lead to an interrupt and that service it are outlined below.
1. When the external hardware determines it needs service either to move some data into it or out of it or to report an error, we say the device requests an interrupt. This occurs when portt bit 0 falls.
2. If the poett bit 0 pin is an input (in ddrt bit 0) and had been assigned (in tmski bit 0) to sense interrupts, we say portt bit 0 interrupts are enabled.
3. If the microprocessor’s condition code register’s I bit is 0 we say the microprocessor is enabled. When I is 1, the microprocessor is masked (or the microprocessor is disabled). If a signal from the device is sent to the controller, we say the microprocessor sees a request, or a request is pending, and an interrupt will occur, as described below. (The bit I is also controlled by hardware in the next step.)
4. Most microcomputers cannot stop in the middle of an instruction. Therefore, if the microprocessor recognizes an interrupt, it honors an interrupt at the end of the current instruction. When the 6812 honors a counter/timer interrupt, it saves the registers and the program counter on the stack, sets the condition code register I bit, and loads the 16-bit word at Oxffee into the program counter to process this interrupt. Importantly, condition code bit I is set after the former I was saved on the stack.
5. Beginning at the address specified by Oxffee is a routine called the timer 0 handler. The handler is like a subroutine that performs the work requested by the device. It may-move a word between the device and a buffer, or it may report or fix up an error. One of a handler’s critically important but easy to overlook functions is that it must explicitly remove the cause of the interrupt (by negating the interrupt request) unless the hardware does that for you automatically. This is done by writing 1 into bit 0 of the tflgi port.
6. When it is completed, the handler executes an RTI instruction; this restores the registers and program counter to resume the program where it left off.

Some points about the interrupt sequence must be stressed.

As soon as it honors an interrupt seen on a line, the 6812, like most computers, sets the I condition code bit to prevent honoring another interrupt from the same device. If it didn’t, the first instruction in the handler would be promptly interrupted—an infinite loop that will fill up the stack. You do not have to worry about returning it to its value before it was changed, because step 6 restores the program counter and the condition code register and its I bit to the values they had before the interrupt was honored. However, a handler can change that level using a tfr, and, or or to condition code instruction to permit honoring interrupts. Note that the I/O device is generally still asserting its interrupt request line because it doesn’t know what is going on inside the microprocessor. If the rti is executed or i is otherwise cleared, this same device will promptly interrupt the processor again and again — hanging up the machine. Before the handler executes rti or changes i, it must remove the interrupt source! (Please excuse our frustration, but this is so simple yet so much of a problem.)

To handle the interrupts,

we need to put the handler’s address in the 16-bit word at Oxffee. The mechanism that puts an interrupt handler’s address where the interrupt mechanism needs to find it is specific to each compiler. In a compiler that is specifically designed for I/O interfacing, all we need to do is write interrupt 8 in front of the name of the procedure for counter/timer device 0 (a number different from 8 is used for other devices —see Table 11.1). This convention inserts the address of the handler into Oxffee, and further ends the procedure with an rti. For other compilers a statement * (int * ) Oxffee = (int) handler; puts the address of the handler in the location that the hardware will use when an interrupt occurs. However, this location is in EEPROM in the ‘ A4 and flash in the ‘B32, so special programming procedures are used.

There are two parts of the path that an interrupt request takes.

In our example, the counter/timer flag is set if an edge occurs on its input. A switch in series with an input that can set this flag is called an arm; if it is closed the device is armed, and if it is opened, the device is disarmed. Any switch between the flag register and the 6812 controller is called an enable; if all such switches are closed the device is enabled, and if any are opened, the device is disabled. Arming a device lets it record a request and makes it possible to request an interrupt, either immediately if it is enabled or later if it is disabled. You disarm a device if you do not want to honor an interrupt now or later. But you disable an interrupt to postpone it. You disable an interrupt if you can’t honor it now, but you may honor it later when interrupts are enabled.

Also, for gadfly synchronization,

you arm the device so the flag register can become set when the device enters the DONE state, but you do not enable the interrupt because the program has to test the flag. If an interrupt did occur and was honored properly so as not to crash the computer, the gadfly loop wouldn’t exit because the flag would be cleared in the handler before the gadfly loop could test it and exit its loop.
We illustrate the use of interrupt synchronization by implementing a variation of the Geiger counter that used gadfly synchronization. Each time a pulse occurs, portt bit 0 sees a rising edge, which causes an interrupt. To count the pulses, execute the C procedure
tmp7D-4_thumb[1]

The main procedure above initializes the control registers and loops forever.

The I condition code bit is generally clear after the 6812 is reset and must be cleared to enable interrupts to occur. A high-level language like C generally does not have a way to enable interrupts, except by inserting embedded assembly language. The statement asm CLI inserts CLI into the assembly-language program. Each time another vector element is to be output, a switch is closed, and portt bit 0 sees a rising edge. This causes an interrupt, and the handler is entered. This handler increments the count.
We further illustrate an interrupt-based traffic light controller that is essentially the same as the gadfly-based traffic light controller example. The main procedure initializes the control registers, waits for all elements to be output, and then disables the interrupt. Each time another vector element is to be output, a switch is closed, and portt bit 0 sees a falling edge. See Figure 11.9. This causes an interrupt, and the handler is entered. This handler outputs an element from the vector. To output the vector, execute
tmp7D-5_thumb[1]
An optimized assembly-language program segment for the body of the C procedure is shown below. For it and the subsequent handler program segment, we assume there is a global variable I that is initialized to $80, the number of elements in the buffer, and there is an $80-element buffer.
tmp7D-6_thumb[1]

This raises an often-misunderstood point about interrupts.

Gadfly has lower latency than interrupt synchronization. Gadfly does not have to save the registers and then initialize registers used in the handler. If, when using interrupt synchronization, you just waste time in a gadfly or wait loop, use gadfly synchronization to lower latency.

The 6812 has a number of I/O devices, and most of them have their own interrupt vector,

shown in Table 11.1. The handler used in the previous example has its vector at $FFEE and $FFEF, for “Timer channel 0.” When an edge occured on portt bit 0, the contents of this vector, the 16-bit data in $FFEE (high byte) and $FFEF (low byte), are put into the program counter, and the interrupt handler is then executed starting at this address. Other interrupt vectors of interest in this introductory discussion are the reset, SWI, and TRAP vectors. The reset vector at $FFFE and $FFFF is the address of the first instruction that is executed when a 6812 comes out of reset. Locations $FFF6 and SFFF7 usually contain the address of the monitor program, which is where you go when an SWI instruction is executed, or a BGND instruction is executed, but the background debug module is not set up to handle a monitor program. Locations $FFF8 and $FFF9 usually contain the address of the handler for illegal instructions, which can be used to emulate instructions not implemented in the 6812.
Table 11.1. Interrupt Vectors in the 6812 ‘A4
Interrupt Vectors in the 6812 'A4
This section has introduced the interrupt and its implementation on the 6812. You have learned how interrupts work in hardware and how an assembly-language program can be written to handle the interrupt from the timer module 0, in particular for rising or falling edges on portt bit 0.

This section,

together with the last section, has shown two commonly used alternative methods for synchronization. Gadfly synchronization actually provides lower latency than interrupt synchronization (that is, faster response to an edge signal), while interrupts let you do other work while waiting for an edge from an I/O device. Upon completion of these two sections, you should find either technique easy to use.

Next post:

Previous post: