Create Data Interface Configuration Programmatically
This example shows how to programmatically create a data interface configuration in an Embedded Coder Dictionary. To automate the creation of an Embedded Coder Dictionary in a script or to create a data interface configuration programmatically, use this programming interface.
In this example, you create a shared Embedded Coder Dictionary in an SLDD file so that multiple models can use the code definitions. In the data interface configuration, you create code definitions that control the naming and placement of global data and functions. You also use a memory section definition that includes a pragma to place the data and functions in fast memory. To verify the architecture that you set up through the code definitions, apply the definitions to a model, and then generate code.
Set Up Embedded Coder Dictionary
Create a Simulink data dictionary (SLDD file) to store the code definitions. Storing the definitions in a shared SLDD file enables you to use the definitions in multiple models.
dictionaryFile = Simulink.data.dictionary.create('codeDefinitions.sldd');
Create an Embedded Coder Dictionary in the SLDD file. When you create the dictionary, represent it with a coder.Dictionary
object. Use the object to perform operations on the entire Embedded Coder Dictionary and to access sections of it.
codeDictionary = coder.dictionary.create('codeDefinitions.sldd');
The coder.Dictionary
object contains three coder.dictionary.Section
objects that represent the sections of an Embedded Coder Dictionary: Storage Classes, Memory Sections, and Function Customization Templates. A coder.dictionary.Section
object contains coder.dictionary.Entry
objects that represent the definitions in that section. To interact with a definition and access its properties, use the coder.dictionary.Entry
object that represents it.
When you create an Embedded Coder Dictionary, the dictionary loads definitions from the Simulink
package so that the Embedded Coder Dictionary then contains built-in definitions. If you have custom code definitions stored in a package, load that package to the dictionary. When you use the Embedded Coder Dictionary to configure the code interface for a model, you can apply definitions from packages that you loaded.
Memory Sections
To create memory section definitions, add entries to the Memory Sections section. Storage classes and function customization templates residing in the same dictionary can use these memory sections. For this example, add a memory section named FastMem
, which allocates memory by using a pragma. When you apply the memory section to a storage class or function template, their generated definitions and declarations are in the memory section.
memorySections = getSection(codeDictionary,'MemorySections'); msFast = addEntry(memorySections,'FastMem'); set(msFast,'PreStatement','#pragma begin FAST'); set(msFast,'Comment','/*Fast onchip RAM*/'); set(msFast,'PostStatement','#pragma end FAST');
Storage Classes
For this example, create a storage class named ExportToPrivateHeader
, which generates a global variable declaration in the header file $R_private.h
and definition in $R_private.c
. The token $R
signifies the name of the root model for which you generate code. To use a variable in external code, apply this storage class to the data element and include the header file in the external code.
storageClasses = getSection(codeDictionary,'StorageClasses'); exportToPrivateH = addEntry(storageClasses,'ExportToPrivateHeader'); set(exportToPrivateH,'HeaderFile','$R_private.h','DataScope','Exported');
To apply the memory section FastMem
to the storage class, use the coder.dictionary.Entry
object that represents the memory section.
set(exportToPrivateH,'MemorySection',msFast);
Create another storage class definition named ImportFromHeader
for data that external code defines. Because the storage class has 'DataScope'
set to 'Imported'
, the generated code reads and writes to the variable defined by your external code.
importFromH = addEntry(storageClasses,'ImportFromHeader'); set(importFromH,'DataScope','Imported','HeaderFile','$R_input.h','DataInit','Dynamic');
Function Customization Templates
To create a function customization template, create another coder.dictionary.Section
object that represents the Function Customization Templates section. Add an entry to this section, which represents a definition that controls the appearance of generated entry-point functions. Apply the memory section FastMem
to the function template.
functionTemplates = getSection(codeDictionary,'FunctionCustomizationTemplates'); fcGlobal = addEntry(functionTemplates,'GlobalFunctions'); set(fcGlobal,'FunctionName','$R$N'); set(fcGlobal,'MemorySection',msFast); saveChanges(dictionaryFile);
Apply Code Generation Definitions
Confirm the settings of your code definitions by applying them to a model and generating code. You can configure the model code interface to use the code definitions programmatically or by using the Code Mappings editor.
Open the model ConfigurationInterface and attach the data dictionary that you created to the model.
open_system('ConfigurationInterface') set_param('ConfigurationInterface','EmbeddedCoderDictionary','codeDefinitions.sldd');
The model contains four inports. In1
is configured to use the storage class ImportFromFile
. For this example, you configure the other inports to read data from external code by default. The model also contains state data for the Delay block that you configure to be accessible by external code. When you apply the storage classes ImportFromHeader
and ExportToPrivateHeader
to the model elements, the generated code conforms to this architecture.
To configure the model with the code generation definitions, get the code mapping for the model.
cm = coder.mapping.api.get('ConfigurationInterface');
Use the code mapping to configure data to use your storage class definitions. For the state data in the Delay block, specify the storage class ExportToPrivateHeader
.
setState(cm,'ConfigurationInterface/Delay','StorageClass','ExportToPrivateHeader');
Specify the default storage class ImportFromHeader
for root inport data. For inports of the model, by default, the generated code uses data that external code defines in the file ConfigurationInterface_input.c
. To compile and link this external file when you build the generated code, set the configuration parameter CustomSource
to ConfigurationInterface_input.c
.
setDataDefault(cm,'Inports','StorageClass','ImportFromHeader'); set_param('ConfigurationInterface','CustomSource','ConfigurationInterface_input.c');
Specify the function customization template GlobalFunctions
for the default code generation of execution functions.
setFunctionDefault(cm,'Execution','FunctionCustomizationTemplate','GlobalFunctions');
Verify that the code definitions reflect your specifications.
Open the Code Mappings editor. In the Simulink Editor, open the Embedded Coder app. On the C Code tab, select Code Interface > Default Code Mappings.
In the Code Mappings editor, on the Data Defaults tab, expand the Inports and Outports section. The Inports category shows the storage class
ImportFromHeader
. On the Inports tab, the inportsIn2
,In3
, andIn4
use the model default storage classImportFromHeader
. The inportIn1
has a different storage class specified,ImportFromFile
. This setting overrides the default storage class so thatIn1
reads data from a different external file.On the Signals/States tab, the state X shows the storage class
ExportToPrivateHeader
.On the Function Defaults tab, the Execution category shows the template
GlobalFunctions
.Open the Embedded Coder Dictionary. On the C Code tab, select Code Interface > Embedded Coder Dictionary. The code definitions that you added to the dictionary appear in the tabs.
Generate and Verify the Code
Generate code for the model.
slbuild('ConfigurationInterface', 'generateCodeOnly', true);
### 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 16.695s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 18.006s
The header file ConfigurationInterface_private.h
defines the Delay block state data according to the storage class ExportToPrivateHeader
. External code can access this state data.
file = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface_private.h'); coder.example.extractLines(file,'/* Storage class', ... '#endif');
/* Storage class 'ExportToPrivateHeader' */ /*Fast onchip RAM*/ #pragma begin FAST extern MYTYPE X; /* '<Root>/Delay' */ #pragma end FAST
Because the inports use the storage class specifications, the generated header files do not define inport data. Instead, the generated file ConfigurationInterface.h
includes the external header file that you specified in the storage class definition. The generated code reads inport data from the variables defined in the external file ConfigurationInterface_inputs.c
.
In the generated source file ConfigurationInterface.c
, the execution (step) function reflects the settings of the function customization template GlobalFunctions
. Because the template GlobalFunctions
uses the memory section FastMem
, the execution function is stored in the memory section and reflects the prestatement, poststatement, and comments that you set in the FastMem
definition.
file2 = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface.c'); coder.example.extractLines(file2,'/* Model step function */', ... '/* Logic:');
/* Model step function */ /*Fast onchip RAM*/ #pragma begin FAST void ConfigurationInterface_step(void) {
After you configure the Embedded Coder Dictionary, you can share the dictionary with your team or organization. You and other users can apply your definitions to multiple models so that the models use the same software architecture.
See Also
Embedded Coder Dictionary | Code Mappings
Editor – C | coder.Dictionary
| coder.mapping.api.CodeMapping
| coder.dictionary.Section
| coder.dictionary.Entry