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 LibraryCodeGeneration
and library LibraryCodeGenerationLibrary
. 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:
LibraryCodeGeneration LibraryCodeGenerationLibrary
Configure Reusable Library Subsystems
To perform library-based code generation, you must configure the library subsystem as reusable.
In the Subsystem block parameters dialog box, select Treat as an atomic unit.
On the Code Generation tab:
Set Function packaging to
Reusable function
.Set the Function name options and File name options parameters based on this table. This table summarizes how the code generator produces code. For the purpose of this table, assume that the Subsystem block is named
mySubsystem
and theFile name
value forUser specified
option ismyFunction
.Function Name Options File Name Options Generated Function Name Generated File Name Auto
Auto
mySubsystem_checksum
mySubsystem_checksum.c
,mySubsystem_checksum.h
Use subsystem name
Code generation is not supported. Use function name
mySubsystem_checksum
mySubsystem_checksum.c
,mySubsystem_checksum.h
User specified
Code generation is not supported. Use subsystem name
Auto
Code generation is not supported. Use subsystem name
Code generation is not supported. Use function name
Code generation is not supported. User specified
Code generation is not supported. User specified
Auto
mySubsystem_Single
mySubsystem_Single.c, mySubsystem_Single.h
Use subsystem name
Code generation is not supported. Use function name
mySubsystem_Single
mySubsystem_Single.c, mySubsystem_Single.h
User specified
(This specification is supported only if the user-specified function name and file name are same.)myFunction_Single
myFunction_Single.c, myFunction_Single.h
Note
When you set Function name options or File name options to
User specified
, the specification must contain$R
. The code generator expands$R
to the function interface name.
For more information about the Subsystem block parameters, see Subsystem.
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:
In the Subsystem block parameters dialog box, on the Code Generation tab, set the Function name options parameter to
User specified
.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.Set the File name option parameter to
Auto
orUse function name
.In the library, right-click the Subsystem and select C/C++ Function Interfaces > Create Function Interface. In the Create Function Interface dialog box, for the Name parameter, specify a name that describes the context.
Configure and Manage Function Interfaces
The model LibraryCodeGeneration
contains two instances of the
reusable library subsystem Atomic_Controller
. Each instance represents a
function interface. In the library LibraryCodeGenerationLibrary
,
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:
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.
For the Simulink model with instance parameter, select the model that contains the subsystem.
For the Library block instance name parameter, select the subsystem.
Click OK and close the Create Function Interface dialog box.
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:
In the library, right-click the badge at the lower rightmost side of the reusable library subsystem and select Manage Function Interfaces.
Select the function interfaces that you want to modify.
Click Export.
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
.Open the exported model. Make your changes to the subsystem input and output block parameter settings and model configuration parameter settings. Save the model.
In the library, right-click the reusable library subsystem and select C/C++ Function Interfaces > Create Function Interface. Specify a function interface Name.
For the Simulink model with instance parameter, select the exported model that is in the current working folder.
For the Library block instance name parameter, select the subsystem.
Click OK and close the Create Function Interface dialog box.
Configure Function Interfaces from Within a Library
In the library, right-click the badge at the lower rightmost side of the subsystem and select Configure Function Interface.
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.
To modify the model configuration parameters, click the gear button and make the changes. Click Apply. Close the Configuration Parameters dialog box.
To replace a function interface with an existing one from an instance model, select Regenerate Using Instance.
Specify values for the Simulink model with instance and Library block instance name parameters. Click Regenerate.
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.
When you generate code for the LibraryCodeGenerationLibrary
library,
the LibraryCodeGenerationLibrary
folder contains these
.c
and .h
files:
Atomic_Controller_Single.h
Atomic_Controller_Single.c
Atomic_Controller_Double.h
Atomic_Controller_Double.c
These function 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);
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='LibraryCodeGenerationLibrary' set_param(library, 'GenCodeOnly', 'on') slbuild(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:
Set the model configuration parameter Shared code placement to
Shared location
.Specify a setting for the Behavior when pregenerated library subsystem code is missing parameter or leave the default setting, which is warning.
In the Configuration Parameters dialog box, the parameter settings on the Code Generation panes must be identical between the model and function interface of the reusable library subsystem. If the settings are different, the checksums will not match, and you might get a warning, error, or neither depending on the setting of the Behavior when pregenerated library subsystem code is missing parameter.
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 LibraryCodeGeneration
.
/* Model step function */ void LibraryCodeGeneration_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:
Create a test harness in a library for a unique subsystem and function interface pair.
With the SIL/PIL Manager:
Run normal mode and software-in-the-loop (SIL) or processor-in-the-loop (PIL) simulations of the subsystem.
Compare numerical results in the Simulation Data Inspector.
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.
For Each Subsystem blocks.
Stateflow® chart subsystems.
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.
Signal and state data logging.
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.
You cannot apply a configuration reference to a function interface on a reusable library subsystem. To compare configuration sets, export the function interface to a separate model, and then export the configuration set to a MATLAB® script. See Save a Configuration Set for more information.
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
.You cannot place multiple generated functions into a single file.