Generate Interrupt Service Routines
To generate an interrupt service routine (ISR) associated with a specific VME interrupt level for an example RTOS (for example, VxWorks®), use the Async Interrupt block. The Async Interrupt block enables the specified interrupt level and installs an ISR that calls a connected function call subsystem.
You can also use the Async Interrupt block in a simulation. It provides an input port that you can enable and connect to a simulated interrupt source.
Note
The operating system integration techniques that are demonstrated in this section use blocks that are in the Interrupt Templates block library. The blocks in that library provide starting point examples to help you develop custom blocks for a target environment.
Connecting the Async Interrupt Block
To generate an ISR, connect an output of the Async Interrupt block to the control input of:
A function call subsystem
The input of a Task Sync block
The input to a Stateflow® chart configured for a function call input event
Example model rtwdemo_async
shows an Async Interrupt block
that is configured to service two interrupt sources. Each of the two output signals is
connected to a function call subsystem.
Requirements and Restrictions
The Async Interrupt block supports VME interrupts 1 through 7.
The Async Interrupt block uses these system calls to the example RTOS (VxWorks):
sysIntEnable
sysIntDisable
intConnect
intLock
intUnlock
tickGet
Performance Considerations
Execution of large subsystems at interrupt level can have a significant impact on interrupt response time for interrupts of equal and lower priority in the system. It is best to keep ISRs as short as possible. Connect only function call subsystems that contain a small number of blocks to an Async Interrupt block.
A better solution for large subsystems is to use the Task Sync block to
synchronize the execution of the function call subsystem to a RTOS task. Place the
Task Sync block between the Async Interrupt block and the
function call subsystem. The Async Interrupt block installs the Task
Sync block as the ISR. The ISR releases a synchronization semaphore (performs a
semGive
) to the task, and returns immediately from interrupt level.
The task is then scheduled and run by the RTOS (VxWorks). See Spawn and Synchronize Execution of RTOS Task for more information.
Dual-Model Approach for Developing Real-Time Systems that Include ISRs
When developing a real-time system that includes ISRs, consider using a dual-model approach. Develop one model that includes a plant and a controller for simulation, and another model that includes only the controller for code generation. By using a Simulink® library, you can implement changes to both models simultaneously. This figure shows how changes made to the plant or controller, both of which are in a library, are propagated to the models.
Dual-Model Use of Async Interrupt Block for Simulation and Code Generation
A single-model approach is also possible. The Plant component of the model is active only during simulation. For code generation, you switch out the Plant components out of the system and you generate code only for the interrupt block and controller parts of the model.
Dual-Model Approach: Simulation
Example model rtwdemo_async
shows the dual-model approach to modeling.
During simulation, the Pulse Generator blocks provide simulated interrupt
signals.
During simulation:
When the value of the input port is nonzero, Simulink imitates the behavior of each interrupt by calling the destination function unconditionally where the interrupt occurs.
Subsystems connected to Async Interrupt block output ports execute in order of their priority in the RTOS (in this example, VxWorks). If two or more interrupt signals occur simultaneously, the Async Interrupt block executes the downstream systems in the order specified by their interrupt levels (level 7 gets the highest priority). The first input element maps to the first output element.
You can use the Async Interrupt block in a simulation without enabling the
simulation input. The Async Interrupt block inherits the base rate of the
model and calls the connected subsystems in order of their priorities in the RTOS. (In this
case, the Async Interrupt block behaves as if inputs receive a
1
simultaneously.)
Dual-Model Approach: Code Generation
In the generated code for the example model:
Ground blocks provide input signals to the Variant Source block
The Async Interrupt block does not use its simulation input
The Ground blocks drive control input of the Variant Source block, so the code generator does not produce code for that signal path. The code generator does not produce code for blocks that drive the simulation control input to the Variant Source block because that path is not selected during code generation. However, the sample times of driving blocks for the simulation input to the Variant Source block contribute to the sample times supported in the generated code. To avoid including unnecessary sample times in the generated code, use the sample times of the blocks driving the simulation input in the model where generated code is intended.
The code generator produces standalone functions for the ISRs and the interrupt vector table is as follows:
Offset | |
---|---|
192 | &isr_num1_vec192() |
193 | &isr_num2_vec193() |
Consider the code generated from this model, assuming that the Async Interrupt block parameters are configured as shown in this figure.
Initialization Code
During code generation, the Async Interrupt block installs interrupt code in
the code generated for subsystem blocks as interrupt service routines. The interrupt
vectors for IRQ1
and IRQ2
are stored at locations
192
and 193
, relative to the base of the interrupt
vector table, as specified by the VME interrupt vector offset(s)
parameter.
Installing an ISR requires two RTOS (VxWorks) calls, int_connect
and
sysInt_Enable
. The Async Interrupt block inserts
these calls in the
function, as shown in this code fragment.model
_initialize
/* VxWorks Interrupt Block: '<Root>/Async Interrupt' */ /* Connect and enable ISR function: isr_num1_vec192 */ if( intConnect(INUM_TO_IVEC(192), isr_num1_vec192, 0) != OK) { printf("intConnect failed for ISR 1.\n"); } sysIntEnable(1); /* VxWorks Interrupt Block: '<Root>/Async Interrupt' */ /* Connect and enable ISR function: isr_num2_vec193 */ if( intConnect(INUM_TO_IVEC(193), isr_num2_vec193, 0) != OK) { printf("intConnect failed for ISR 2.\n"); } sysIntEnable(2);
The Async Interrupt block does not configure the hardware that generates the
interrupt. Typically, the interrupt source is a VME I/O board, which generates interrupts
for specific events (for example, at the end of an analog-to-digital conversion). You set
up the VME interrupt level and vector in registers or by using jumpers on the board. You
can use the mdlStart
routine of a user-written device driver
(S-function) to set up the registers and enable interrupt generation on the board. You
must match the interrupt level and vector specified in the Async Interrupt
block parameter dialog box to the level and vector set up on the I/O board.
Generated ISR Code
The actual ISR generated for IRQ1
in the
RTOS (VxWorks) is listed below.
/* VxWorks Interrupt Block: '<Root>/Async Interrupt' */ void isr_num1_vec192(void) { int_T lock; FP_CONTEXT context; /* Use tickGet() as a portable tick counter example. A much higher resolution can be achieved with a hardware counter */ Async_Code_M->Timing.clockTick2 = tickGet(); /* disable interrupts (system is configured as non-ive) */ lock = intLock(); /* save floating point context */ fppSave(&context); /* Call the system: <Root>/Subsystem A */ Count(0, 0); /* restore floating point context */ fppRestore(&context); /* re-enable interrupts */ intUnlock(lock); }
Note these features of the ISR:
Because of the setting of the Preemption Flag(s) parameter, the ISR is locked; that is, it cannot be preempted by a higher priority interrupt. The ISR is locked and unlocked in the example RTOS (VxWorks) by calls to the functions
int_lock
andint_unlock
.The connected subsystem,
Count
, is called from within the ISR.The
Count
function executes algorithmic (model) code. Therefore, the floating-point context is saved and restored across the call toCount
.The ISR maintains its own absolute time counter, which is distinct from other periodic base rate or subrate counters in the system. Timing data is maintained for use by code generated for blocks executed within the ISR that require absolute or elapsed time.
See Timers in Asynchronous Tasks for details.
Model Termination Code
The model termination function disables the interrupts in the RTOS (VxWorks):
/* Model terminate function */ void Async_Code_terminate(void) { /* VxWorks Interrupt Block: '<Root>/Async Interrupt' */ /* Disable interrupt for ISR system: isr_num1_vec192 */ sysIntDisable(1); /* VxWorks Interrupt Block: '<Root>/Async Interrupt' */ /* Disable interrupt for ISR system: isr_num2_vec193 */ sysIntDisable(2); }