To control the appearance of data in the generated code, you can use built-in storage
classes such as
ExportToFile (see Organize Parameter Data into a Structure by Using Struct Storage Class). If the
built-in storage classes do not meet your requirements, you can create your own storage
classes. To create a storage class that you can apply to data objects, create the storage
class in a package by using the Custom Storage Class Designer. See Define Storage Classes, Memory Sections, and Function Templates for Software Architecture.
To define a storage class that you can apply in a model by using the Code Mappings editor, use the Embedded Coder Dictionary. Or, create the storage class in a package and refer to the package from the Embedded Coder Dictionary.
A package also defines
classes. See Data Objects. A data object from a package such as
Simulink can use storage classes defined in that package but not storage
classes that are defined in other packages.
For information about using the Custom Storage Class Designer to create memory sections, see Control Data and Function Placement in Memory by Inserting Pragmas.
This example shows how to control code generated from a model by creating and applying your own storage class for data objects.
Open the model rtwdemo_cscpredef. You can control code generated from this model by defining your own data classes and creating your own storage classes.
In this example, you export the declarations and definitions of multiple signals and parameters in the model to one declaration header file and one definition file.
To create storage classes, you first create a data class package to contain the storage class definitions. Data objects that you create from your package can use the storage classes that the package defines.
Create your own data class package by copying the example package folder
+SimulinkDemos. Navigate to the example package folder.
% Remember the current folder path currentPath = pwd; % Navigate to the example package folder demoPath = '\toolbox\simulink\simdemos\dataclasses'; cd([matlabroot,demoPath])
+SimulinkDemos folder to your clipboard.
Return to your working folder.
+SimulinkDemos folder from your clipboard into your
working folder. Rename the copied folder to
Navigate inside the
+myPackage folder to the file
Signal.m to edit the definition of the
methods section that defines the method
setupCoderInfo. In the call to the function
'myPackage'. When you
finish, the section appears as follows:
methods function setupCoderInfo(h) % Use custom storage classes from this package useLocalCustomStorageClasses(h, 'myPackage'); end end % methods
useLocalCustomStorageClasses allows you to apply
the storage classes that
myPackage defines to data objects that you
Save and close the file.
Navigate inside the
+myPackage folder to the file
Parameter.m to edit the definition of the
Parameter class. Uncomment the
that defines the method
setupCoderInfo and replace
Save and close the file.
You can use the Custom Storage Class Designer to create or to edit the storage classes that a data class package defines.
Set your current folder to the folder that contains the package
Open the Custom Storage Class Designer.
Select the storage class
In the Name field, rename the storage class to
In the Header file drop-down list, change the selection from
Instance specific to
Specify. In the new
field, provide the header file name
In the Definition file drop-down list, change the selection
Instance specific to
Specify. In the new
field, provide the definition file name
Click OK. Click Yes to save changes to
the data class package
To apply your own storage class, you create data objects from your package and configure the objects to use your storage class.
Create data objects to represent some of the parameters and signals in the example
model. Create the objects using the data class package
% Parameters templimit = myPackage.Parameter(202); pressurelimit = myPackage.Parameter(45.2); O2limit = myPackage.Parameter(0.96); rpmlimit = myPackage.Parameter(7400); % Signals tempalarm = myPackage.Signal; pressurealarm = myPackage.Signal; O2alarm = myPackage.Signal; rpmalarm = myPackage.Signal;
Set the storage class of each object to
% Parameters templimit.CoderInfo.StorageClass = 'Custom'; templimit.CoderInfo.CustomStorageClass = 'ExportToGlobal'; pressurelimit.CoderInfo.StorageClass = 'Custom'; pressurelimit.CoderInfo.CustomStorageClass = 'ExportToGlobal'; O2limit.CoderInfo.StorageClass = 'Custom'; O2limit.CoderInfo.CustomStorageClass = 'ExportToGlobal'; rpmlimit.CoderInfo.StorageClass = 'Custom'; rpmlimit.CoderInfo.CustomStorageClass = 'ExportToGlobal'; % Signals tempalarm.CoderInfo.StorageClass = 'Custom'; tempalarm.CoderInfo.CustomStorageClass = 'ExportToGlobal'; pressurealarm.CoderInfo.StorageClass = 'Custom'; pressurealarm.CoderInfo.CustomStorageClass = 'ExportToGlobal'; O2alarm.CoderInfo.StorageClass = 'Custom'; O2alarm.CoderInfo.CustomStorageClass = 'ExportToGlobal'; rpmalarm.CoderInfo.StorageClass = 'Custom'; rpmalarm.CoderInfo.CustomStorageClass = 'ExportToGlobal';
Select the Signal name must resolve to Simulink signal object option for each of the target signals in the model. You can select the option by using the Signal Properties dialog box, the Resolve column in the Model Data Editor, or by using the command line.
% Signal tempalarm portHandles = get_param('rtwdemo_cscpredef/RelOp1','PortHandles'); outputPortHandle = portHandles.Outport; set_param(outputPortHandle,'MustResolveToSignalObject','on') % Signal pressurealarm portHandles = get_param('rtwdemo_cscpredef/RelOp2','PortHandles'); outputPortHandle = portHandles.Outport; set_param(outputPortHandle,'MustResolveToSignalObject','on') % Signal O2alarm portHandles = get_param('rtwdemo_cscpredef/RelOp3','PortHandles'); outputPortHandle = portHandles.Outport; set_param(outputPortHandle,'MustResolveToSignalObject','on') % Signal rpmalarm portHandles = get_param('rtwdemo_cscpredef/RelOp4','PortHandles'); outputPortHandle = portHandles.Outport; set_param(outputPortHandle,'MustResolveToSignalObject','on')
Generate code for the example model.
In the Code view for the model, view the generated header file
global.h. The file contains the
declarations of the model signals and parameters that use the storage class
/* Declaration for custom storage class: ExportToGlobal */ extern boolean_T O2alarm; extern real_T O2limit; extern boolean_T pressurealarm; extern real_T pressurelimit; extern boolean_T rpmalarm; extern real_T rpmlimit; extern boolean_T tempalarm; extern real_T templimit;
View the generated file
global.c. The file contains the
definitions of the model signals and parameters that use the storage class
/* Definition for custom storage class: ExportToGlobal */ boolean_T O2alarm; real_T O2limit = 0.96; boolean_T pressurealarm; real_T pressurelimit = 45.2; boolean_T rpmalarm; real_T rpmlimit = 7400.0; boolean_T tempalarm; real_T templimit = 202.0;
You cannot directly modify a built-in storage class, such as
ExportToFile from the
Simulink package, but you can
create a copy, and then modify the copy. When you create a new package with no
csc_registration.m file, and then open the Custom Storage Class Designer
for the first time in that package, Simulink copies the definitions of the built-in storage
classes into the package. Then, in the Custom Storage Class Designer, you can modify the
copied definitions. Alternatively, to keep the built-in storage classes available in your
package, copy one of them by clicking Copy, then modify the resulting
The Custom Storage Class Designer is a tool for creating and managing storage classes
and memory sections. To open the Custom Storage Class Designer for a specific package, for
+mypkg, at the command prompt, use the
The name of the folder that represents a package begins with a
When you use the function
cscdesigner, omit the
from the name of the target package.
To control the effect that a storage class has on data in a model, you specify properties of the storage class in the Custom Storage Class Designer. To determine how to generate a particular kind of code, use the information in the table.
|Kind of Data in Generated Code||Technique|
|Structure||Set Type to |
|Macro||Set Data initialization to
|Pointer||Set Data access to |
|Set Data scope to
|Set Memory section to a memory section that specifies
|Calls to external functions to read and write to data||See Call Custom Accessor Functions or Macros Instead of Reading and Writing to Variables.|
For some properties of a storage class, such as Data scope, instead of specifying a value in the Custom Storage Class Designer, you can allow users of the storage class to specify the value. You can create a single, flexible storage class instead of multiple storage classes that vary only by a few property values.
For example, suppose you create a storage class that yields a global variable in the
generated code. You can configure the storage class so that a user can set the
Data scope property to
Exported for a
signal in a model and set the property to
Imported for a
In the Custom Storage Class Designer, for each property that you want to configure in
this way, set the property value to
Instance specific. Then,
when a user applies the storage class to a data item, the property appears to the user as
a custom attribute for that data item. For information about instance-specific custom
attributes, see Storage Class Properties.
To create a storage class that yields a macro in the generate code, set Data
Macro and clear For
When you set Data initialization to
Macro, Definition file has
no meaning. To prevent users of the storage class from
specifying a meaningless definition file, in the Custom Storage Class Designer, set
Definition file to
Specify and leave the
text box empty.
To define the macro in a header file (
#define), specify the
name of the header file with the Header file property.
To provide the macro definition as a compiler option or compiler flag, set
Data access to
Header file to
Specify. Leave the
Header file text box empty. Then, the generated code does not
define the macro and does not include (
#include) a header
To specify the compiler option or flag, use the model configuration parameter Configuration Parameters > Code Generation > Custom Code > Additional build information > Defines. See Code Generation Pane: Custom Code: Additional Build Information: Defines.
To create a storage class that aggregates data items into a flat structure (similar to
the built-in storage class
Struct), set Type to
FlatStructure. The Structure Attributes
To control the name of the global structure variable that appears in the generated code, use the Struct name property and text box.
If you set Struct name to
specific, users of the storage class specify the name of the
structure variable. In this case, the code generator derives the name of the
structure type from the name of the variable.
To more precisely control the name and other characteristics of the structure
type, set Struct name to
Control the type characteristics by using the additional properties that
To generate a structure with bit fields (similar to the built-in storage class
BitField), select Bit-pack booleans. Data
items that use the data type
boolean appear in the generated code
as bit fields of the structure.
To use the default Simulink®
Coder™ initialization strategy, set Data initialization
to the default value,
The generated code statically initializes parameter data with an
assignment statement at the top of a
.cpp source file, outside of
The generated code dynamically initializes signal and state data as part
of the initialization function of the model (named
To statically initialize the data, set Data initialization
To dynamically initialize the data, set Data initialization
To prevent the generated code from initializing the data, set Data
None. When your external
code initializes the data, use this setting to prevent the generated code from
overwriting your initialization.
Using the built-in storage class
GetSet, you can generate code that
calls your external, custom functions instead of directly interacting with variables. For
general information about
GetSet, see Access Data Through Functions with Storage Class GetSet.
To create a similar storage class, set Type to
Specify the names of the external functions.
To apply the same
function naming scheme to data items that use the storage class, set
Get function and Set function to
Specify. Then, in the text boxes, specify the
function naming scheme, for example,
get_myData_$N. Use the
$N in a naming scheme to represent the name of each
data item. If you do not use the token, each data item uses the same specified
set function name, so the model
generates an error when you generate code.
To specify a different
function name for each data item, set Get function or
Set function to
specific. Later, when you create a data item and apply the
storage class, specify the function name by configuring the custom attributes
of the data item.
Specify the name of the header file that declares the
set functions with the Header file
property. In this case, Definition file has
no meaning. To prevent users of the storage class from
specifying a meaningless definition file, set Definition file
Specify and leave the text box empty.
If you implement the
get mechanism for scalar or array data
as a macro instead of a function, you can generate code that omits parentheses when
reading that data. On the Access Function Attributes tab,
select Get data through macro (omit parentheses).
When your external code defines data, to avoid generating a duplicate definition, you
must configure the generated code to read and write to the existing data. In the Custom
Storage Class Designer, set Data scope to
Imported. The code generator does not generate a definition
for the global variable or macro.
If your code defines a pointer variable, to generate code that interacts with
the pointer, set Data access to
If you generate structured data by setting Type to
FlatStructure, your code must define the structure type
and the global structure variable.
If your code initializes state or signal data, you can prevent the generated
code from overwriting your initialization by setting Data
None. See Prevent Duplicate Initialization Code for Global Variables
To customize the comments that appear in the generated code, on the
Comments tab, set Comment rules to
Specify. To specify a comment that appears with the
declaration of each data item, use the Declaration comment box. To
specify a comment that appears with the definition, use the Definition
For structured data (you set Type to
FlatStructure), to specify a comment that appears with the
structure type definition, use the Type comment box.
As you configure a storage class in the Custom Storage Class Designer, to check for possible errors in the configuration, click Validate.
For example, validating the storage class warns you if you accidentally set
Data initialization to
For signals selected. A signal cannot appear in the generated code as
To use a storage class that you create, you must make the defining package available. Either set your current folder to the folder that contains the package or add the folder containing the package folder to the MATLAB® path (see What Is the MATLAB Search Path?). Adding the package to the MATLAB path enables you to use the storage classes no matter where you set your current folder.
To use package-based storage classes in the Code Mappings editor, refer to the package from an Embedded Coder Dictionary. To configure an Embedded Coder Dictionary to refer to the package, see Refer to Code Generation Definitions in a Package.
When you create a package, you can refer to a storage class defined in another package
such as the built-in package
Simulink or a different package that you
created. Then, the defining package and any referencing packages
can use the storage class. When you want to make a change to the storage class, you make the
change only once, in the defining package.
To configure a package to refer to a storage class that another package defines:
In the Custom Storage Class Designer, select the Custom Storage Class tab.
Use Select Package to select the referencing package. The package must be writable.
In the Custom storage class definitions pane, select the existing definition below which you want to insert the reference.
Click New Reference.
A new reference with a default name and properties appears below the previously selected definition. The new reference is selected and a Reference tab appears that shows the initial properties.
Use Name to specify a name for the new reference. The name must be unique in the importing package, but can duplicate the name in the source package. The name cannot be a TLC keyword.
Set Refer to custom storage class in package to specify the package that contains the storage class that you want to reference.
Set Custom storage class to reference to specify the storage class to be referenced.
Click OK or Apply. To save the changes permanently, click Save.
When you apply a storage class to a data item, you select the storage class from a drop-down list.
To control the order of the custom storage classes in the list, in the Custom Storage Class Designer, use the Up and Down buttons. The order of the storage classes in drop-down lists matches the order that you specify in the Custom Storage Class Designer.
To prevent a user of a storage class from applying the storage class to parameter data or to signal and state data, use the For parameters and For signals check boxes. When you clear one of these properties, for the corresponding kind of data, the storage class does not appear in the drop-down list.
For example, if your storage class yields a macro in the generated code because
you set Data initialization to
to prevent users from applying the storage class to signal data, clear For
When you click Save in the Custom Storage Class Designer, the
Designer saves memory section and storage class definitions into the
csc_registration.m file in the package folder. To determine the
location of this file, in the Custom Storage Class Designer, inspect the value of
You can prevent changes to the storage class definitions of an entire package by
csc_registration.m file from a MATLAB file to a P-file. Use the
A best practice is to keep
csc_registration.p in your package folder. That way, if you modify the
storage classes by using the Designer, you can delete
and later regenerate it after you finish the modifications. Because the P-coded version of
the file takes precedence, when both files exist in the package, the storage classes are
protected and you cannot modify them in the Custom Storage Class Designer.
If creating your own storage class by manipulating the properties in the Custom Storage
Class Designer does not meet your requirements, you can finely control the generated code by
writing TLC code for your storage class. Use an advanced mode of the Custom Storage Class
Designer and, for the storage class, set Type to
Other. See Finely Control Data Representation by Writing TLC Code for a Storage Class.