Main Content

Generate Modular Function Code for Nonvirtual Subsystems

About Nonvirtual Subsystem Code Generation

默认情况下,生成代码的时候nonvirtual年代ubsystem, the code generator places internal data associated with a nonvirtual subsystem in the same data structure as internal data for the parent model. This can make it difficult to trace and test code, particularly for nonreusable subsystems. Also, in large models containing nonvirtual subsystems, data structures can become large and potentially difficult to compile.

To generate modular function code for nonvirtual subsystems, including atomic subsystems and conditionally executed subsystems, use the subsystem block parameterFunction with separate data. This block parameter instructs the code generator to produce a block I/O and DWork data structure for the nonvirtual subsystem function that is independent from the parent model data structures. As a result, generated code for the subsystem:

  • Is easier to trace.

  • Is easier to test.

  • Reduces the size of a model's global data structures.

To use theFunction with separate dataparameter,

  • Configure the model with an ERT-based system target file.

  • Configure the subsystem to be atomic or conditionally executed.

  • Set the subsystem block parameterFunction packagingtoNonreusable function.

To configure your subsystem for generating modular function code, invoke the Subsystem Parameters dialog box and make a series of selections to display and enable theFunction with separate dataoption. SeeConfigure Subsystem for Generating Modular Function CodeandModular Function Code for Nonvirtual Subsystemsfor details. For limitations that apply, seeNonvirtual Subsystem Modular Function Code Limitations.

For more information about generating code for atomic subsystems, see the sectionsControl Generation of Functions for SubsystemsandGenerate Code and Executables for Individual Subsystems.

Configure Subsystem for Generating Modular Function Code

  1. Verify that the model containing the subsystem uses an ERT-based system target file.

  2. Select the subsystem for which you want to generate modular function code and open the Subsystem Parameters dialog box. The dialog box for an atomic subsystem is shown below. (In the dialog box for a conditionally executed subsystem, the dialog box optionTreat as atomic unitis greyed out, and you can skip Step 3.)

  3. If the block parameterTreat as atomic unitis available for selection but not selected, the subsystem is neither atomic nor conditionally executed. Select the parameterTreat as atomic unit, which enables theFunction packagingparameter on theCode Generationtab. Select theCode Generationtab.

  4. For theFunction packagingparameter, selectNonreusable function. After you make this selection, theFunction with separate dataparameter is displayed.

    Before you generate code for the nonvirtual subsystem with theFunction with separate dataparameter selected, consider generating function code with the parameter cleared and save the generated function.cand.hfiles in a separate directory for later comparison.

  5. Select theFunction with separate dataparameter. Additional parameters appear.

    To control the naming of the generated subsystem function and the subsystem files, modify subsystem parametersFunction name optionsandFile name options.

  6. Save your subsystem parameter changes and exit the dialog box by clickingOK.

  7. Generate code for the subsystem and examine the generated files, including the function.cand.hfiles named according to your subsystem parameter specifications.

For more information on generating code for nonvirtual subsystems, seeControl Generation of Functions for Subsystems. For examples of generated subsystem function code, seeModular Function Code for Nonvirtual Subsystems.

Modular Function Code for Nonvirtual Subsystems

This example shows how to generate nonvirtual subsystem function code with theFunction with separate dataparameter cleared and selected and compares the results.

  1. Open example modelrtwdemo_atomic. Then, open theEmbedded Coderapp. Change the system target file toert.tlc.

    This model shows how to preserve the boundary of a virtual subsystem. When you select subsystem block parameterTreat as atomic unit, the code that the code generator produces for the subsystem executes as an atomic unit. When configured as atomic, you can specify how the code generator represents the subsystem by setting theFunction Packagingparameter on theCode Generationtab. You can specify that the subsystem is translated to one of these types of implementation:

    • Inline: Inlined subsystem code at call sites.

    • Function:void/voidfunction with I/O and internal data in the model global data structure.

    • Reusable Function: Reentrant function with data passed in as function arguments.

    • Auto: Code generator optimizes the implementation based on context.

  2. Double-click the SS1 subsystem and examine the contents.

    Then, close the subsystem window.

  3. Right-click the SS1 subsystem, select Block Parameters (Subsystem) from the context menu, and examine the settings. Simulink®and the code generator can avoid "artificial" algebraic loops when you make the subsystem atomic with subsystem parameterMinimize algebraic loop occurrences.

  4. Create a variant ofrtwdemo_atomicthat shows function codewithoutdata separation.

    1. In the Subsystem Parameters dialog box,

      • In theMaintab, selectTreat as atomic unit.

      • In theCode Generationtab:

        • SetFunction packagingtoNonreusable function.

        • SetFunction name optionstoUser specified.

        • SetFunction nametomyfun.

        • SetFile name optionstoUse function name. This setting is optional but simplifies the later task of code comparison by causing the atomic subsystem function code to be generated into filesmyfun.candmyfun.h.

      Donotselect theFunction with separate dataparameter.

    2. ClickApplyto apply the changes and clickOKto exit the dialog box.

    3. Save the model variant with a unique file name (for example,rtwdemo_atomic1) to a writable location.

  5. Create a variant ofrtwdemo_atomicthat shows function codewithdata separation.

    1. Open modelrtwdemo_atomic.

    2. Open theEmbedded Coderapp. Change the system target file toert.tlc.

    3. In the model canvas, right-click the SS1 subsystem and selectBlock Parameters (Subsystem). In the Subsystem Parameters dialog box,

      • In theMaintab, selectTreat as atomic unit.

      • In theCode Generationtab:

        • SetFunction packagingtoNonreusable function.

        • SetFunction name optionstoUser specified.

        • SetFunction nametomyfun.

        • SetFile name optionstoUse function name.

        • SelectFunction with separate data.

    4. ClickApplyto apply the change and clickOKto exit the dialog box.

    5. Save the model variant with a unique file name (for example,rtwdemo_atomic2) to a writable location.

  6. Generate code for each model (for example,rtwdemo_atomic1andrtwdemo_atomic2).

  7. Compare themodel.c/.handmyfun.c/.hfiles generated for the two models. For code comparison discussion, seeH File Differences for Nonvirtual Subsystem Function Data SeparationandC File Differences for Nonvirtual Subsystem Function Data Separation.

    In this example, there are not significant differences in the generated variants ofert_main.c,model_private.h,model_types.h, orrtwtypes.h.

H File Differences for Nonvirtual Subsystem Function Data Separation

  • SelectingFunction with separate datacauses the code generator to place type definitions for subsystem data in themyfun.hfile forrtwdemo_atomic2:

    /* Block states (default storage) for system '/SS1' */ typedef struct { real_T Integrator_DSTATE; /* '/Integrator' */ } DW_myfun_T;

    Forrtwdemo_atomic1, type definitions for subsystem data belong to the model and appear inrtwdemo_atomic1.h:

    /* Block signals (default storage) */ typedef struct { real_T Sum; /* '/Sum' */ } B_rtwdemo_atomic_1_T; /* Block states (default storage) for system '' */ typedef struct { real_T Integrator_DSTATE; /* '/Integrator' */ } DW_rtwdemo_atomic_1_T;
  • SelectingFunction with separate datagenerates the following external declarations in themyfun.hfile forrtwdemo_atomic2:

    /* Extern declarations of internal data for system '/SS1' */ extern DW_myfun_T myfun_DW; extern void myfun_Update(void); extern void myfun(void);

    By contrast, the generated code forrtwdemo_atomic1contains model-level external declarations for the subsystemBlockIOandD_Workdata, inrtwdemo_atomic1.h:

    /* Block signals (default storage) */ extern B_rtwdemo_atomic_1_T rtwdemo_atomic_1_B; /* Block states (default storage) */ extern DW_rtwdemo_atomic_1_T rtwdemo_atomic_1_DW;

C File Differences for Nonvirtual Subsystem Function Data Separation

  • SelectingFunction with separate datacauses a separate subsystem initialize function,myfun_initialize, to be generated in themyfun.cfile forrtwdemo_atomic2:

    void myfun_initialize(void) { { ((real_T*)&rtwdemo_atomic2_myfunB.Integrator)[0] = 0.0; } rtwdemo_atomic2_myfunDW.Integrator_DSTATE = 0.0; }

    The subsystem initialize function inmyfun.cis invoked by the model initialize function inrtwdemo_atomic2.c:

    / * rtwdemo_atomi模型初始化函数* /空白c2_initialize(void) { ... /* Initialize subsystem data */ myfun_initialize(); }

    By contrast, forrtwdemo_atomic1, subsystem data is initialized by the model initialize function inrtwdemo_atomic1.c:

    / * rtwdemo_atomi模型初始化函数* /空白c1_initialize(void) { ... /* block I/O */ { ... ((real_T*)&rtwdemo_atomic1_B.Integrator)[0] = 0.0; } /* states (dwork) */ rtwdemo_atomic1_DWork.Integrator_DSTATE = 0.0; ... }
  • SelectingFunction with separate datagenerates the following declarations in themyfun.cfile forrtwdemo_atomic2:

    /* Declare variables for internal data of system '/SS1' */ DW_myfun_T myfun_DW;

    By contrast, the generated code forrtwdemo_atomic1contains model-level declarations for the subsystemsBlockIOandD_Workdata, inrtwdemo_atomic1.c:

    /* Block signals (default storage) */ B_rtwdemo_atomic_1_T rtwdemo_atomic_1_B; /* Block states (default storage) */ DW_rtwdemo_atomic_1_T rtwdemo_atomic_1_DW;
  • SelectingFunction with separate datagenerates identifier naming that reflects the subsystem orientation of data items. The references to subsystem data in subsystem functions, such asmyfunandmyfun_update, are in the modelmodel_stepfunction. For example, compare this code frommyfunforrtwdemo_atomic2

    /* DiscreteIntegrator: '/Integrator' */ rtwdemo_atomic_2_Y.Out1 = myfun_DW.Integrator_DSTATE;

    to the corresponding code frommyfunforrtwdemo_atomic1.

    /* DiscreteIntegrator: '/Integrator' */ rtwdemo_atomic_1_Y.Out1 = rtwdemo_atomic_1_DW.Integrator_DSTATE;

Partition Functions in Generated Code

This example shows how to associate subsystems in a model with function names and files.

Learn how to:

  • Specify function and file names in the generated code.

  • Identify the parts of the generated code that are required for integration.

  • Generate code for atomic subsystems.

  • Identify data that are required to execute a generated function.

For information about the example model and other examples in this series, seePrepare a Control Algorithm Model for C Code Generation.

Atomic and Virtual Subsystems

The example models inPrepare a Control Algorithm Model for C Code GenerationandConfigure Data Interface in the Generated Codeusevirtual subsystems. Virtual subsystems visually organize blocks but do not affect the model functionality.Atomic subsystemsevaluate the blocks included in a model as a unit. With atomic subsystems, you can specify additional function partitioning information. In a model, atomic subsystems appear with a bold border.

View Changes in Model Architecture

Open the example modelrtwdemo_PCG_Eval_P3.

Save a copy of the model to a writable folder.

This example shows how to replace the virtual subsystems withfunction-call subsystems. Function-call subsystems:

  • Are atomic subsystems

  • Enable you to control subsystem execution order

  • Execute when afunction call signaltriggers

By controlling the execution order of the subsystems, you can match the model with an existing system that has a specific execution order.

The figure identifies the function call subsystems (1)PI_ctrl_1,PI_ctrl_2, andPos_Command_Arbitration.

This version of the model contains the new subsystemExecution_Order_Control(2), which contains a Stateflow® chart that models the calling functionality of a scheduler. The subsystem controls the execution order of the function call subsystems through function call signals (3). Later in this example, you examine how changing the execution order can change the simulation results.

This version of the model contains new Signal Conversion blocks (4) at the outputs of the PI controllers. With these additional blocks in place, the code generator can generate a single reentrant function for the PI controllers.

Control Function Location and File Placement in the Generated Code

InPrepare a Control Algorithm Model for C Code GenerationandConfigure Data Interface in the Generated Code, the code generator creates a singlemodel_stepfunction that contains the control algorithm code. However, many applications require a greater level of control over the file placement of functions. By modifying the parameters of atomic subsystems, you can specify multiple functions within a single model.

The figure shows the subsystem parameters forPI_ctrl_1.

Treat as atomic unit

  • Enables other submenus. For atomic subsystems, this parameter is automatically selected and disabled.

Sample time

  • Specifies a sample time for execution. Not available for function-call subsystems.

函数包装选项

  • Auto-- Determines how the subsystem appears in the generated code. This value is the default.

  • Inline-- Places the subsystem code inline with the rest of the model code.

  • Function-- Generates the code for the subsystem as a function.

  • Reusable function-- Generates a reusable (reentrant) function from the subsystem. The function passes all input and output data through formal parameters. The function does not directly access global variables.

Function name options

  • SelectingFunctionorReusable functionforFunction packagingenables function name options.

  • Auto-- Determines the function.

  • Use subsystem name-- Bases the function on the subsystem name.

  • User specified-- Applies the specified file name.

File name options

  • SelectingFunctionorReusable functionforFunction packagingenables file name options.

  • Auto——通用电气模块中的函数定义的地方nerated for the parent system, or, if the model root is the parent, inmodel.c.

  • Use subsystem name-- Generates a separate file. The name of the file is the name of the subsystem or library block.

  • Use function name-- Generates a separate file. The name of the file is the name that you specify withFunction name options.

  • User specified-- Applies the specified, unique file name.

Function with separate data

  • Enabled when you setFunction packagingtoFunction. When selected, the code generator separates the internal data of the subsystem (for example, signals) from the data of the parent model. The subsystem owns this separate data.

Generate Reentrant Code

Embedded Coder® supportsreentrant code. Reentrant code is a reusable programming routine that multiple programs can use simultaneously. Reentrant code is used in operating systems and other system software that uses multithreading to handle concurrent events. Reentrant code does not maintain state data, so there are no persistent variables in the function. Calling programs maintain state variables and must pass the state data into the function. Multiple users or processes can share one copy of a reentrant function.

To generate reentrant code, you must first specify the subsystem as reusable by configuring the subsystem parameterFunction packaging.

In some cases, the configuration of the model prevents reusable code. The table lists common issues.

Cause Solution
Subsystem output feeds global signal Add a Signal Conversion block between the data subsystem and the global signal.
Generated function receives data Select Configuration Parameters > (formal parameters) through pointers Model Referencing > Pass fixed-size scalar root inputs by value for code generation.
Subsystem uses global signal data Use a port to pass the global data in and out in internal algorithm of the subsystem.

Use a Mask to Pass Parameter Values into Library Subsystem

To define algorithmic parameter data (such as a gain or coefficient) outside the scope of a reusable library block or subsystem, you can apply amaskto the block or subsystem and create a mask parameter. You can then specify a different parameter value for each instance of the block or subsystem. Each mask parameter appears in the generated code as a formal parameter of the reentrant function.

In this version of the model, the subsystemsPI_ctrl_1andPI_ctrl_2are masked. In each mask, the values of thePandIgains are set by data objects such asI_Gain_2andP_Gain_2.

Generate Code for Atomic Subsystem

InPrepare a Control Algorithm Model for C Code GenerationandConfigure Data Interface in the Generated Code, you generate code at the root level of the model. Alternatively, you can build a specific subsystem.

To initiate a subsystem build, use the context menu. You can choose from these options:

  1. Build This Subsystem: Treats the subsystem as a separate mode and creates the full set of source C files and header files. This option does not support function-call subsystems.

  2. Generate S-Function: Generates C code for the subsystem and creates an S-Function wrapper. You can then simulate the code in the original model. This option does not support function-call subsystems.

  3. Export Functions: Generates C code without the scheduling code that comes with theBuild This Subsystemoption. Use this option to build subsystems that use triggers, such as function-call subsystems.

Alternatively, open theEmbedded Coderapp, select the subsystem and on theC Codetab, clickBuild.

Examine Generated Code

This example compares the files that are generated for the full system build with the files that are generated for exported functions. You also examine how the masked data appears in the code.

Run the build script for the three options. Then, examine the generated files by clicking the hyperlinks.

rtwdemo_PCG_Eval_P3.c

  • Full Build:Yes, Step function

  • PI_ctrl_1: No

  • Pos_Command_Arbitration: No

PI_ctrl_1.c

  • Full Build: No

  • PI_ctrl_1:Yes触发函数

  • Pos_Command_Arbitration: No

Pos_Command_Arbitration.c

  • Full Build: No

  • PI_ctrl_1: No

  • Pos_Command_Arbitration:Yes, Init and Function

PI_Ctrl_Reusable.c

  • Full Build:Yes

  • PI_ctrl_1:Yes

  • Pos_Command_Arbitration: No

ert_main.c

  • Full Build:Yes

  • PI_ctrl_1:Yes

  • Pos_Command_Arbitration:Yes

eval_data.c

  • Full Build:Yes(1)

  • PI_ctrl_1:Yes(1)

  • Pos_Command_Arbitration: No, Eval data not used in diagram

(1)eval_data.chas different content in the full and export function builds. The full build includes all of the parameters that the model uses. The export function contains only the variables that the subsystem uses.

Masked Data in the Generated Code

In the filertwdemo_PCG_Eval_P3.c, the call sites of the reentrant function use the data objectsP_Gain,I_Gain,P_Gain_2, andI_Gain_2as arguments.

Effect of Execution Order on Simulation Results

By default, Simulink® executes the subsystems in this order:

  1. PI_ctrl_1

  2. PI_ctrl_2

  3. Pos_Command_Arbitration

For this example, you can specify one of two alternative orders of execution. You can then use the test harness to observe the effect of the execution order on the simulation results. The subsystemExecution_Order_Controlhas two configurations that control the execution order. To choose a configuration, use the subsystem context menu.

Change the execution order and observe the results.

The simulation results (throttle position over time) vary slightly depending on the order of execution. You can see the difference most clearly when the throttle request changes.

For the next example in this series, seeCall External C Code from Model and Generated Code.

Nonvirtual Subsystem Modular Function Code Limitations

Nonvirtual subsystem block parameterFunction with separate datahas the following limitations:

  • The parameter is available for models configured with an ERT-based system target file.

  • The nonvirtual subsystem to which the parameter is applied cannot have multiple sample times or continuous sample times; that is, the subsystem must be single-rate with a discrete sample time.

  • The nonvirtual subsystem cannot contain continuous states.

  • The nonvirtual subsystem cannot output function call signals.

  • The nonvirtual subsystem cannot contain noninlined S-functions.

  • The generated files for the nonvirtual subsystem will reference model-wide header files, such asmodel.handmodel_private.h.

  • The parameter is incompatible with theClassic call interfaceparameter. Selecting both parameters generates an error.

  • The parameter is incompatible with theReusable functionsetting for model configuration parameterCode interface packaging. Selecting both parameters generates an error.

  • When you select the parameter for a subsystem, the model that contains the subsystem cannot contain aData Store Memoryblock withShare across model instancesselected. SeeData Store Memory.

Related Topics