You are on page 1of 40

Chapter

3
Polling and Interrupt Handling

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-1

Polling and Interrupt Handling


3.1 Overview Polling Interrupt Handling Design Considerations

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-2

Overview
A device driver is a software solution for a hardware operation problem. The software must be aware of state changes or events in the hardware. Examples of state changes and events are:
q q

Floppy drive door opened DMA operation complete Data has arrived Device has completed initialization and is now available for use. ...

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-3

Methods
Polling
q

Software periodically queries the hardware for event occurrences. Hardware causes ow of execution to be changed due to a event occurrences.

Interrupt Handling
q

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-4

Polling and Interrupt Handling


Overview 3.2 Polling Interrupt Handling Design Considerations

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-5

Managing non-interrupt driven devices using polling techniques


q

Task polling during idle times Task polling at periodic intervals Using watchdog timers Using auxiliary clock

Task synchronization

Data buffering (asynchronous I/O)

Mutual exclusion and race condition issues

Approach Overview
Application Application

Driver

Driver

Driver Poll Task

Device

Device

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-6

Application program calls driver routines, which access device.


q

driver is executed in the context of the application task all I/O is synchronous

Application program calls driver routines, which communicate with the driver poll task.
q

poll routine executes as separate task I/O may be asynchronous

Task Time Polling


To poll your device when the system is idle: Create a low priority task In an innite loop poll the device:
q q

FOREVER { status = *pDeviceAdr; ... }

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-7

What are the consequences of the above?

Task Time Polling


To poll device at a periodic interval: Create a moderate or high priority task In an innite loop poll device and call taskDelay( ).
q q

FOREVER { status = *pDeviceAdr; ... taskDelay (POLL_RATE); }

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-8

What are the consequences of this choice?

Task Time Polling Without Drift


Poll device from a task synchronized by a watchdog timer:
1 2 3 4 5 6 7 8 9 10 11 12 13 LOCAL SEM_ID fooSemId; LOCAL WDOG_ID fooWdId; STATUS fooInit (void) { /* Create poll task */ fooSemId = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY); taskSpawn (...fooPoll,...); /* Create watchdog timer and start it */ fooWdId = wdCreate (); wdStart (fooWdId, POLL_RATE, fooWdFunc, param); }

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-9

What are the consequences of this choice? Please note that error checking has been removed in the code above.

Code Example (Contd)


14 LOCAL void fooWdFunc (int param) 15 { 16 semGive (fooSemId); 17 wdStart (fooWdId, POLL_RATE, fooWdFunc, param); 18 } 19 20 LOCAL void fooPoll (void) 21 { 22 semTake (fooSemId, WAIT_FOREVER); 23 status = *pDeviceAdr; 24 ... 25 }

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-10

Interrupt Time Polling


Poll device using a watchdog timer:
1 LOCAL WDOG_ID fooWdId; 2 3 STATUS fooInit (void) 4 { 5 fooWdId = wdCreate (); 6 wdStart (fooWdId, POLL_RATE, pollFunc, param); 7 } 8 9 LOCAL void pollFunc (int param) 10 { 11 status = *pDeviceAdr; 12 ... 13 wdStart (fooWdId, POLL_RATE, pollFunc, param); 14 }

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-11

High Speed Interrupt Time Polling


Use the auxiliary clock for very fast polling:
void fooPollStart (int rate) { sysAuxClkConnect (fooPoll, param); sysAuxClkRateSet (rate); sysAuxClkEnable (); } LOCAL void fooPoll (int param) { status = *pDeviceAdr; ... } void fooPollStop (void) { sysAuxClkDisable (); }

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-12

The existence and restrictions on the auxiliary clock is board dependent. See cong.h for the minimum (AUX_CLK_RATE_MIN) and maximum (AUX_CLK_RATE_MAX) auxiliary clock rates.

For simplicity, error checking has been removed from the example routines above.

Comparison of Polling Techniques


Using a low priority task allows device polling as system load permits. Polling task could starve if priority is not high enough. The higher the priority, the more consistently the task accesses the device. A high priority polling task may block out other tasks. Using watchdogs provides the most reliable periodic device access with the greatest cost (to the rest of the system). To reduce overhead, interrupts should be used for high speed polling.
Tornado Device Driver Workshop Copyright Wind River Systems Wind River Systems

3-13

Since there is less overhead in servicing an interrupt then in a context switch, high speed polling is best done in an auxiliary clock ISR.

Polling and Interrupt Handling


Overview Polling 3.3 Interrupt Handling Design Considerations

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-14

Installing an interrupt service routine (ISR).

What can and cannot be done in an ISR.

Debugging an ISR.

Interrupt Service Routine (ISR)


User-dened routine to execute upon receipt of an interrupt. In an ISR, do not:
q

Block, e.g. call semTake( ) Use a routine that requires a task context (TCB), e.g. call taskIdSelf( ) Use oating point operations (unless oating point registers are saved and restored)

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-15

Handling Interrupts
1. Interrupt task when device asserts IRQ line 2. During interrupt acknowledge cycle, decide which device needs service 3. Call routine appropriate for the device as indicated in the Interrupt Vector Table 4. In VxWorks-dened interrupt wrapper routine, save registers and call user-dened ISR 5. Restore registers on return from ISR 6. Unless ISR made a task of higher priority ready to run, resume interrupted task

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-16

Floating point registers are NOT automatically saved and restored by interrrupt wrapper routine.

Auto-vectored, Vectored and Chained Interrupts


If the system is autovectored, software will be run to determine which device caused the interrupt. In a true vectored system, hardware will complete a set of bus cycles to determine the STATUS/ID information and the service routine for this particular device will be called. Chained interrupts allow multiple service routines to be simultaneously connected to a particular vector. All chained routines will be executed in response to an interrupt for a particular vector. It is the responsibility of the ISR to determine if its device is active.
Tornado Device Driver Workshop Copyright Wind River Systems Wind River Systems

3-17

Converting Interrupt Number to Interrupt Vector


INUM_TO_IVEC (intNum)
Converts an interrupt number to interrupt vector in an architecture dependent manner:
Interrupt Table Example (MC68K) 0 0 4 Interrupt 1 Interrupt 8 Number 2 3 12 Vector 255 1020

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-18

Macro dened in iv.h.

Installing an ISR
STATUS intConnect (vector, routine, param)
vector routine param Example:
#include "iv.h" ... void myISR(); ... if (intConnect (INUM_TO_IVEC(intNum), myISR, 0) == ERROR) return (ERROR);

The interrupt vector The address of the user-dened ISR Any value to be passed to this ISR

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-19

The vector is NOT the interrupt number. It is the address offset of the entry in the interrupt vector table.

The param is sometimes used to indicate which board is interrupting when managing multiple boards of the same type. This avoids having to write two separate ISRs. For example:
/* connect intConnect /* connect intConnect ... void myISR ... first boards ISR */ (INUM_TO_IVEC(intNumberBoard0), myIsr, 0); second boards ISR */ (INUM_TO_IVEC(intNumberBoard1), myIsr, 1); (int boardNumber)

ISR Restrictions
No I/O system calls
q

Dont call routines that make I/O system calls, e.g. printf( )

No blocking
q

Dont take a semaphore or call any routine that may take a semaphore, e.g. malloc( ) No taskDelay( )

Do not do anything that requires a task context


q

Dont use 0 for a tid, e.g. taskSuspend (0) Dont use mutual exclusion semaphores

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-20

I/O system calls, e.g. read( ) and write( ), typically block until the device is ready to satisfy the request.

It is perfectly OK to read or write to device registers (as long as there is no blocking).

What Can Be Done In An ISR


Calling semGive( ) or semFlush( ) on a binary or counting semaphore Reading or writing to memory, including memorymapped I/O Making non-blocking writes to a pipe or message queue Calling logMsg( ) Calling any routine in lstLib or bLib Calling any routine in rngLib except rngCreate( ) Calling wdStart( ) and wdCancel( ) Calling taskSuspend( ), taskResume( ) or taskPrioritySet( )
Tornado Device Driver Workshop Copyright Wind River Systems Wind River Systems

3-21

See Programmers Guide for a complete list.

ISR Guidelines
Keep ISRs short The general rule is Do as little as possible. The longer the ISR, the longer the delay for lower or equal priority interrupts. Avoid using oating point operations in an ISR. The shorter the ISR, the easier it is to debug. It is the responsibility of the ISR to determine if its device is active. This is required if the ISR is ever to be installed on a system with chained interrupts.

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-22

To use oating point operations in an ISR, you must save and restore the registers yourself. See fppALib for save and restore routines.

Common ISR Scenarios


Call semGive( ) and do everything else at task time. Read from the device and place data read into pipe or message queue.

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-23

Example:
SEM_ID semId; ... intConnect (INUM_TO_IVEC (intNumber), semGive, semId); ... void myFunc() /* task time */ { FOREVER { semTake (semId, WAIT_FOREVER); . . /* deal with device */ . } }

Enabling Interrupts
In systems with a bridge to an external, shared bus, it is necessary to program the bridge chip to pass interrupts asserted on that bus to the processor. Bridge chips for the VMEbus will often have this ability. It is essential that only one processor in a VME system service a particular VME interrupt level.

sysIntEnable (intLevel)
Makes target respond to VMEbus interrupts of specied interrupt level.
Tornado Device Driver Workshop Copyright Wind River Systems Wind River Systems

3-24

There are seven interrupt levels on a VME bus.

Not all interrupt levels may be available on all BSPs.

Some BSPs multiplex VMEbus interrupts. For example, VMEbus interrupt levels 3 and 4 may be multiplexed into interrupt level 3.

Some BSPs (e.g. hkv2f) require manual handling of the interrupt acknowledge cycle for certain interrupts levels. See your target specic documentation.

Some boards may require a hardware jumper change.

Debugging ISRs
Whenever possible, start simply and build slowly. Use logMsg( ) to display information to the console. Use sprintf( ) to log data into memory:
char * ptr; ... ptr = (char *) malloc (SIZE_OF_BUFFER); ... void myISR () { ... ptr += sprintf (ptr, "%d", data);

Write data into a location of memory that is not cleared on reboot. This is particularly helpful when debugging interrupts that are crashing the system.
Tornado Device Driver Workshop Copyright Wind River Systems Wind River Systems

3-25

How do you nd a memory location that is not cleared on reboot? This requires some trial and error. The most common place to nd this is between the end of the Interrupt Vector Table (typically address 00x400) and the beginning of vxWorks (typically loaded at 0x1000), e.g. address 0x400. You could write to the location you are interested in, reboot the system and check to see if the contents of the memory have changed.

Polling and Interrupt Handling


Overview Polling Interrupt Handling 3.4 Design Considerations

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-26

Task Synchronization
Device Poll Task Task A

Task A waits until an event occurs on the device by calling semTake( ). When the polling task detects the event, it calls semGive( ). Task A returns from the semTake( ).

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-27

The event could be:


q

a state change data received device available for writing an error condition

To synchronize multiple tasks, have the poll task call semFlush( ) instead of semGive( ).

Task Synchronization
Device ISR Task

Task executes semTake( ) and blocks. When device receives data it generates an interrupt. The ISR calls semGive( ). The task returns from the semTake( ).

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-28

Data Buffering
Device Poll Task buffer task

When data is available on device, the poll task reads it and puts it in shared memory, ring buffer, linked list, pipe or message queue. Cooperating task gets data from buffer.

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-29

For output reverse process: Task writes data into buffer. When device is ready to receive data, poll task copies data from buffer to device.
q q

Advantages of using a pipe or message queue: Provides task synchronization Guards against mutual exclusion problems
q q q

If shared memory, ring buffers, or linked lists are used, the driver must: insure mutual exclusion, if necessary provide its own means of task synchronization
q

Data Buffering
Device ISR buffer task

When data available on device, the device generates an interrupt. In the ISR, read data from device and put it on a ring buffer, pipe or message queue. Task reads data from device by getting data from buffer.

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-30

As we saw with polled devices:


q

pipes and message queues have the advantage of providing built-in mutual exclusion and task synchronization facilities. shared memory, or ring buffers provide no mutual exclusion protection or task synchronization facilities

Design Questions: Speed vs. Robustness


The assumptions made dictate design choices:
q

Assumptions about the hardware environment


multiple I/O boards? always have the same jumper settings?

Assumptions about the intended use


always have the same devices connected? will the action to be performed after an event ever change?

The more that may be assumed, the faster the driver can be. The nature of the device may dictate a certain level of performance (i.e. there may be timing restrictions). When in doubt, dont assume!
Tornado Device Driver Workshop Copyright Wind River Systems Wind River Systems

3-31

Design Questions: Who Handles the Action?


Typically, the driver handles the events (the hardware changed) and leaves it to an application program to handle the actions (what to do about it). Sometimes it is not obvious what constitutes an event. This scheme, although exible, typically requires a synchronization and data communication mechanism. Which is most appropriate depends on speed vs. robustness.

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-32

Using semaphores for synchronization is very fast but does not provide any data.

Using message queues provides both synchronization and data communication. Using pipes provides the benets of message queues plus those of the standard I/O system interface.

Case Study
Remote RR Crossing
Sensor

Input Board

Status Light

Output Board

Input board not interrupt driven. Status Light should reect status of remote railroad crossing.

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-33

How do you write your driver?


q

Will the number of railroad crossings change? Will the method of monitoring the railroad crossings ever change? Could the action (lighting the light) change? What is more critical: speed or extensibility/maintainability?

Driver Cautions
Mutual exclusion
q

Is required for multiple tasks modifying data structures at the same time Is required for multiple tasks attempting to program the device at the same time Is provided by mutual exclusion semaphores

Race conditions
q

Can be avoided with mutual exclusion semaphores or taskLock( ) Avoidance may require non-atomic test and set when the condition tested may be changed by a preempting task
Copyright Wind River Systems Wind River Systems

Tornado Device Driver Workshop

3-34

Remember that your ISR can cause mutual exclusion and race conditions.

Try to restructure your design to avoid task/interrupt conicts.

As a last resort, use intLock( ) to lock out interrupts.

taskLock/taskUnlock
taskLock( ) prevents task preemption until taskUnlock( ) is called. Does not disable interrupts. Task preemption is not enabled until as many taskUnlocks as taskLocks have been called. Performing any action which blocks will enable task preemption.

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-35

Example:
taskLock(); ... /* critical region: task preemption disabled */ ... taskUnlock();

intLock/intUnlock
intLock( ) disables interrupts until intUnlock( ) is called. Returns an architecture dependent integer that must be passed to intUnlock( ). Does not disable task preemption. May be called at interrupt time.

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-36

Example:
key = intLock(); ... /* critical region: interrupts disabled */ ... intUnlock (key);

Interrupt Level Caveat


VxWorks enables interrupts on context switches. Use intLock( ) to mask your interrupts; do not raise the interrupt level at task time.

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-37

The intLevelSet( ) routine (which allows raising the interrupt level) should only be used at interrupt time. If used at task time, a higher priority interrupt could cause a context switch which would end up enabling interrupts.

Test and Set


BOOL sysBusTas (addr)
If the value pointed to by addr is not set, function sets it and returns TRUE; otherwise returns FALSE. The test-and-set is an atomic operation. Example:
char * addr; ... /* wait until available */ while (sysBusTas (addr) == FALSE) taskDelay (ticks); ... /* reset test address when done */ *addr = 0;

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-38

There is a vxTas( ) routine, written in assembler, that could be used for local test-and-set operations. Not all boards support sysBusTas( ).

Review
Polling techniques. Mutual exclusion & race conditions tools: Routines semGive/semTake taskLock/taskUnlock intLock/intUnlock sysBusTas Description Uses mutex semaphores Prevents/allows task preemption Prevents/allows interrupts Atomically tests-and-sets a memory location

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-39

Review
Routine intConnect sysIntEnable INUM_TO_IVEC Description Installs an ISR Enables a VMEbus interrupt level Converts interrupt number to vector

Tornado Device Driver Workshop

Copyright Wind River Systems Wind River Systems

3-40

You might also like