• No results found

Polling versus Interrupts in Input Devices

In document 68HCS12Text_Printable (Page 155-159)

If data is not available when polled, the program can either wait for the data to become available, or perform some other task and then poll again. These two alternatives are shown in the flow charts:

If we wait for data, alternative A, then nothing else can be done. This is an acceptable technique if there is nothing else to do, but probably would not be a good idea for a keyboard input controlling machinery - the machinery could not be controlled while waiting for user input! If we use alternative B, then the machinery could be controlled while waiting for that user keystroke.

But some inputs require quick response (response time is referred to as latency), or occur at a fast rate, in which case we risk buffer overflow. Technique B will fail if Do Other Things takes too long - the latency of A is the time it takes to poll the device, while that of B might be as long as the time to poll plus the time to execute Do Other Things. If we know when the data will arrive or we know the wait will be short, technique A may be acceptable. But how do we minimize latency and still do other things while we wait? The solution is to check the status of the peripheral at various points in the program. If at any point the peripheral indicates that it needs servicing (data available for input or requesting data for output) then a subroutine is called to handle it.

Let’s consider an example using the 68HCS12 Serial Communications Interface. When a byte of data is received from outside the

microcontroller, the status register SC0SR1 bit called RDRF (bit 5, which is mask value $20) gets set. At this time the data register, SC0DRL can be read to obtain the data. The action of reading SC0DRL will automatically reset RDRF, which will be set again when the next byte arrives. If we want to wait for the data to arrive, the code to poll the flag and read the data is:

l1: brclr SC0SR1 #$20 l1 ; wait if no data ldaa SC0DRL ; get data byte

process data byte ; (do what we need to do with the data)

If we use a subroutine and multiple polling locations, the polling code is:

brclr SC0SR1 #$20 l1 ; branch if no data

jsr process ; process data if present l1:

The important consideration in the placing of the polling code is this: if RDRF is signaled but another byte arrives before the current byte is processed, then data will be lost. The polling code must be placed at enough locations in the program so as to prevent data loss. Assuming we are successful, we may have many occurrences of the code, each

consuming ROM locations. We also waste time checking for data arrival when no data has arrived. There must be a better way! The way is interrupts.

An interrupt is basically a subroutine call which is forced by hardware, rather than invoked by a bsr or jsr. With a few exceptions, an interrupt can happen between instructions at any place in a program. Using interrupts is equivalent to polling at each instruction, but without any time or space overhead. The subroutine called by interrupts is called an interrupt service routine.

Using interrupts requires some initial configuration. First, the peripheral device must be capable of generating interrupt requests and the ability to issue such requests must be enabled for that device (this is done by setting control register bits). When the

peripheral's request is acknowledged by the processor, the peripheral provides the processor with an interrupt vector address. The interrupt vector is a memory location which contains the address of the interrupt service routine. The programmer is

responsible for setting the contents of the vector location to be the address of the routine. The processor then calls the interrupt service routine.

Since an interrupt can occur anywhere in the program, it is important that the contents of all the processors registers be preserved during the execution of the interrupt routine. This must be done either by the programmer or for some processors, the 68HCS12 included, happens automatically. In the 68HCS12, the A, B, X, Y, and CCR registers are saved on the stack, along with the return address. All registers must be restored at the end of the interrupt service routine. The rti instruction in the 68HCS12 restores all registers and returns to the instruction which was about to be executed when the interrupt occurred. This instruction is used instead of rts in an interrupt service routine.

In our serial communications interface example, the interrupt vector address is $FFD6. So that word location would need to be initialized with the address of our new interrupt service routine, SC0ISR. The interface would need to be configured to cause an interrupt when a byte arrives. This process will be described in detail in later sections. Finally, the interrupt service routine would need to be provided:

SC0ISR:

ldaa SC0DRL ; get data byte

process data byte ;(save/restore other registers as needed) rti

SC0ISR will be called whenever a byte arrives. No polling is necessary. The interrupt latency is the time it takes to finish the current instruction and invoke the interrupt service routine. Since this time include pushing all the registers on the stack, it's much longer than the original polling approach A, but typically far less than the other polling

approaches, and there is no time wasted polling the device when there is no data available.

Suppose we don't want to process the data byte at the time the data arrives, but want to process it elsewhere. In that case we need to buffer the data. Buffering techniques are discussed in the section on the Serial Communications Interface.

In document 68HCS12Text_Printable (Page 155-159)

Related documents