Generate Interrupt Service Routines
This example shows how to use the Async Interrupt block to generate an interrupt service routine (ISR) that is associated with a specific VME interrupt level for an RTOS (for example, VxWorks®). The Async Interrupt block enables a specified interrupt level and installs an ISR that calls a connected function-call subsystem.
For simulation, the Async Interrupt block 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 topic use blocks that are in the Interrupt Templates block library. The blocks in that library serve as examples to help you develop custom blocks for a specific target environment.
Connect Async Interrupt Block
To generate an ISR, connect an output of the Async Interrupt block to the control input of one of the following:
Function-call subsystem
Input of a Task Sync block
Input to a Stateflow® chart configured for a function-call input event
Open example model AsynchronousEventsTop.
open_system('AsynchronousEventsTop');
The model includes an Async Interrupt block that is configured to service two interrupt sources as follows:
VME interrupts 1 and 2
VME interrupt vector offsets 192 and 193
Simulink® task priorities 10 and 11
VME interrupt 1 is not preemptable and VME interrupt 2 is preemptable
Simulation input is enabled
Each of the two block output signals is connected to a function-call subsystem that is in referenced model AsynchronousEventsRef
.
Open the reference model AsynchronousEventsRef.
open_system('AsynchronousEventsRef');
Output signal Interrupt1 connects to function-call subsystem Count. Interrupt2 connects to function-call subsystem Algorithm. Asynchronous Task Specification blocks on the signal lines specify the priority (10 and 11) of the asynchronous task represented by the connected function-call subsystem.
The Async Interrupt block uses calls to these VxWorks® RTOS functions:
sysIntEnable
sysIntDisable
intConnect
intLock
intUnlock
tickGet
Interrupt Response Time 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. To minimize interrupt response time, connect the Async Interrupt block to function-call subsystems that contain a small number of blocks.
For a large subsystem, use the Task Sync block to synchronize the execution of the function-call subsystem to an 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 RTOS, in this case VxWorks®, schedules and runs the task.
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.
A single-model approach is also possible. In that case, the plant component of the model is active during simulation only. For code generation, you switch the plant component out of the system and generate code for the interrupt block and controller parts of the model.
Dual-Model Approach: Simulation
The AsynchronousEventsTop
model 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 fixed-step size (fundamental sample time) 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 code generated from the model:
Ground blocks provide input signals to the Variant Source block.
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 these standalone functions for the ISRs:
Offset 192: &isr_num1_vec192()
Offset 193: &isr_num2_vec193()
The generated code shown in the following sections is based on the Async Interrupt block in model AsynchronousEventsTop
being configured as follows:
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.
For VxWorks®, installing an ISR requires calls to system functions int_connect and sysInt_Enable
. The Async Interrupt block inserts these calls in the model_initialize function, as shown in this code fragment.
/* Model initialize function */ static void AsynchronousEventsTop_initialize(void) { /* Start for S-Function (vxinterrupt1): '<Root>/Async_Interrupt' */ /* 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); /* End of Start for S-Function (vxinterrupt1): '<root>/Async Interrupt' */ /* SystemInitialize for ModelReference: '<Root>/Model' incorporates: * Inport: '<Root>/In1_60hz' * Inport: '<Root>/In2_60_hz' * Inport: '<Root>/In3_60hz' * Outport: '<Root>/Out1' * Outport: '<Root>/Out2' * Outport: '<Root>/Out3' */ AsynchronousEventsRef_Init(&AsynchronousEventsTop_Y.Out1); AsynchronousEventsRef_Enable(); }
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 code generator produces this ISR for IRQ1:
/* VxWorks Interrupt Block: '<Root>/Async Interrupt' */ void isr_num1_vec192(void) { int_T lock; FP_CONTEXT context; /* disable interrupts (system is configured as non-preemptive) */ lock = intLock(); /* save floating point context */ fppSave(&context); /* Call the system: '<Root>/Model' */ { /* S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ /* ModelReference: '<Root>/Model' incorporates: * Inport: '<Root>/In1_60hz' * Inport: '<Root>/In2_60_hz' * Inport: '<Root>/In3_60hz' * Outport: '<Root>/Out1' * Outport: '<Root>/Out2' * Outport: '<Root>/Out3' */ AsynchronousEventsRef_Interrupt1(&AsynchronousEventsTop_Y.Out1); /* End of Outputs for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ } /* restore floating point context */ fppRestore(&context); /* re-enable interrupts */ intUnlock(lock); }
The code generator produces this ISR for IRQ2:
/* VxWorks Interrupt Block: '<Root>/Async Interrupt' */ void isr_num2_vec193(void) { FP_CONTEXT context; /* save floating point context */ fppSave(&context); /* Call the system: '<Root>/Model' */ { /* S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ /* ModelReference: '<Root>/Model' incorporates: * Inport: '<Root>/In1_60hz' * Inport: '<Root>/In2_60_hz' * Inport: '<Root>/In3_60hz' * Outport: '<Root>/Out1' * Outport: '<Root>/Out2' * Outport: '<Root>/Out3' */ AsynchronousEventsRef_Interrupt2(); /* End of Outputs for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ } /* restore floating point context */ fppRestore(&context); }
Note these features of the ISRs:
Because the Preemption Flag(s) parameter is selected for IRQ1, that ISR is locked. The ISR cannot be preempted by a higher priority interrupt. Calls to the function
intLock
andintUnlock
lock and unlock the ISR in the RTOS.The ISRs call the function generated for the subsystem
Count
orAlgorithm
in referenced modelAsynchronousEventsRef. Count
is connected toInterrupt1. Algorithm
is connected toInterrupt2.
The
Count
andAlgorithm
functions execute model algorithmic code. Therefore, the ISRs save and restore the floating-point context across the calls toCount
andAlgorithm
.
Termination Code
The model termination function disables interrupts in the RTOS.
/* Model terminate function */ static void AsynchronousEventsTop_terminate(void) { /* Terminate for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ /* 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); /* End of Terminate for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ }