Manage Replacement of Simulink Data Types in Generated Code
You can manage the replacement of Simulink® data types in generated code by using:
Data Type Replacement configuration parameters – see Using Data Type Replacement Configuration Parameters.
Objects to specify data types for block diagram signals – see Using Data Type Objects for Block Diagram Signals.
Using Data Type Replacement Configuration Parameters
You can use the Data type replacement configuration parameter to control the replacement of Simulink data types in generated code:
If you set the parameter to
Use coder typedefs
, the code generator creates the header filertwtypes.h
and generates data types that are based on the C89 language standard. See Simulink Coder Data Types in Generated CodeThe
rtwtypes.h
file defines the data types throughtypedef
statements that build on C primitive types, for example,float
andshort
.If you set the parameter to
Use C data types with fixed-width integers
, the generated code uses data types from the C99 language standard, which includes definitions fromstdint.h
andstdbool.h
. See C99 Data Types in Generated Code.The generated code does not include the rtwtypes.h header file. The file
rtwtypes.h
is generated in some cases because it might be needed by static source code located undermatlabroot
. Additionally, if you use custom code that requires Simulink Coder™ data type definitions, you can force the generation ofrtwtypes.h
by selecting the Coder typedefs compatibility check box.
If you also select the Specify custom data type names check box, you can specify replacement names for the data types. See Specify Custom Names Using Data Replacement Type Pane.
C99 Data Types in Generated Code
When the Data type replacement configuration parameter is
set to Use C data types with fixed-width integers
,
the code generator replaces Simulink data types with C99 data types as shown in this
table.
Simulink Name | Code Generation Name |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Simulink Coder Data Types in Generated Code
When the Data type replacement configuration parameter is
set to Use coder typedefs
, the code generator
replaces Simulink data types with Simulink
Coder data types as shown in this table.
Simulink Name | Code Generation Name |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specify Custom Names Using Data Replacement Type Pane
You can specify custom names for the generated data types. For example, to
change the name of the Simulink
Coder data type int8_T
to myType
,
create a Simulink.AliasType
object. In the Command Window,
enter:
myType = Simulink.AliasType;
Set the BaseType
property to the Simulink data type that corresponds to the generated data type name. In
this example, int8
corresponds to
int8_T
.
myType.BaseType = 'int8';
Specify the header file that contains the definition of the data type.
myType.HeaderFile = "my_header.h" writelines("typedef signed char myType;", "my_header.h")
In the Configuration Parameters dialog box, select the Specify
custom data type names check box. Then, in the Replacement Name field that corresponds to
int8
, enter myType
.
For an example, see Replace and Rename Simulink Coder Data Types to Conform to Coding Standards.
Replace Implementation-Dependent Types with the Same Type Name
Some Simulink
Coder type names map to C primitives that are implementation-dependent.
For example, the Simulink
Coder type int_T
maps to the C type
int
, whose bit length depends on the native integer size
of your target hardware. Other implementation-dependent types include
boolean_T
, char_T
, and
uint_T
.
For more readable, simpler code, you can use the same type name to replace
multiple Simulink
Coder types of the same size. For example, if the native integer size of
your hardware is 32 bits, you can replace int_T
and
int32_T
with the same type name, say,
myInt
.
Configure your target hardware settings in Configuration Parameters > Hardware Implementation.
Create a
Simulink.AliasType
object namedmyInt
. In this case, becauseint_T
andint32_T
represent a 32-bit signed integer, setBaseType
toint32
.myInt = Simulink.AliasType('int32')
Specify the header file that contains the definition of the data type.
myInt.HeaderFile = "my_header.h" writelines("typedef signed char myInt;", "my_header.h")
In the Replacement Name fields for both data types, specify
myInt
.
Note
Many-to-one data type replacement does not support the
char
(char_T
) built-in data type.
Use char
only in one-to-one data type
replacements.
Many-to-one data type replacement is not supported for Simulink Coder data types of different sizes.
Using Data Type Objects for Block Diagram Signals
You can specify data types for block diagram signals by using the Model Editor and
data type objects, for example, Simulink.AliasType
and Simulink.NumericType
.
Specify Custom Names Using Model Editor
You can specify custom names for the generated data types. For example, to
rename the Simulink
Coder data type int8_T
, create a
Simulink.AliasType
object, specifying a name that you want
the generated code to use. In the Command Window, enter:
myType = Simulink.AliasType;
Set the BaseType
property to the Simulink data type that corresponds to the generated data type name. In
this example, int8
corresponds to
int8_T
.
myType.BaseType = 'int8';
Specify the header file that contains the definition of the data type.
myType.HeaderFile = "my_header.h" writelines("typedef signed char myType;", "my_header.h")
Then, in the Model Editor, use the Simulink.AliasType
object
to specify the data type of an individual signal, that is, a block output, or
block parameter. By default, due to data type propagation and inheritance (see
Data Type Inheritance Rules), the signals, states, and parameters of
other downstream blocks typically inherit the same data type. Optionally, you
can configure upstream blocks to inherit the type (Inherit: Inherit
via back propagation
) or stop the propagation at an arbitrary
block by specifying a noninherited data type setting.
For an example, see Create Data Type Alias in the Generated Code.
This table summarizes two techniques you can use for naming data types in generated code.
Naming Objective | Technique |
---|---|
Configure the code generator to define a particular data item, such as a variable, by using a specific, meaningful type name. | In the model, locate the data item that corresponds
to the variable. For example, trace from the code
generation report to the model. Use the name of the
If
necessary, to prevent
other data items in upstream and downstream blocks from
using the same type name, configure those items to use a
data type setting that is not inherited. By default,
most signals use the inherited type
|
Use the same type name for multiple signals and other data items in a data path, which is a series of connected blocks. | In the model, use the name of a
Usually, no matter where on the data path you specify the type, downstream data items inherit the type. You can configure upstream data items to inherit the type, too. Consider specifying the type in a block that you do not expect to remove or change frequently. |
Define Abstract Numeric Types and Rename Types
This model shows user-defined types, consisting of numeric and alias types. Numeric types allow you to define abstract numeric types, which is particularly useful for fixed-point types. Alias types allow you to rename types, which allows you create a relationship for types.
Explore Example Model
Open the example model and configure it to show the generated names of blocks.
load_system('UserDefinedDataTypes') set_param('UserDefinedDataTypes','HideAutomaticNames','off') open_system('UserDefinedDataTypes')
Key Features of User-Defined Types
Displayed and propagated on signal lines
Used to parameterize a model by type (e.g., In1 specifies its Output data type as
ENG_SPEED
)Types with a common ancestor can be mixed, whereby the common ancestor is propagated (e.g., output of Sum1)
Intrinsically supported by the Simulink Model Explorer
Include an optional header file attribute that is ideal for importing legacy types (ignored for GRT targets)
Types used in the generated code (ignored for GRT targets)
Instructions
Inspect the user-defined types in the Model Explorer by double-clicking the first yellow button below.
Inspect the replacement data type mapping by double-clicking the second yellow button below.
Compile the diagram to display the types in this model (Debug > Update Model > Update Model or Ctrl+D).
Generate code with the blue button below and inspect model files to see how user-defined types appear in the generated code.
Modify the attributes of
ENG_SPEED
andENG_SPEED_OFFSET
and repeat steps 1-4.
Notes
User-defined types are a feature of Simulink that facilitate parameterization of the data types in a model. Embedded Coder preserves alias data type names (e.g.,
ENG_SPEED
) in the generated code, whereas Simulink Coder implements user-defined types as their base type (e.g.,real32_T
).Embedded Coder also enables you to replace the built-in data types with user-defined data types in the generated code.
Control Names of Structure Types
To control the names of the standard structures that Simulink
Coder creates by default to store data
(
for parameter
data, for example), use Configuration Parameters > Code Generation > Identifiers > Global types to specify a naming rule. For more information, see Identifier Format Control.model
_P
When you use nonvirtual buses and parameter structures to aggregate signals
and block parameters into a custom structure in the generated code, control the
name of the structure type by creating a Simulink.Bus
object.
For more information, see Organize Data into Structures in Generated Code.
Generate Code That Reuses Data Types From External Code
To generate code that reuses a data type definition from your external C code,
specify the data scope of the corresponding data type object or enumeration in
Simulink as Imported
. With this setting, the generated
code includes (#include
) the definition from your code. For
more information about controlling the file placement of a custom data type, see
Control File Placement of Custom Data Types.
Instead of creating individual data type objects and enumerated types, and
then configuring them, consider creating the objects and types by using the
Simulink.importExternalCTypes
function. By default, the
function configures the new objects and types so that the generated code imports
(reuses) the type definitions from your code. You can then use the objects and
types to set data types in a model and to configure data type replacements. For
more information, see Simulink.importExternalCTypes
and Exchange Structured and Enumerated Data Between Generated and External Code.
Create Data Type Alias in the Generated Code
This example shows how to configure the generated code to use a data type name (typedef
) that you specify.
Export Type Definition
When you integrate code generated from a model with code from other sources, your model code can create an exported typedef
statement. Therefore, all of the integrated code can use the type. This example shows how to export the definition of a data type to a generated header file.
Create a Simulink.AliasType
object named mySingleAlias
that acts as an alias for the built-in data type single
.
mySingleAlias = Simulink.AliasType('single');
Configure the object to export its definition to a header file called myHdrFile.h
.
mySingleAlias.DataScope = 'Exported'; mySingleAlias.HeaderFile = 'myHdrFile.h';
Open the model ConfigurationInterface
.
open_system('ConfigurationInterface')
Configure the model to show the generated names of blocks.
set_param('ConfigurationInterface','HideAutomaticNames','off')
On the Modeling tab, click Model Data Editor.
In the model, select the Inport block labeled In1
.
Use the Data Type column to set the data type to mySingleAlias
.
set_param('ConfigurationInterface/In1','OutDataTypeStr','mySingleAlias')
Configure In1
to use default storage.
In the C Code tab, select Code Interface > Default Code Mappings.
In the Code Mappings editor, under Inports and Outports, select category Inports. Set the default storage class to Default
.
On the Inports tab, set Storage Class to Model default
.
cm = coder.mapping.api.get('ConfigurationInterface'); setDataDefault(cm,'Inports','StorageClass','Default'); setInport(cm,'In1','StorageClass','Model default');
Generate code from the model.
slbuild('ConfigurationInterface')
### Starting build procedure for: ConfigurationInterface ### Successful completion of code generation for: ConfigurationInterface Build Summary Top model targets: Model Build Reason Status Build Duration ============================================================================================================ ConfigurationInterface Information cache folder or artifacts were missing. Code generated. 0h 0m 11.136s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 11.873s
In the code generation report, view the file ConfigurationInterface_types.h
. The code creates a #include
directive for the generated file myHdrFile.h
.
file = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface_types.h'); coder.example.extractLines(file,'#include "myHdrFile.h"',... '#include "myHdrFile.h"',1,1)
#include "myHdrFile.h"
View the file myHdrFile.h
. The code uses the identifier mySingleAlias
as an alias for the data type real32_T
. By default, generated code represents the Simulink data type single
by using the identifier real32_T
.
The code also provides a macro guard of the form filename_h_
. When you export a data type definition to integrate generated code with code from other sources, you can use macro guards of this form to prevent unintentional identifier clashes.
file = fullfile('slprj','ert','_sharedutils','myHdrFile.h'); coder.example.extractLines(file,'#ifndef myHdrFile_h_',... ' * File trailer for generated code.',1,0)
#ifndef myHdrFile_h_ #define myHdrFile_h_ #include "rtwtypes.h" typedef real32_T mySingleAlias; typedef creal32_T cmySingleAlias; #endif /* myHdrFile_h_ */ /*
View the file ConfigurationInterface.h
. The code uses the data type alias mySingleAlias
to define the structure field input1
, which corresponds to the Inport block labeled In1
.
file = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface.h'); coder.example.extractLines(file,... '/* External inputs (root inport signals with default storage) */',... '} ExtU_ConfigurationInterface_T;',1,1)
/* External inputs (root inport signals with default storage) */ typedef struct { mySingleAlias input1; /* '<Root>/In1' */ MYTYPE input2; /* '<Root>/In2' */ MYTYPE input3; /* '<Root>/In3' */ MYTYPE input4; /* '<Root>/In4' */ } ExtU_ConfigurationInterface_T;
Import Type Definition
When you integrate code generated from a model with code from other sources, to avoid redundant typedef
statements, you can import a data type definition from the external code. This example shows how to import your own definition of a data type from a header file that you create.
Use a text editor to create a header file to import. Name the file ex_myImportedHdrFile.h
. Place it in your working folder. Copy the following code into the file.
#ifndef HEADER_myImportedHdrFile_h_ #define HEADER_myImportedHdrFile_h_ typedef float myTypeAlias; #endif
The code uses the identifier myTypeAlias
to create an alias for the data type float
. The code also uses a macro guard of the form HEADER_filename_h
. When you import a data type definition to integrate generated code with code from other sources, you can use macro guards of this form to prevent unintentional identifier clashes.
At the command prompt, create a Simulink.AliasType
object named myTypeAlias
that creates an alias for the built-in type single
. The Simulink data type single
corresponds to the C data type float
.
myTypeAlias = Simulink.AliasType('single');
Configure the object so that generated code imports the type definition from the header file ex_myImportedHdrFile.h
.
myTypeAlias.DataScope = 'Imported'; myTypeAlias.HeaderFile = 'ex_myImportedHdrFile.h';
Open the model ConfigurationInterface
.
open_system('ConfigurationInterface')
On the Modeling tab, click Model Data Editor.
In the model, select the Inport block labeled In1
.
Use the Data Type column to set the data type to myTypeAlias
.
set_param('ConfigurationInterface/In1','OutDataTypeStr','myTypeAlias')
Generate code from the model.
slbuild('ConfigurationInterface')
### Starting build procedure for: ConfigurationInterface ### Successful completion of code generation for: ConfigurationInterface Build Summary Top model targets: Model Build Reason Status Build Duration ======================================================================================== ConfigurationInterface Generated code was out of date. Code generated. 0h 0m 9.1382s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 10.01s
In the code generation report, view the file ConfigurationInterface_types.h
. The code creates a #include
directive for your header file ex_myImportedHdrFile.h
.
file = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface_types.h'); coder.example.extractLines(file,'#include "ex_myImportedHdrFile.h',... '/* Forward declaration for rtModel */',1,0)
#include "ex_myImportedHdrFile.h" #include "MYTYPE.h" #ifndef DEFINED_TYPEDEF_FOR_Table1_Type_ #define DEFINED_TYPEDEF_FOR_Table1_Type_ typedef struct { MYTYPE BP[11]; MYTYPE Table[11]; } Table1_Type; #endif #ifndef DEFINED_TYPEDEF_FOR_Table2_Type_ #define DEFINED_TYPEDEF_FOR_Table2_Type_ typedef struct { MYTYPE BP1[3]; MYTYPE BP2[3]; MYTYPE Table[9]; } Table2_Type; #endif #endif /* ConfigurationInterface_types_h_ */ /* * File trailer for generated code. * * [EOF] */
View the file ConfigurationInterface.h
. The code uses the data type alias myTypeAlias
to define the structure field input1
, which corresponds to the Inport block labeled In1
.
file = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface.h'); coder.example.extractLines(file,... '/* External inputs (root inport signals with default storage) */',... '} ExtU_ConfigurationInterface_T;',1,1)
/* External inputs (root inport signals with default storage) */ typedef struct { myTypeAlias input1; /* '<Root>/In1' */ MYTYPE input2; /* '<Root>/In2' */ MYTYPE input3; /* '<Root>/In3' */ MYTYPE input4; /* '<Root>/In4' */ } ExtU_ConfigurationInterface_T;
Display Base Data Types and Aliases on Model Diagram
When you display signal data types on the model diagram, you can choose to display aliases (such as myTypeAlias
) and base data types (such as int16
). To display aliases, on the Debug tab, select Information Overlays > Alias Data Types. To display the base types, select Information Overlays > Base Data Types. For more information, see Port Data Types.
Create a Named Fixed-Point Data Type in the Generated Code
This example shows how to create and name a fixed-point data type in generated code. You can use the name of the type to specify parameter and signal data types throughout a model and in generated code.
The example model FixedPointCodeGeneration
uses fixed-point data types. So that you can more easily see the fixed-point data type in the generated code, in this example, you create a Simulink.Parameter
object that appears in the code as a global variable.
Create a Simulink.AliasType
object that defines a fixed-point data type. Name the object myFixType
. The generated code uses the name of the object as a data type.
myFixType = Simulink.AliasType('fixdt(1,16,4)');
Open the model FixedPointCodeGeneration
.
open_system('FixedPointCodeGeneration')
Configure the model to show the generated names of the blocks.
set_param('FixedPointCodeGeneration','HideAutomaticNames','off')
On the Modeling tab, click Model Data Editor.
In the Model Data Editor, select the Parameters tab.
In the model, select the Gain block.
In the Model Data Editor, for the row that represents the Gain parameter of the Gain block, in the Value column, specify myParam
.
Click the action button (with three vertical dots) next to the parameter value. Select Create.
In the Create New Data dialog box, set Value
to Simulink.Parameter(8)
. In this example, for more easily readable code, you set the parameter value to 8 instead of -3.2. Click Create. A Simulink.Parameter
object named myParam
appears in the base workspace. The object stores the real-world value 8
, which the Gain block uses for the value of the Gain parameter.
In the Simulink.Parameter property dialog box, set Storage class to ExportedGlobal
. Click OK. With this setting, myParam
appears in the generated code as a separate global variable.
In the Model Data Editor, use the Data Type column to set the data type of the Gain parameter of the Gain block to myFixType
.
On the Signals tab, use the Data Type column to set the data type of the Gain block output to myFixType
.
Use the Data Type column to set the data type of the Conversion
block output to myFixType
.
Alternatively, you can use these commands at the command prompt to configure the blocks and create the object:
set_param('FixedPointCodeGeneration/Gain','Gain','myParam','OutDataTypeStr','myFixType',... 'ParamDataTypeStr','myFixType') myParam = Simulink.Parameter(8); myParam.StorageClass = 'ExportedGlobal'; set_param('FixedPointCodeGeneration/Conversion','OutDataTypeStr','myFixType')
In the model, set Configuration Parameters > Code Generation > System target file to ert.tlc
. With this setting, the code generator honors data type aliases such as myFixType
.
set_param('FixedPointCodeGeneration','SystemTargetFile','ert.tlc')
Select the configuration parameter Generate code only.
set_param('FixedPointCodeGeneration','GenCodeOnly','on')
Generate code from the model.
slbuild('FixedPointCodeGeneration')
### Starting build procedure for: FixedPointCodeGeneration ### Successful completion of code generation for: FixedPointCodeGeneration Build Summary Top model targets: Model Build Reason Status Build Duration ============================================================================================================== FixedPointCodeGeneration Information cache folder or artifacts were missing. Code generated. 0h 0m 11.447s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 12.363s
In the code generation report, view the file FixedPointCodeGeneration_types.h
. The code defines the type myFixType
based on an integer type of the specified word length (16).
file = fullfile('FixedPointCodeGeneration_ert_rtw','FixedPointCodeGeneration_types.h'); coder.example.extractLines(file,'#ifndef DEFINED_TYPEDEF_FOR_myFixType_',... '/* Forward declaration for rtModel */',1,0)
#ifndef DEFINED_TYPEDEF_FOR_myFixType_ #define DEFINED_TYPEDEF_FOR_myFixType_ typedef int16_T myFixType; typedef cint16_T cmyFixType; #endif
View the file FixedPointCodeGeneration.c
. The code uses the type myFixType
, which is an alias of the integer type int16
, to define the variable myParam
.
file = fullfile('FixedPointCodeGeneration_ert_rtw','FixedPointCodeGeneration.c'); coder.example.extractLines(file,'myFixType myParam = 128;','myFixType myParam = 128;',1,1)
myFixType myParam = 128; /* Variable: myParam
The stored integer value 128
of myParam
is not the same as the real-world value 8
because of the scaling that the fixed-point data type myFixType
specifies. For more information, see Scaling (Fixed-Point Designer) in the Fixed-Point Designer documentation.
The line of code that represents the Gain block applies a right bit shift corresponding to the fraction length specified by myFixType
.
coder.example.extractLines(file,... 'FixedPointCodeGeneration_Y.Out1 = (myFixType)((myParam * rtb_Conversion) >> 4);',... 'FixedPointCodeGeneration_Y.Out1 = (myFixType)((myParam * rtb_Conversion) >> 4);',1,1)
FixedPointCodeGeneration_Y.Out1 = (myFixType)((myParam * rtb_Conversion) >> 4);
Rename Data Type Object
To rename a data type object such as Simulink.AliasType
or
Simulink.Bus
after you create it (for example, to rename an
alias when coding standards change or when you encounter a naming conflict), you
can allow Simulink to rename the object and correct
all of the references to the object that appear
in a model or models. In the Model Explorer, right-click the variable and select
Rename All. For more information, see Rename Variables.
Display Signal Data Types on Block Diagram
For readability, you can display signal data types directly on a block diagram. When you use custom names for primitive data types, you can choose to display the custom name (the alias), the underlying primitive, or both. See Port Data Types.
Data Type Replacement Limitations
You cannot configure the generated code to use these custom C data types:
Array types
Pointer types
const
orvolatile
types
You cannot configure the generated code to use generic C primitive types such as
int
andshort
.
When you set Data type replacement to Use C data
types with fixed-width integers
, these limitations apply:
You cannot generate code for third-party hardware workflows that use Embedded Coder® support packages.
In generated C++ code, statements that include the header files
stdint.h
andstdbool.h
violate MISRA™ C++:2008 rule 18-0-1.If the model includes Simscape™ blocks, some of the generated source files might contain
#include "rtwtypes.h"
. Generated code from Simscape blocks is not intended for production deployment. The build process can compile the generated code because the code generator creates artwtypes.h
file for continuous-time models.
When you set Data type replacement to Use coder
typedefs
and select the Specify custom data type
names configuration parameter, these limitations apply:
Data type replacement does not support multiple levels of mapping. Each replacement data type name maps directly to one or more built-in data types.
Data type replacement is not supported for simulation target code generation for referenced models.
Code generation performs data type replacements while generating
.c
,.cpp
, and.h
files. Code generation places these files in build folders (including top and referenced model build folders) and in the_sharedutils
folder. Exceptions are as follows:rtwtypes.h
multiword_types.h
model_reference_types.h
builtin_typeid_types.h
model_sf.c
or.cpp
(ERT S-function wrapper)model_dt.h
(C header file supporting external mode)model_capi.c
or.cpp
model_capi.h
Data type replacement is not supported for complex data types.
Many-to-one data type replacement is not supported for the
char
data type. Attempting to usechar
as part of a many-to-one mapping to a custom data type represents a violation of the MISRA C™ specification. For example, if you mapchar
(char_T
) and eitherint8
(int8_T
) oruint8
(uint8_T
) to the same replacement type, the result is a MISRA C violation. If you try to generate C++ code, the code generator makes invalid implicit type casts, resulting in compile-time errors. Usechar
only in one-to-one data type replacements.Many-to-one data type replacement is not supported for Simulink Coder data types of different sizes. For more information, see Replace Implementation-Dependent Types with the Same Type Name.
For ERT S-functions, replace the
boolean
data type with only an 8-bit integer,int8
, oruint8
.Set the
DataScope
property of aSimulink.AliasType
object toAuto
(default) orImported
.