Main Content

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.

Example model rtwdemo_async, which shows an Async Interrup block configured to service two inputerrupt sources

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

How changes made to plant or controller model that are in a library get propagated to models

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.

Example model rtwdemo_async, which shows an Async Interrupt block configured to service two inputerrupt sources

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.

Example model rtwdemo_async, which shows an Async Interrupt block configured to service two interrupt sources

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.

Block parameter settings for Async Interrupt block

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 model_initialize function, as shown in this code fragment.

/* 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 and int_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 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 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);
}

Related Topics