Professional Documents
Culture Documents
3
Polling and Interrupt Handling
3-1
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. ...
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
3-4
3-5
Task polling during idle times Task polling at periodic intervals Using watchdog timers Using auxiliary clock
Task synchronization
Approach Overview
Application Application
Driver
Driver
Device
Device
3-6
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
3-7
3-8
3-9
What are the consequences of this choice? Please note that error checking has been removed in the code above.
3-10
3-11
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.
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.
3-14
Debugging an ISR.
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)
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
3-16
Floating point registers are NOT automatically saved and restored by interrrupt wrapper routine.
3-17
3-18
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
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( )
Dont use 0 for a tid, e.g. taskSuspend (0) Dont use mutual exclusion semaphores
3-20
I/O system calls, e.g. read( ) and write( ), typically block until the device is ready to satisfy the request.
3-21
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.
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.
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
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.
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.
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( ).
3-27
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( ).
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.
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.
3-30
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
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
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.
3-33
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
3-34
Remember that your ISR can cause mutual exclusion and race conditions.
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.
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.
3-36
Example:
key = intLock(); ... /* critical region: interrupts disabled */ ... intUnlock (key);
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.
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
3-39
Review
Routine intConnect sysIntEnable INUM_TO_IVEC Description Installs an ISR Enables a VMEbus interrupt level Converts interrupt number to vector
3-40