Manage Replacement of Simulink Data Types in Generated Code - MATLAB & Simulink (original) (raw)

You can manage the replacement of Simulink® data types in generated code by using:

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 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
double double
single float
int32 int32_t
int16 int16_t
int8 int8_t
uint32 uint32_t
uint16 uint16_t
uint8 uint8_t
boolean bool
int int
uint unsigned int
char char
uint64 uint64_t
int64 int64_t

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
double real_T
single real32_T
int32 int32_T
int16 int16_T
int8 int8_T
uint32 uint32_T
uint16 uint16_T
uint8 uint8_T
boolean boolean_T
int int_T
uint uint_T
int char_T
uint64 uint64_T
int64 int64_T

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 toint8_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 toint8, 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 typeint, whose bit length depends on the native integer size of your target hardware. Other implementation-dependent types includeboolean_T, char_T, anduint_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 andint32_T with the same type name, say,myInt.

  1. Configure your target hardware settings in > .
  2. Create a Simulink.AliasType object namedmyInt. In this case, becauseint_T and int32_T represent a 32-bit signed integer, set BaseType to int32.
    myInt = Simulink.AliasType('int32')
  3. 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")
  4. In the Replacement Name fields for both data types, specify myInt.

Note

Many-to-one data type replacement does not support thechar (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 aSimulink.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 toint8_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 (seeData 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 theSimulink.AliasType object to set the data type of the item.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 typeInherit: Inherit via internal rule.
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 aSimulink.AliasType object to set the data type of one of the signals in the path, for example, a root-level Inport block or aConstant block. For example, if the path begins with an Inport block at the root level of the model, you can specify the type in that block. By default, due to data type propagation, the data items in the other blocks typically inherit the same type.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

Instructions

  1. Inspect the user-defined types in the Model Explorer by double-clicking the first yellow button below.
  2. Inspect the replacement data type mapping by double-clicking the second yellow button below.
  3. Compile the diagram to display the types in this model (Debug > Update Model > Update Model or Ctrl+D).
  4. Generate code with the blue button below and inspect model files to see how user-defined types appear in the generated code.
  5. Modify the attributes of ENG_SPEED and ENG_SPEED_OFFSET and repeat steps 1-4.

Notes

Control Names of Structure Types

To control the names of the standard structures that Simulink Coder creates by default to store data (_`model`__P for parameter data, for example), use > > > to specify a naming rule. For more information, see Identifier Format Control.

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, seeControl 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 theSimulink.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 13.241s

1 of 1 models built (0 models already up to date) Build duration: 0h 0m 14.167s

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)

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; / '/In1' / MYTYPE input2; / '/In2' / MYTYPE input3; / '/In3' / MYTYPE input4; / '/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 8.7197s

1 of 1 models built (0 models already up to date) Build duration: 0h 0m 9.7531s

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_ */

/*

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; / '/In1' / MYTYPE input2; / '/In2' / MYTYPE input3; / '/In3' / MYTYPE input4; / '/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 14.545s

1 of 1 models built (0 models already up to date) Build duration: 0h 0m 15.645s

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 orSimulink.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 . 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. SeePort Data Types.

Data Type Replacement Limitations

When you set Data type replacement to Use C data types with fixed-width integers, these limitations apply:

When you set Data type replacement to Use coder typedefs and select the Specify custom data type names configuration parameter, these limitations apply: