Main Content

Library-Based Code Generation for Reusable Library Subsystems

Library-based code generation provides a way of generating code for a set of reusable components that models can share. For each top-level reusable library subsystem, you specify a set of function interfaces that lock down the subsystem interface. A function interface consists of the subsystem input and output block parameter settings and the model configuration parameter settings.

Function interfaces are independent models that you save with an accompanying library. Before generating code for a model containing instances of the reusable library subsystem, you generate code for the library. Library-based code generation makes the library the owner of the code. To make the individual models the owner of the code, you can generate code for reusable library subsystems to the shared utilities folder. For more information, see Generate Reusable Code from Library Subsystems Shared Across Models.

Example Model and Library

To show how to use function interfaces and library-based code generation, this example uses the model rtwdemo_libcodegen_mdl and library rtwdemo_libcodegen_lib. The model contains two instances of the reusable library subsystem Atomic_Controller. For Atomic_Controller_Single, the input signal data type is single. For Atomic_Controller_Double, the input signal data type is double. To open the model and library files, at the MATLAB command prompt, enter:

rtwdemo_libcodegen_mdl
rtwdemo_libcodegen_lib

Configure Reusable Library Subsystems

To perform library-based code generation, you must configure the library subsystem as reusable.

  1. In the Subsystem block parameters dialog box, select Treat as atomic unit.

  2. In the Subsystem block parameters dialog box, on the Code Generation tab, set the Function packaging parameter to Reusable function.

Specify Unique Function Interface Names

Each function interface corresponding to the same reusable library subsystem must have a unique name. To specify a unique name, follow these steps:

  1. In the Subsystem block parameters dialog box, on the Code Generation tab, set the Function name options parameter to User specified.

  2. For the Function name parameter, specify the $R and $N tokens. The $R token represents the function interface name. The $N token represents the subsystem name.

  3. In the Create Function Interface dialog box, for the Name parameter, specify a name that describes the context.

  4. Set the File name option parameter to Auto or Use function name.

Configure and Manage Function Interfaces

The model rtwdemo_libcodegen_mdl contains two instances of the reusable library subsystem Atomic_Controller. Each instance represents a function interface. In the library rtwdemo_libcodegen_lib, right-click the badge at the lower rightmost side of the reusable library subsystem Atomic_Controller. Select Manage Function Interfaces. The two function interfaces have the names Single and Double because Atomic_Controller takes single and double data types.

To create function interfaces, in a library, right-click a subsystem and select C/C++ Function Interfaces > Create Function Interface. Specify a function interface Name.

Then, to configure the function interfaces, choose one of the following methods.

Specify a Function Interface from Model

To create function interfaces from linked instances of the reusable library subsystem:

  1. In the library, right-click the badge at the lower rightmost side of the reusable library subsystem and select Create Function Interface. In the dialog box, select the Specify library block instance to create function interface parameter.

  2. For the Simulink model with instance parameter, select the model that contains the subsystem.

  3. For the Library block instance name parameter, select the subsystem.

  4. Click OK and close the Create Function Interface dialog box.

  5. For each function interface, repeat the preceding steps.

Note

You can create a function interface from within a model that contains an instance of a linked reusable library subsystem. You must be in the Code perspective. To open the Code perspective, from the apps menu, select Embedded Coder. If the subsystem has function interfaces, a badge appears at the lower-right corner of the subsystem. Right-click the badge and select Create Function Interface. If the subsystem does not have function interfaces, right-click the subsystem, and select C/C++ Function Interfaces > Create Function Interface.

Export and Configure an Existing Function Interface

To export and configure the function interface as an independent model:

  1. In the library, right-click the badge at the lower rightmost side of the reusable library subsystem and select Manage Function Interfaces.

  2. Select the function interfaces that you want to modify.

  3. Click Export.

  4. In the Save As window, specify the current working folder. An exported function interface is a .slx file that has the function interface name plus the appendix _export.

  5. Open the exported model. Make your changes to the subsystem input and output block parameter settings and model configuration parameter settings. Save the model.

  6. In the library, right-click the reusable library subsystem and select C/C++ Function Interfaces > Create Function Interface. Specify a function interface Name.

  7. For the Simulink model with instance parameter, select the exported model that is in the current working folder.

  8. For the Library block instance name parameter, select the subsystem.

  9. Click OK and close the Create Function Interface dialog box.

Configure Function Interfaces from Within a Library

  1. In the library, right-click the badge at the lower rightmost side of the subsystem and select Configure Function Interface.

  2. In the Configure Function Interface dialog box, for the subsystem inputs and outputs, specify values for the Data Type, Dimensions, and Signal Type parameters. To modify other subsystem input and output parameter settings, follow the export method in the preceding section.

  3. To modify the model configuration parameters, click the gear button and make the changes. Click Apply. Close the Configuration Parameters dialog box.

  4. To replace a function interface with an existing one from an instance model, select Regenerate Using Instance.

  5. Specify values for the Simulink model with instance and Library block instance name parameters. Click Regenerate.

  6. Click Apply and close the Configure Function Interface dialog box.

Build the Library

After you specify function interfaces for the subsystems in your library, generate code for the library. Before generating code for your model, you must generate code for the library. The code generator packages the library code as a separate C library. The generated code for the library is in a folder corresponding to your hardware settings (for example, IntelWin64). The library code folder has the same name as the library and must be at the same hierarchical level as the library.

To generate code, check that the library is unlocked. Open the Embedded Coder app and click Build Library.

When you generate code for the rtwdemo_libcodegen_lib library, the rtwdemo_libcodegen_lib folder contains these .c and .h files:

  • Atomic_Controller_Single.h

  • Atomic_Controller_Single.c

  • Atomic_Controller_Double.h

  • Atomic_Controller_Double.c

These functions names are representative of the $N$R specification for the Function name options and Function name parameters on the Subsystem block parameters dialog box.

A _shared folder contains code for shared utilities (for example, fixed-point utilities and Lookup Table and MATLAB function blocks), supplementary files, and exported parameters and types.

When you generate code for a model that contains an instance of a reusable library subsystem that can use the pregenerated library code, the model links to the library code. The code generator uses a checksum to determine reusability. The generated code for the model must be in the same folder as the library. At the MATLAB command line, enter:

Simulink.fileGenControl('set', 'CodeGenFolderStructure',...
 Simulink.filegen.CodeGenFolderStructure.TargetEnvironmentSubfolder);
For more information, see Simulink.fileGenControl.

If the model is unable to use the library code, you can specify whether or not Embedded Coder produces a warning or an error during code generation. In the Configuration Parameters dialog box, set the Behavior when pregenerated library subsystem code is missing diagnostic parameter setting.

You can generate code for a library but not execute a makefile by entering these commands:

library='rtwdemo_libcodegen_lib'
set_param(library, 'GenCodeOnly', 'on')
rtwbuild(library)

Note

You can generate code for a library consisting of reusable subsystems that contain S-functions. To avoid uncompilable code, in the TLC function corresponding to the S-function, avoid directing the code generator to interact with model files, such as model.c, model.h, and model_types.h.

Generate Code from Model Containing a Reusable Library Subsystem Instance

To generate code from a model that contains an instance of a reusable library subsystem for which you want to use the library code:

  1. Set the model configuration parameter Shared code placement to Shared location.

  2. Specify a setting for the Behavior when pregenerated library subsystem code is missing parameter or leave the default setting, which is warning.

  3. In the Configuration Parameters dialog box, the parameter settings on the Code Generation panes must all be identical to each other. If the settings are different, you might get a warning, error, or neither depending on the setting of the Behavior when pregenerated library subsystem code is missing parameter.

  4. If a reusable library subsystem uses a shared local data store and you configure default mapping for model data elements, leave the default storage class mapping for category Shared local data stores set to Default.

Here is the generated C code for rtwdemo_libcodegen_mdl.

/* Model step function */
void rtwdemo_libcodegen_mdl_step(void)
{
  /* Outputs for Atomic SubSystem: '<Root>/Atomic_Controller_Double' */

  /* Inport: '<Root>/pos_rqst' incorporates:
   *  Inport: '<Root>/fbk_1'
   *  Outport: '<Root>/pos_cmd_one'
   */
  Atomic_Controller_Double(pos_rqst1, rtU.fbk_1, &rtY.pos_cmd_one,
    &rtDW.Atomic_Controller_Double);

  /* End of Outputs for SubSystem: '<Root>/Atomic_Controller_Double' */

  /* Outputs for Atomic SubSystem: '<Root>/Atomic_Controller_Single' */

  /* Inport: '<Root>/pos_rqst1' incorporates:
   *  Inport: '<Root>/fbk_2'
   *  Outport: '<Root>/pos_cmd_two'
   */
  Atomic_Controller_Single(pos_rqst2, rtU.fbk_2, &rtY.pos_cmd_two,
    &rtDW.Atomic_Controller_Single);

  /* End of Outputs for SubSystem: '<Root>/Atomic_Controller_Single' */
}

The code contains calls to the Atomic_Controller_Single and Atomic_Controller_Double functions. The generated code pulls the function definitions from the pregenerated library code.

Verify Code Generated from Reusable Library Subsystems

Verification Workflow

If you have Simulink® Test™ software, you can verify code that you generate from reusable library subsystems. Use this workflow:

  1. Create a test harness in a library for a unique subsystem and function interface pair.

  2. With the SIL/PIL Manager:

    1. Run normal mode and software-in-the-loop (SIL) or processor-in-the-loop (PIL) simulations of the subsystem.

    2. Compare numerical results in the Simulation Data Inspector.

    3. View the Simulink Coverage™ analysis report.

For more information, see Test Library Blocks (Simulink Test).

Verification Workflow Limitations

The verification workflow does not support:

  • Function-Call Subsystem blocks.

  • Triggered Subsystem blocks or subsystems that use zero-crossing events.

  • Function interfaces where the number of Inports/Outports does not match the number of Inports/Outports in the graphical interface.

  • Parameters that use the ExportToFile storage class.

  • Subsystems with Outport blocks that are fed by Mux or Demux blocks.

  • Virtual buses that are passed as Inport blocks.

  • Data Store Memory blocks that use the ExportedGlobal storage class.

  • Blocks where data is initialized outside the subsystem code, for example, the Width block.

  • Code coverage highlighting and annotation.

For such cases, you can create a model that contains an instance of the reusable library subsystem and use the SIL/PIL Manager to run SIL or PIL simulations.

Limitations

Because the code generator uses a checksum to determine reusability, the same limitations that apply to generating code for models that share reusable library subsystems apply to library-based code generation. See Limitations. These limitations also apply:

  • You cannot specify a function interface on a reusable library subsystem that is within another reusable library subsystem.

  • Only ERT and ERT-derived system target files support library-based code generation.

  • Each function interface that corresponds to the same reusable library subsystem must be unique.

  • On Windows platform, avoid naming the library lib.slx as doing so may interfere with the static library compilation process.

  • When you generate code from a library, the code generator only generates code for top-level reusable subsystems in the library. The top-level library subsystem can be instantiated at any level in a client model and the instance in the client model reuses library code if it finds any.

  • A library subsystem cannot reuse code if it is inside an Enabled Subsystem block with the Enable block parameter, States when enabling, set to reset.

Related Topics