Main Content

Generate Interrupt Service Routines

To generate an interrupt service routine (ISR) associated with a specific VME interrupt level for the example RTOS (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 can be enabled and connected to a simulated interrupt source.

Note

The operating system integration techniques that are demonstrated in this section use one or more blocks the blocks in the vxlib1 library. These blocks provide starting point examples to help you develop custom blocks for your 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

The next figure shows an Async Interrupt block configured to service two interrupt sources. The outputs (signal width 2) are connected to two function call subsystems.

Requirements and Restrictions

Note the following requirements and restrictions:

  • The Async Interrupt block supports VME interrupts 1 through 7.

  • The Async Interrupt block uses the following 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. As a general rule, 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. The Task Sync block is placed between the Async Interrupt block and the function call subsystem. The Async Interrupt block then 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 example RTOS (VxWorks). See Spawn and Synchronize Execution of RTOS Task for more information.

Using the Async Interrupt Block in Simulation and Code Generation

This section describes a dual-model approach to the development and implementation of real-time systems that include ISRs. In this approach, you develop one model that includes a plant and a controller for simulation, and another model that only includes the controller for code generation. Using a Simulink® library, you can implement changes to both models simultaneously. The next 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. In this approach, the Plant component of the model is active only in simulation. During code generation, the Plant components are effectively switched out of the system and code is generated only for the interrupt block and controller parts of the model. For an example of this approach, see the rtwdemo_async model.

Dual-Model Approach: Simulation

The following block diagram shows a simple model that illustrates the dual-model approach to modeling. During simulation, the Pulse Generator blocks provide simulated interrupt signals.

The simulated interrupt signals are routed through the Async Interrupt block's input port. Upon receiving a simulated interrupt, the block calls the connected subsystem.

During simulation, subsystems connected to Async Interrupt block outputs are executed in order of their priority in the example RTOS (VxWorks). In the event that 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 also use the Async Interrupt block in a simulation without enabling the simulation input. In such a case, 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 all inputs received a 1 simultaneously.)

Dual-Model Approach: Code Generation

In the generated code for the sample model,

  • Ground blocks provide input signals to the Environment Controller block

  • The Async Interrupt block does not use its simulation input

The Ground blocks drive control input of the Environment Controller block, so code is not generated for that signal path. The code generator does not produce code for blocks that drive the simulation control input to the Environment Controller block because that path is not selected during code generation. However, the sample times of driving blocks for the simulation input to the Environment Controller 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.

Standalone functions are installed as 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 the next figure.

Initialization Code

In the generated code, the Async Interrupt block installs the code in the 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 model_initialize function, as shown in the following code excerpt.

/* 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 hardware that generates the interrupt is not configured by the Async Interrupt block. Typically, the interrupt source is a VME I/O board, which generates interrupts for specific events (for example, end of A/D conversion). The VME interrupt level and vector are set up 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 dialog 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);
}

There are several features of the ISR that should be noted:

  • Because of the setting of the Preemption Flag(s) parameter, this 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 the int_lock and int_unlock functions.

  • 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 to Count.

  • 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 the use of any blocks executed within the ISR that require absolute or elapsed time.

    See Timers in Asynchronous Tasks for details.

Model Termination Code

The model's 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);
}

Related Topics