Spawn and Synchronize Execution of RTOS Task
This example shows how to simulate and generate code for asynchronous events on a real-time multitasking system. The model contains an Async Interrupt block, a Task Sync block, asynchronously executed subsystems Count
and Algorithm
, and Rate Transition blocks. The Async Interrupt block creates two Versa Module Eurocard (VME) interrupt service routines (ISRs) that pass interrupt signals to subsystem Count
and the Task Sync block. Count
executes at interrupt level. Algorithm
executes as an asynchronous task. The code that the code generator produces for subsystems is tailored for the VxWorks® operating system.
About the Example Model
Open the example model rtwdemo_async
.
You can place an Async Interrupt block between a simulated interrupt source and one of these model elements:
Function call subsystem
Task Sync block
A Stateflow® chart configured for a function call input event
A referenced model with an Inport block that connects to one of the preceding model elements
The Async Interrupt and Task Sync blocks enable the subsystems to execute asynchronously. Reconfigure the Async Interrupt and Task Sync blocks to generate code for an alternative run-time environment.
Count
represents a simple interrupt service routine (ISR) that executes at interrupt level. It is best to keep ISRs as simple as possible. This subsystem includes only a Discrete-Time Integrator block.
Algorithm
includes more substance. It includes multiple blocks and produces two output values. Execution of larger subsystems at interrupt level can significantly impact response time for interrupts of equal and lower priority in the system. A better solution for larger subsystems is to use the Task Sync block to represent the ISR for the function-call subsystem.
The Async Interrupt block generates calls to ISRs. Place the block between a simulated interrupt source and one of the following:
Function call subsystem
Task Sync block
A Stateflow chart configured for a function call input event
For each specified interrupt level, the block generates a Versa Module Eurocard (VME) ISR that executes the connected subsystem, Task Sync block, or chart.
In the example model, the Async Interrupt block is configured for VME interrupts 1 and 2, by using interrupt vector offsets 192 and 193. Interrupt 1 connects directly to subsystem Count
. Interrupt 2 connects to a Task Sync block, which serves as the ISR for Algorithm
. Place a Task Sync block in one of the following locations:
Between an Async Interrupt block and a function-call subsystem or Stateflow chart.
At the output port of a Stateflow chart that has an event,
Output to Simulink
, that you configure as a function call.
In the example model, the Task Sync block is between the Async Interrupt block and function-call subsystem Algorithm
. The Task Sync block is configured with the task name Task()
, a priority of 50, a stack size of 8192, and data transfers of the task synchronized with the caller task. The spawned task uses a semaphore to synchronize task execution. The Async Interrupt block triggers a release of the task semaphore.
Four Rate Transition blocks handle data transfers between ports that operate at different rates. In two instances, protected Rate Transition blocks protect data transfers (prevent them from being preempted and corrupted). In the other two instances, unprotected Rate Transition blocks introduce no special behavior. Their presence informs Simulink® of a rate transition.
The code generated for the Async Interrupt and Task Sync blocks is tailored for the example RTOS (VxWorks). However, you can modify the blocks to generate code specific to your run-time environment.
Data Transfer Assumptions
Data transfers occur between one reading task and one writing task.
A read or write operation on a byte-size variable is atomic.
When two tasks interact, only one can preempt the other.
For periodic tasks, the task with the faster rate has higher priority than the task with the slower rate. The task with the faster rate preempts the tasks with slower rates.
Tasks run on a single processor. Time slicing is not allowed.
Processes do not stop and restart, especially while data is being transferred between tasks.
Simulate the Model
Simulate the model. By default, the model is configured to show sample times in different colors. Discrete sample times for input and output appear red and green, respectively. Constants are reddish-blue. Asynchronous interrupts and tasks are purple. The Rate Transition Blocks, which are a hybrid rate (their input and output sample times can differ), are yellow.
Generate Code and Report
Generate code and a code generation report for the model. Generated code for the Async Interrupt and Task Sync blocks is for the example RTOS (VxWorks). However, you can modify the blocks to generate code for another run-time environment.
1. Create a temporary folder for the build and inspection process.
2. Build the model.
### Starting build procedure for: rtwdemo_async Warning: Simulink Coder: The tornado.tlc target will be removed in a future release. ### Successful completion of code generation for: rtwdemo_async Build Summary Top model targets built: Model Action Rebuild Reason ================================================================================== rtwdemo_async Code generated. Code generation information file does not exist. 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 10.129s
Review Initialization Code
Open the generated source file rtwdemo_async.c
. The initialization code:
1. Creates and initializes the synchronization semaphore Task0_semaphore
.
*(SEM_ID *)rtwdemo_async_DW.SFunction_PWORK.SemID = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY); if (rtwdemo_async_DW.SFunction_PWORK.SemID == NULL) { printf("semBCreate call failed for block Task0.\n"); }
2. Spawns task task0
and assigns the task priority 50.
rtwdemo_async_DW.SFunction_IWORK.TaskID = taskSpawn("Task0", 50.0, VX_FP_TASK, 8192.0, (FUNCPTR)Task0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0); if (rtwdemo_async_DW.SFunction_IWORK.TaskID == ERROR) { printf("taskSpawn call failed for block Task0.\n"); } /* End of Start for S-Function (vxtask1): '<S4>/S-Function' */ /* 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);
3. Connects and enables ISR isr_num1_vec192
for interrupt 1 and ISR isr_num2_vec193
for interrupt 2.
{ int32_T i; /* InitializeConditions for RateTransition: '<Root>/Protected RT1' */ for (i = 0; i < 60; i++) { rtwdemo_async_DW.ProtectedRT1_Buffer[i] = 0.0; } /* End of InitializeConditions for RateTransition: '<Root>/Protected RT1' */ /* InitializeConditions for RateTransition: '<Root>/Protected RT2' */ for (i = 0; i < 60; i++) { rtwdemo_async_DW.ProtectedRT2_Buffer[i] = 0.0; } /* End of InitializeConditions for RateTransition: '<Root>/Protected RT2' */ /* SystemInitialize for S-Function (vxinterrupt1): '<Root>/Async Interrupt' incorporates: * SubSystem: '<Root>/Count' */ /* System initialize for function-call system: '<Root>/Count' */ /* InitializeConditions for DiscreteIntegrator: '<S2>/Integrator' */ rtwdemo_async_DW.Integrator_DSTATE_l = 0.0; rtwdemo_async_DW.Integrator_PREV_U_o = 0.0; /* SystemInitialize for Outport: '<Root>/Out1' incorporates: * Outport: '<S2>/Out' */ rtwdemo_async_Y.Out1 = 0.0; /* SystemInitialize for S-Function (vxinterrupt1): '<Root>/Async Interrupt' incorporates: * SubSystem: '<S3>/Subsystem' */ /* System initialize for function-call system: '<S3>/Subsystem' */ /* SystemInitialize for S-Function (vxtask1): '<S4>/S-Function' incorporates: * SubSystem: '<Root>/Algorithm' */ /* System initialize for function-call system: '<Root>/Algorithm' */ rtwdemo_async_M->Timing.clockTick2 = rtwdemo_async_M->Timing.clockTick4; /* InitializeConditions for DiscreteIntegrator: '<S1>/Integrator' */ rtwdemo_async_DW.Integrator_DSTATE = 0.0; /* InitializeConditions for Sum: '<S1>/Sum1' incorporates: * DiscreteIntegrator: '<S1>/Integrator' */ rtwdemo_async_DW.Integrator_PREV_U = 0.0; /* SystemInitialize for Sum: '<S1>/Sum' incorporates: * Outport: '<S1>/Out1' */ memset(&rtwdemo_async_B.Sum[0], 0, 60U * sizeof(real_T)); /* SystemInitialize for Outport: '<Root>/Out3' incorporates: * Outport: '<S1>/Out2' */ rtwdemo_async_Y.Out3 = 0.0; /* End of SystemInitialize for S-Function (vxtask1): '<S4>/S-Function' */ /* End of SystemInitialize for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ } /* Enable for S-Function (vxinterrupt1): '<Root>/Async Interrupt' incorporates: * SubSystem: '<Root>/Count' */ /* Enable for function-call system: '<Root>/Count' */ rtwdemo_async_DW.Count_RESET_ELAPS_T = true; /* Enable for DiscreteIntegrator: '<S2>/Integrator' */ rtwdemo_async_DW.Integrator_SYSTEM_ENABLE_h = 1U; /* Enable for S-Function (vxinterrupt1): '<Root>/Async Interrupt' incorporates: * SubSystem: '<S3>/Subsystem' */ /* Enable for function-call system: '<S3>/Subsystem' */ /* Enable for S-Function (vxtask1): '<S4>/S-Function' incorporates: * SubSystem: '<Root>/Algorithm' */ /* Enable for function-call system: '<Root>/Algorithm' */ rtwdemo_async_M->Timing.clockTick2 = rtwdemo_async_M->Timing.clockTick4; rtwdemo_async_DW.Algorithm_RESET_ELAPS_T = true; /* Enable for DiscreteIntegrator: '<S1>/Integrator' */ rtwdemo_async_DW.Integrator_SYSTEM_ENABLE = 1U; /* End of Enable for S-Function (vxtask1): '<S4>/S-Function' */ /* End of Enable for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ } /* Model terminate function */ static void rtwdemo_async_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' */ /* Terminate for S-Function (vxinterrupt1): '<Root>/Async Interrupt' incorporates: * SubSystem: '<S3>/Subsystem' */ /* Termination for function-call system: '<S3>/Subsystem' */ /* Terminate for S-Function (vxtask1): '<S4>/S-Function' */ /* VxWorks Task Block: '<S4>/S-Function' (vxtask1) */ /* Destroy task: Task0 */ taskDelete(rtwdemo_async_DW.SFunction_IWORK.TaskID); /* End of Terminate for S-Function (vxtask1): '<S4>/S-Function' */ /* End of Terminate for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ } /*========================================================================* * Start of Classic call interface * *========================================================================*/ void MdlOutputs(int_T tid) { rtwdemo_async_output(tid); } void MdlUpdate(int_T tid) { rtwdemo_async_update(tid); } void MdlInitializeSizes(void) { } void MdlInitializeSampleTimes(void) { } void MdlInitialize(void) { } void MdlStart(void) { rtwdemo_async_initialize(); } void MdlTerminate(void) { rtwdemo_async_terminate(); } /* Registration function */ RT_MODEL_rtwdemo_async_T *rtwdemo_async(void) { /* Registration code */ /* initialize non-finites */ rt_InitInfAndNaN(sizeof(real_T)); /* initialize real-time model */ (void) memset((void *)rtwdemo_async_M, 0, sizeof(RT_MODEL_rtwdemo_async_T)); /* Initialize timing info */ { int_T *mdlTsMap = rtwdemo_async_M->Timing.sampleTimeTaskIDArray; mdlTsMap[0] = 0; mdlTsMap[1] = 1; /* polyspace +2 MISRA2012:D4.1 [Justified:Low] "rtwdemo_async_M points to static memory which is guaranteed to be non-NULL" */ rtwdemo_async_M->Timing.sampleTimeTaskIDPtr = (&mdlTsMap[0]); rtwdemo_async_M->Timing.sampleTimes = (&rtwdemo_async_M->Timing.sampleTimesArray[0]); rtwdemo_async_M->Timing.offsetTimes = (&rtwdemo_async_M->Timing.offsetTimesArray[0]); /* task periods */ rtwdemo_async_M->Timing.sampleTimes[0] = (0.016666666666666666); rtwdemo_async_M->Timing.sampleTimes[1] = (0.05); /* task offsets */ rtwdemo_async_M->Timing.offsetTimes[0] = (0.0); rtwdemo_async_M->Timing.offsetTimes[1] = (0.0); } rtmSetTPtr(rtwdemo_async_M, &rtwdemo_async_M->Timing.tArray[0]); { int_T *mdlSampleHits = rtwdemo_async_M->Timing.sampleHitArray; int_T *mdlPerTaskSampleHits = rtwdemo_async_M->Timing.perTaskSampleHitsArray; rtwdemo_async_M->Timing.perTaskSampleHits = (&mdlPerTaskSampleHits[0]); mdlSampleHits[0] = 1; rtwdemo_async_M->Timing.sampleHits = (&mdlSampleHits[0]); } rtmSetTFinal(rtwdemo_async_M, 0.5); rtwdemo_async_M->Timing.stepSize0 = 0.016666666666666666; rtwdemo_async_M->Timing.stepSize1 = 0.05; rtwdemo_async_M->solverInfoPtr = (&rtwdemo_async_M->solverInfo); rtwdemo_async_M->Timing.stepSize = (0.016666666666666666); rtsiSetFixedStepSize(&rtwdemo_async_M->solverInfo, 0.016666666666666666); rtsiSetSolverMode(&rtwdemo_async_M->solverInfo, SOLVER_MODE_MULTITASKING); /* block I/O */ rtwdemo_async_M->blockIO = ((void *) &rtwdemo_async_B); (void) memset(((void *) &rtwdemo_async_B), 0, sizeof(B_rtwdemo_async_T)); /* states (dwork) */ rtwdemo_async_M->dwork = ((void *) &rtwdemo_async_DW); (void) memset((void *)&rtwdemo_async_DW, 0, sizeof(DW_rtwdemo_async_T)); /* external inputs */ rtwdemo_async_M->inputs = (((void*)&rtwdemo_async_U)); (void)memset(&rtwdemo_async_U, 0, sizeof(ExtU_rtwdemo_async_T)); /* external outputs */ rtwdemo_async_M->outputs = (&rtwdemo_async_Y); (void)memset(&rtwdemo_async_Y, 0, sizeof(ExtY_rtwdemo_async_T)); /* Initialize Sizes */ rtwdemo_async_M->Sizes.numContStates = (0);/* Number of continuous states */ rtwdemo_async_M->Sizes.numY = (3); /* Number of model outputs */ rtwdemo_async_M->Sizes.numU = (60); /* Number of model inputs */ rtwdemo_async_M->Sizes.sysDirFeedThru = (1);/* The model is direct feedthrough */ rtwdemo_async_M->Sizes.numSampTimes = (2);/* Number of sample times */ rtwdemo_async_M->Sizes.numBlocks = (19);/* Number of blocks */ rtwdemo_async_M->Sizes.numBlockIO = (6);/* Number of block outputs */ return rtwdemo_async_M; } /*========================================================================* * End of Classic call interface * *========================================================================*/
The order of these operations is important. Before the code generator enables the interrupt that activates the task, it must spawn the task.
Review Task and Task Synchronization Code
In the generated source file rtwdemo_async.c
, review the task and task synchronization code.
The code generator produces the code for function Task0
from the Task Sync block. That function includes a small amount of interrupt-level code and runs as an RTOS task.
The task waits in an infinite for
loop until the system releases a synchronization semaphore. If the system releases the semaphore, the function updates its task timer and calls the code generated for the Algorithm
subsystem.
In the example model, the Synchronize the data transfer of this task with the caller task parameter for the Task Sync block is set. This parameter setting updates the timer associated with the Task Sync block (rtM->Timing.clockTick2
) with the value of the timer that the Async Interrupt block (rtM->Timing.clockTick3
) maintains. As a result, code for blocks within the Algorithm
subsystem use timer values that are based on the time of the most recent interrupt, rather than the most recent activation of Task0
.
{ /* Wait for semaphore to be released by system: rtwdemo_async/Task Sync */ for (;;) { if (semTake(*(SEM_ID *)rtwdemo_async_DW.SFunction_PWORK.SemID,NO_WAIT) != ERROR) { logMsg("Rate for Task Task0() too fast.\n",0,0,0,0,0,0); #if STOPONOVERRUN logMsg("Aborting real-time simulation.\n",0,0,0,0,0,0); semGive(stopSem); return(ERROR); #endif } else { semTake(*(SEM_ID *)rtwdemo_async_DW.SFunction_PWORK.SemID, WAIT_FOREVER); } /* Use the upstream clock tick counter for this Task. */ rtwdemo_async_M->Timing.clockTick2 = rtwdemo_async_M->Timing.clockTick4; /* Call the system: '<Root>/Algorithm' */ { int32_T i; int32_T i_0; /* RateTransition: '<Root>/Protected RT1' */ i = rtwdemo_async_DW.ProtectedRT1_ActiveBufIdx * 60; for (i_0 = 0; i_0 < 60; i_0++) { rtwdemo_async_B.ProtectedRT1[i_0] = rtwdemo_async_DW.ProtectedRT1_Buffer[i_0 + i]; } /* End of RateTransition: '<Root>/Protected RT1' */ /* S-Function (vxtask1): '<S4>/S-Function' */ /* Output and update for function-call system: '<Root>/Algorithm' */ { real_T Sum; int32_T i; rtwdemo_async_M->Timing.clockTick2 = rtwdemo_async_M->Timing.clockTick4; if (rtwdemo_async_DW.Algorithm_RESET_ELAPS_T) { rtwdemo_async_DW.Algorithm_ELAPS_T = 0U; } else { rtwdemo_async_DW.Algorithm_ELAPS_T = rtwdemo_async_M->Timing.clockTick2 - rtwdemo_async_DW.Algorithm_PREV_T; } rtwdemo_async_DW.Algorithm_PREV_T = rtwdemo_async_M->Timing.clockTick2; rtwdemo_async_DW.Algorithm_RESET_ELAPS_T = false; /* DiscreteIntegrator: '<S1>/Integrator' */ if (rtwdemo_async_DW.Integrator_SYSTEM_ENABLE == 0) { /* DiscreteIntegrator: '<S1>/Integrator' */ rtwdemo_async_DW.Integrator_DSTATE += 0.016666666666666666 * (real_T) rtwdemo_async_DW.Algorithm_ELAPS_T * rtwdemo_async_DW.Integrator_PREV_U; } /* End of DiscreteIntegrator: '<S1>/Integrator' */ /* Outport: '<Root>/Out3' incorporates: * SignalConversion generated from: '<S1>/Out2' */ rtwdemo_async_Y.Out3 = rtwdemo_async_DW.Integrator_DSTATE; /* Sum: '<S1>/Sum1' */ rtwdemo_async_DW.Integrator_PREV_U = -0.0; for (i = 0; i < 60; i++) { /* Sum: '<S1>/Sum' incorporates: * Constant: '<S1>/Offset' */ Sum = rtwdemo_async_B.ProtectedRT1[i] + 1.25; rtwdemo_async_B.Sum[i] = Sum; /* Sum: '<S1>/Sum1' */ rtwdemo_async_DW.Integrator_PREV_U += Sum; } /* Update for DiscreteIntegrator: '<S1>/Integrator' */ rtwdemo_async_DW.Integrator_SYSTEM_ENABLE = 0U; } /* End of Outputs for S-Function (vxtask1): '<S4>/S-Function' */ /* RateTransition: '<Root>/Protected RT2' */ for (i = 0; i < 60; i++) { rtwdemo_async_DW.ProtectedRT2_Buffer[i + (rtwdemo_async_DW.ProtectedRT2_ActiveBufIdx == 0) * 60] = rtwdemo_async_B.Sum[i]; } rtwdemo_async_DW.ProtectedRT2_ActiveBufIdx = (int8_T) (rtwdemo_async_DW.ProtectedRT2_ActiveBufIdx == 0); /* End of RateTransition: '<Root>/Protected RT2' */ } } } /* 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 */ rtwdemo_async_M->Timing.clockTick3 = tickGet(); /* disable interrupts (system is configured as non-preemptive) */ lock = intLock(); /* save floating point context */ fppSave(&context); /* Call the system: '<Root>/Count' */ { /* S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ /* Output and update for function-call system: '<Root>/Count' */ if (rtwdemo_async_DW.Count_RESET_ELAPS_T) { rtwdemo_async_DW.Count_ELAPS_T = 0U; } else { rtwdemo_async_DW.Count_ELAPS_T = rtwdemo_async_M->Timing.clockTick3 - rtwdemo_async_DW.Count_PREV_T; } rtwdemo_async_DW.Count_PREV_T = rtwdemo_async_M->Timing.clockTick3; rtwdemo_async_DW.Count_RESET_ELAPS_T = false; /* DiscreteIntegrator: '<S2>/Integrator' */ if (rtwdemo_async_DW.Integrator_SYSTEM_ENABLE_h == 0) { /* DiscreteIntegrator: '<S2>/Integrator' */ rtwdemo_async_DW.Integrator_DSTATE_l += 0.016666666666666666 * (real_T) rtwdemo_async_DW.Count_ELAPS_T * rtwdemo_async_DW.Integrator_PREV_U_o; } /* End of DiscreteIntegrator: '<S2>/Integrator' */ /* Outport: '<Root>/Out1' incorporates: * SignalConversion generated from: '<S2>/Out' */ rtwdemo_async_Y.Out1 = rtwdemo_async_DW.Integrator_DSTATE_l; /* Update for DiscreteIntegrator: '<S2>/Integrator' incorporates: * Constant: '<S2>/Constant' */ rtwdemo_async_DW.Integrator_SYSTEM_ENABLE_h = 0U; rtwdemo_async_DW.Integrator_PREV_U_o = 1.0; /* End of Outputs for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ } /* restore floating point context */ fppRestore(&context); /* re-enable interrupts */ intUnlock(lock); } /* VxWorks Interrupt Block: '<Root>/Async Interrupt' */ void isr_num2_vec193(void) { /* Use tickGet() as a portable tick counter example. A much higher resolution can be achieved with a hardware counter */ rtwdemo_async_M->Timing.clockTick4 = tickGet(); /* Call the system: '<S3>/Subsystem' */ { /* S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ /* Output and update for function-call system: '<S3>/Subsystem' */ /* S-Function (vxtask1): '<S4>/S-Function' */ /* VxWorks Task Block: '<S4>/S-Function' (vxtask1) */ /* Release semaphore for system task: Task0 */ semGive(*(SEM_ID *)rtwdemo_async_DW.SFunction_PWORK.SemID); /* End of Outputs for S-Function (vxtask1): '<S4>/S-Function' */ /* End of Outputs for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ } }
The code generator produces code for ISRs isr_num1_vec192
and isr_num2_vec293
. ISR isr_num2_vec192
:
Disables interrupts.
Saves floating-point context.
Calls the code generated for the subsystem that connects to the referenced model Inport block, which receives the interrupt.
Restores floating-point context.
Reenables interrupts.
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 */ rtwdemo_async_M->Timing.clockTick3 = tickGet(); /* disable interrupts (system is configured as non-preemptive) */ lock = intLock(); /* save floating point context */ fppSave(&context); /* Call the system: '<Root>/Count' */ { /* S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ /* Output and update for function-call system: '<Root>/Count' */ if (rtwdemo_async_DW.Count_RESET_ELAPS_T) { rtwdemo_async_DW.Count_ELAPS_T = 0U; } else { rtwdemo_async_DW.Count_ELAPS_T = rtwdemo_async_M->Timing.clockTick3 - rtwdemo_async_DW.Count_PREV_T; } rtwdemo_async_DW.Count_PREV_T = rtwdemo_async_M->Timing.clockTick3; rtwdemo_async_DW.Count_RESET_ELAPS_T = false; /* DiscreteIntegrator: '<S2>/Integrator' */ if (rtwdemo_async_DW.Integrator_SYSTEM_ENABLE_h == 0) { /* DiscreteIntegrator: '<S2>/Integrator' */ rtwdemo_async_DW.Integrator_DSTATE_l += 0.016666666666666666 * (real_T) rtwdemo_async_DW.Count_ELAPS_T * rtwdemo_async_DW.Integrator_PREV_U_o; } /* End of DiscreteIntegrator: '<S2>/Integrator' */ /* Outport: '<Root>/Out1' incorporates: * SignalConversion generated from: '<S2>/Out' */ rtwdemo_async_Y.Out1 = rtwdemo_async_DW.Integrator_DSTATE_l; /* Update for DiscreteIntegrator: '<S2>/Integrator' incorporates: * Constant: '<S2>/Constant' */ rtwdemo_async_DW.Integrator_SYSTEM_ENABLE_h = 0U; rtwdemo_async_DW.Integrator_PREV_U_o = 1.0; /* End of Outputs for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ } /* restore floating point context */ fppRestore(&context); /* re-enable interrupts */ intUnlock(lock); } /* VxWorks Interrupt Block: '<Root>/Async Interrupt' */
ISR isr_num2_vec293
maintains a timer that stores the tick count at the time that the interrupt occurs. After updating the timer, the ISR releases the semaphore that activates Task0
.
/* Spawned with priority: 50 */ void Task0(void) { /* Wait for semaphore to be released by system: rtwdemo_async/Task Sync */ for (;;) { if (semTake(*(SEM_ID *)rtwdemo_async_DW.SFunction_PWORK.SemID,NO_WAIT) != ERROR) { logMsg("Rate for Task Task0() too fast.\n",0,0,0,0,0,0); #if STOPONOVERRUN logMsg("Aborting real-time simulation.\n",0,0,0,0,0,0); semGive(stopSem); return(ERROR); #endif } else { semTake(*(SEM_ID *)rtwdemo_async_DW.SFunction_PWORK.SemID, WAIT_FOREVER); } /* Use the upstream clock tick counter for this Task. */ rtwdemo_async_M->Timing.clockTick2 = rtwdemo_async_M->Timing.clockTick4; /* Call the system: '<Root>/Algorithm' */ { int32_T i; int32_T i_0; /* RateTransition: '<Root>/Protected RT1' */ i = rtwdemo_async_DW.ProtectedRT1_ActiveBufIdx * 60; for (i_0 = 0; i_0 < 60; i_0++) { rtwdemo_async_B.ProtectedRT1[i_0] = rtwdemo_async_DW.ProtectedRT1_Buffer[i_0 + i]; } /* End of RateTransition: '<Root>/Protected RT1' */ /* S-Function (vxtask1): '<S4>/S-Function' */ /* Output and update for function-call system: '<Root>/Algorithm' */ { real_T Sum; int32_T i; rtwdemo_async_M->Timing.clockTick2 = rtwdemo_async_M->Timing.clockTick4; if (rtwdemo_async_DW.Algorithm_RESET_ELAPS_T) { rtwdemo_async_DW.Algorithm_ELAPS_T = 0U; } else { rtwdemo_async_DW.Algorithm_ELAPS_T = rtwdemo_async_M->Timing.clockTick2 - rtwdemo_async_DW.Algorithm_PREV_T; } rtwdemo_async_DW.Algorithm_PREV_T = rtwdemo_async_M->Timing.clockTick2; rtwdemo_async_DW.Algorithm_RESET_ELAPS_T = false; /* DiscreteIntegrator: '<S1>/Integrator' */ if (rtwdemo_async_DW.Integrator_SYSTEM_ENABLE == 0) { /* DiscreteIntegrator: '<S1>/Integrator' */ rtwdemo_async_DW.Integrator_DSTATE += 0.016666666666666666 * (real_T) rtwdemo_async_DW.Algorithm_ELAPS_T * rtwdemo_async_DW.Integrator_PREV_U; } /* End of DiscreteIntegrator: '<S1>/Integrator' */ /* Outport: '<Root>/Out3' incorporates: * SignalConversion generated from: '<S1>/Out2' */ rtwdemo_async_Y.Out3 = rtwdemo_async_DW.Integrator_DSTATE; /* Sum: '<S1>/Sum1' */ rtwdemo_async_DW.Integrator_PREV_U = -0.0; for (i = 0; i < 60; i++) { /* Sum: '<S1>/Sum' incorporates: * Constant: '<S1>/Offset' */ Sum = rtwdemo_async_B.ProtectedRT1[i] + 1.25; rtwdemo_async_B.Sum[i] = Sum; /* Sum: '<S1>/Sum1' */ rtwdemo_async_DW.Integrator_PREV_U += Sum; } /* Update for DiscreteIntegrator: '<S1>/Integrator' */ rtwdemo_async_DW.Integrator_SYSTEM_ENABLE = 0U; } /* End of Outputs for S-Function (vxtask1): '<S4>/S-Function' */ /* RateTransition: '<Root>/Protected RT2' */ for (i = 0; i < 60; i++) { rtwdemo_async_DW.ProtectedRT2_Buffer[i + (rtwdemo_async_DW.ProtectedRT2_ActiveBufIdx == 0) * 60] = rtwdemo_async_B.Sum[i]; } rtwdemo_async_DW.ProtectedRT2_ActiveBufIdx = (int8_T) (rtwdemo_async_DW.ProtectedRT2_ActiveBufIdx == 0); /* End of RateTransition: '<Root>/Protected RT2' */ } } } /* 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 */ rtwdemo_async_M->Timing.clockTick3 = tickGet(); /* disable interrupts (system is configured as non-preemptive) */ lock = intLock(); /* save floating point context */ fppSave(&context); /* Call the system: '<Root>/Count' */ { /* S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ /* Output and update for function-call system: '<Root>/Count' */ if (rtwdemo_async_DW.Count_RESET_ELAPS_T) { rtwdemo_async_DW.Count_ELAPS_T = 0U; } else { rtwdemo_async_DW.Count_ELAPS_T = rtwdemo_async_M->Timing.clockTick3 - rtwdemo_async_DW.Count_PREV_T; } rtwdemo_async_DW.Count_PREV_T = rtwdemo_async_M->Timing.clockTick3; rtwdemo_async_DW.Count_RESET_ELAPS_T = false; /* DiscreteIntegrator: '<S2>/Integrator' */ if (rtwdemo_async_DW.Integrator_SYSTEM_ENABLE_h == 0) { /* DiscreteIntegrator: '<S2>/Integrator' */ rtwdemo_async_DW.Integrator_DSTATE_l += 0.016666666666666666 * (real_T) rtwdemo_async_DW.Count_ELAPS_T * rtwdemo_async_DW.Integrator_PREV_U_o; } /* End of DiscreteIntegrator: '<S2>/Integrator' */ /* Outport: '<Root>/Out1' incorporates: * SignalConversion generated from: '<S2>/Out' */ rtwdemo_async_Y.Out1 = rtwdemo_async_DW.Integrator_DSTATE_l; /* Update for DiscreteIntegrator: '<S2>/Integrator' incorporates: * Constant: '<S2>/Constant' */ rtwdemo_async_DW.Integrator_SYSTEM_ENABLE_h = 0U; rtwdemo_async_DW.Integrator_PREV_U_o = 1.0; /* End of Outputs for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ } /* restore floating point context */ fppRestore(&context); /* re-enable interrupts */ intUnlock(lock); } /* VxWorks Interrupt Block: '<Root>/Async Interrupt' */
Review Task Termination Code
The Task Sync block generates the following termination code.
static void rtwdemo_async_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' */ /* Terminate for S-Function (vxinterrupt1): '<Root>/Async Interrupt' incorporates: * SubSystem: '<S3>/Subsystem' */ /* Termination for function-call system: '<S3>/Subsystem' */ /* Terminate for S-Function (vxtask1): '<S4>/S-Function' */ /* VxWorks Task Block: '<S4>/S-Function' (vxtask1) */ /* Destroy task: Task0 */ taskDelete(rtwdemo_async_DW.SFunction_IWORK.TaskID); /* End of Terminate for S-Function (vxtask1): '<S4>/S-Function' */ /* End of Terminate for S-Function (vxinterrupt1): '<Root>/Async Interrupt' */ }