Control Data and Function Placement in Memory by Inserting Pragmas
For some applications, you can use pragmas and other code decorations to control the
placement of data (global variables) and function definitions in memory. For example, a linker
configuration file can define named sections in a SECTIONS
directive and
map each section to a range of memory addresses. In the C code, you include pragmas that
assign global variables and functions to these named sections and, by extension, to the memory
ranges. By controlling memory placement, you can:
Generate code that is more efficient for your hardware.
Modularize your application code for easier maintenance and modification later in the development process and after deployment.
With Embedded Coder® and memory sections, you can:
Apply default pragmas or other decorations to categories of model data and entry-point functions. To configure these defaults, use the Code Mappings editor. For example, you can:
Apply a default pragma to internal data, which includes block states that the code generator cannot eliminate through optimizations. You can apply a different default pragma to constant parameters, such as nonscalar parameters that the generated code must store in memory.
Apply a default pragma to categories of generated functions, including entry-point functions such as
.model
_step
Override the default pragmas for individual data items such as block parameters, states, and signals. To do so, create your own storage class.
Override the default pragmas for individual functions that correspond to atomic subsystems, which you can configure to appear in the generated code as separate functions with separate data. Use the subsystem parameters dialog box.
Insert Pragmas by Using Memory Sections
In this example, you configure the default memory placement for
all of the data and functions of the algorithm represented by the
example model RollAxisAutopilot
. Then, for some signal data, you override
the default placement.
Explore Example Model and Inspect Default Generated Code
Open the model
RollAxisAutopilot
by typing this command:openExample('RollAxisAutopilot');
The model is configured to generate efficient production code. For example, the configuration parameter Default parameter behavior is set to
Inlined
.In the Apps gallery, under Code generation, click Embedded Coder. The C Code tab opens. Generate code from the model.
In the code generation report, inspect the file
RollAxisAutopilot.h
. The file defines structure types that represent data that the algorithm needs. For example, the file defines a structure type that represents block states such as the states of Discrete-Time Integrator blocks./* Block signals and states (default storage) for system '<Root>' */ typedef struct { real32_T FixPtUnitDelay1_DSTATE; /* '<S7>/FixPt Unit Delay1' */ real32_T Integrator_DSTATE; /* '<S1>/Integrator' */ int8_T Integrator_PrevResetState; /* '<S1>/Integrator' */ } DW;
The file also declares entry-point functions for the model.
/* Model entry point functions */ extern void RollAxisAutopilot_initialize(void); extern void RollAxisAutopilot_step(void);
Inspect
RollAxisAutopilot.c
. This file defines global structure variables to store the data. The file also defines the functions.
In this example, assume your linker configuration file defines named sections
MYALGORITHM_DATA
and MYALGORITHM_CODE
in a
SECTIONS
directive. You can configure the model so that the generated
code includes pragmas, placing the memory allocated for the data and functions in these
named sections.
For a global variable named
myVar
, the pragma syntax is:#pragma SEC_MYALGORITHM_DATA("myVar") double myVar;
For a function named
myFunction
, the pragma syntax is the same except for the section name:#pragma SEC_MYALGORITHM_CODE("myFunction") void myFunction(void)
Create Memory Sections
In this example, you use two pragmas with different syntaxes, so you must create two memory sections.
Open the Embedded Coder app. On the C Code tab, select Code Interface > Embedded Coder Dictionary.
In the Embedded Coder Dictionary dialog box, select the Memory Sections tab and click the Add button.
For the new memory section, set these options:
Name to
MYALGORITHM_DATA
.Statements Surround to
Each variable
.Pre Statement to
#pragma SEC_MYALGORITHM_DATA("$N")
. The token$N
stands for the name of each variable that uses the memory section.
Create another, similar memory section that corresponds to
MYALGORITHM_CODE
.Close the Embedded Coder Dictionary.
Configure Default Pragmas for Data and Functions
On the C Code tab, select Code Interface > Default Code Mappings or Code Interface > Individual Element Code Mappings
In the Data Defaults tab, expand Inports and Outports, Signals and Parameters.
In the table, select the Inports row.
Click the icon and set Memory Section to
MYALGORITHM_DATA
.For the other rows in the table, set Memory Section to
MYALGORITHM_DATA
.Under Function Defaults, for each row in the table, set Memory Section to
MYALGORITHM_CODE
.In your current folder, delete the existing
slprj
folder.Configure the model to generate only code. Select the configuration parameter Configuration Parameters > Generate code only.
Click Generate Code.
Now, the RollAxisAutopilot.c
file applies the pragmas to the
definitions of the structure variables and the functions. For each category of data and
functions that you configured in the Code Mappings editor, the code applies a pragma. For
example, the code applies the MYALGORITHM_DATA
pragma to each of the
structures that store block states, root-level inputs, and root-level outputs.
/* Block signals and states (default storage) */ #pragma SEC_MYALGORITHM_DATA("rtDW") DW rtDW; /* External inputs (root inport signals with default storage) */ #pragma SEC_MYALGORITHM_DATA("rtU") ExtU rtU; /* External outputs (root outports fed by signals with default storage) */ #pragma SEC_MYALGORITHM_DATA("rtY") ExtY rtY;
Retain Default Memory Section After Applying a Default Storage Class or Function Template
In the Code Mappings editor, you can use the Storage Class and
Function Customization Template columns to control the default
appearance of data and functions in the generated code. When you use these columns to
apply a setting other than Default
, the Code Mappings editor
discards the memory section that you applied in the Property Inspector. To retain the
memory section, use the Embedded Coder Dictionary to create a storage class or function
template, then apply the memory section to that storage class or function template.
In this example, you configure the nonparameter data of the model, such as signals and
states, to appear in the same structure by creating a storage class. To retain the
MYALGORITHM_DATA
memory section, you apply the memory section to the
storage class.
In the Embedded Coder Dictionary for the model, select the Storage Classes tab and click the Add button.
For the new storage class, set:
Name to
STRUCT_DATA
.Storage Type to
Structured
.Memory Section to
MYALGORITHM_DATA
.
In the Code Mappings editor, under Data Defaults, in the Storage Class column, select
STRUCT_DATA
for these rows:Inports
Outports
Signals, states and internal data
Generate code from the model.
Inspect
RollAxisAutopilot.c
. Now, the file defines a single structure variable that contains the nonparameter data, applying the pragma to that variable./* Storage class 'STRUCT_DATA' */ #pragma SEC_MYALGORITHM_DATA("STRUCT_DATA_RollAxisAutopilot") RollAxisAutopilot_STRUCT_DATA STRUCT_DATA_RollAxisAutopilot;
Incorporate Default Memory Section into a Storage Class for Individual Mapping
To override the default storage classes that you specify in Code Mappings > Data Defaults, apply a storage class directly to a data item by using the Code Mappings
editor. Directly applying a storage class other than
Auto
or Model default
bypasses the
default memory section that you specify in Data Defaults. To retain
the memory section, create a storage class in the Embedded Coder Dictionary and apply the
desired memory section to it. Then, apply the storage class to individual data items in
the Code Mappings editor. Other models cannot access the storage class and memory section
that you define in the Embedded Coder Dictionary. To share the storage class and memory
section sections among other models, store the Embedded Coder Dictionary in a Simulink
Data Dictionary data (sldd
) outside of your model. Then, share the
dictionary between the target models. For more information, see Migrate Data Interface Configuration from Model File to Shared Data Dictionary.
In RollAxisAutopilot
, in the BasicRollMode
subsystem, the three Gain blocks represent the parameters of a PID control algorithm. In
the Retain Default Memory Section After Applying a Default Storage Class or Function Template section, configure the
nonparameter data of the model, such as signals and states, to appear in the same
structure by applying the default storage class STRUCT_DATA
. In this
example, you configure the output signals of the Gain blocks so that the generated code
allocates memory for them in the MYALGORITHM_DATA
section but does not
appear in the default storage class structure. Define a new storage class
myStore
in the Embedded Coder Dictionary and apply the desired memory
section MYALGORITHM_DATA
to it. Then, directly apply the storage class
to the output signals of the Gain blocks.
In the Embedded Coder Dictionary of the model, select the Storage Classes tab and click the Add button.
For the new storage class, set:
Name to
myStore
.Storage Type to
Structured
.Memory Section to
MYALGORITHM_DATA
.
In the model, navigate into the
BasicRollMode
subsystem. The signals of the subsystem are not automatically populated into the Code Mappings editor. You need to manually add signals by pausing on the ellipsis that appears above or below a signal line to open the action bar. Click the Add Signal button. The button is also available in the Code Mappings editor on the Signals/States tab.After you add the output signals of the Gain blocks, the signal rows appear in the Code Mappings > Signals/States tab. Open the Property Inspector by selecting the signal rows. In the Code section, set these properties:
Storage Class to
myStore
.Identifier to the block names.
Generate code from the model.
Inspect the generated file
RollAxisAutopilot.c
. The file defines a structure variablemyStore_RollAxisAutopilot
and applies the pragma to the variable./* Storage class 'myStore' */ #pragma SEC_MYALGORITHM_DATA("myStore_RollAxisAutopilot") RollAxisAutopilot_myStore myStore_RollAxisAutopilot;
Inspect the generated file
RollAxisAutopilot.h
. The structure variable contains the output signals of the Gain blocks. The output signals are now in a different structure but stored in the sameMYALGORITHM_DATA
memory section.
/* Storage class 'myStore', for system '<Root>' */ typedef struct { real32_T DispGain; /* '<S1>/DispGain' */ real32_T RateGain; /* '<S1>/RateGain' */ real32_T IntGain; /* '<S1>/IntGain' */ } RollAxisAutopilot_myStore;
Configure Pragma to Surround Groups of Definitions
If your build toolchain requires that a pragma or other decoration surround multiple
definitions of variables or functions at once, in an Embedded Coder Dictionary or the Custom
Storage Class Designer, set Statements surround to Group
of variables
(the default in the Custom Storage Class Designer).
Override Default Memory Placement for Individual Data Elements
After you configure memory section defaults in the Code Mappings editor (see Configure Default C Code Generation for Categories of Data Elements and Functions), to override these default settings for individual data elements (signals, parameters, and states), create a storage class and any required memory sections by using the Embedded Coder Dictionary. For more information see, Choose Where to Create and Store Memory Section Definition. When you create the storage class, set the Memory section property to the appropriate memory section. Then, use the Code Mappings editor to apply the storage class to individual data elements.
Choose Where to Create and Store Memory Section Definition
To define a memory section, you must choose where to create it: in an Embedded Coder Dictionary or in a Simulink Shared Dictionary.
If you need to use the memory section only in the Code Mappings editor, define the memory section in an Embedded Coder Dictionary.
If you need to use the memory section only in the Code Mappings editor and want to share it with other models, define the memory section in a Simulink® data dictionary (sldd). For more information, see Share Code Interface Configuration Between Models.
If you need to use the memory section outside of the Code Mappings editor, define the memory section in a package. For example, define memory sections in a package to configure memory sections of an atomic subsystem. For more information, see Override Memory Section for Atomic Subsystem.
Share Memory Section Definition Between Models
If you define the memory section in the Embedded Coder Dictionary of a model, you cannot use the memory section in other models. To share the memory section, migrate the definition to a Simulink® data dictionary (
sldd
). Then, share the dictionary between the target models. For more information, see Migrate Data Interface Configuration from Model File to Shared Data Dictionary.If you define the memory section in a package by using the Custom Storage Class Designer, any model can use the memory section. For more information, see Create Storage Class by Using Custom Storage Class Designer. Add the MATLAB® namespace folder that contains the package folder to the MATLAB search path (see What Is the MATLAB Search Path?).
Override Default Memory Placement for Subsystem Functions and Data
When you use atomic subsystems to partition the generated code into functions (see Generate Subsystem Code as Separate Function and Files), you can apply different memory sections to the functions and data of each subsystem. You can also specify that a subsystem not use a memory section.
To use different memory sections to override the model-level defaults that you set in the Code Mappings editor, see Override Memory Section for Atomic Subsystem.
To specify that a subsystem not use a memory section (in other words, to prevent the subsystem from inheriting the model-level defaults), see Specify That Atomic Subsystem Does Not Use a Memory Section.
Override Memory Section for Atomic Subsystem
The memory sections that you specify for a subsystem override the model-level defaults that you set in the Code Mappings editor. Use this technique to aggregate the data and instruction code for subroutines or subcomponents (represented by subsystems) into different regions of memory. To apply a memory section directly to an atomic subsystem, define the memory section in a package by using the Custom Storage Class Designer. You cannot use a memory section that you define in an Embedded Coder Dictionary. Then, load the package into the model and configure the subsystem block parameters to specify the memory section.
To create the memory section:
In your current folder, create MATLAB namespace folder
+myPackage
. The folder contains files that define a package namedmyPackage
. For more information, see Create and Apply Storage Class Defined in User-Defined Package.To make the package available outside of your current folder, optionally, you can add the folder that contains folder
+myPackage
to the MATLAB search path.Open the Custom Storage Class designer.
cscdesigner('myPackage');
In the Custom Storage Class Designer, select the Memory Section tab.
Click New.
For the new memory section, set these options:
Name to
MYALGORITHM_DATA
.Statements surround to
Each variable
.Pre statement to
#pragma SEC_MYALGORITHM_DATA("$N")
.
Click Apply and Save.
Set your current folder to the folder that contains the
+myPackage
folder.
To apply the memory section in an atomic subsystem:
Configure the Embedded Coder Dictionary of the model to load the package that defines the memory section, as described in Refer to Code Generation Definitions in a Package.
To configure the subsystem to use the memory section, open the subsystem parameters dialog box. On the Code Generation tab:
Set Function packaging to
Nonreusable function
orReusable function
(for reentrant code).If you set Function packaging to
Nonreusable function
, to enable configuration of memory sections for the subsystem data, select Function with separate data. If you do not select Function with separate data, the subsystem data inherits memory sections from the model or, if applicable, a parent subsystem.To apply the
MYALGORITHM_DATA
memory section directly to the subsystem functions and data, use these block parameters:Memory section for initialize/terminate functions
Memory section for execution functions
Memory section for constants
Memory section for internal data
Memory section for parameters
Specify That Atomic Subsystem Does Not Use a Memory Section
By default, subsystem functions and data inherit the model-level memory sections that you specify for relevant function and data categories in the Code Mappings editor. For example, if you specify a function customization template for the Execution category, and that template carries a memory section, the memory section applies to subsystem execution functions as well as model entry-point execution functions.
To specify that a subsystem does not use a memory section, open the subsystem
parameters dialog box. On the Code Generation tab, set these
parameters to Default
:
Memory section for initialize/terminate functions
Memory section for execution functions
Memory section for constants
Memory section for internal data
Memory section for parameters
With these settings, the subsystem does not use a memory section for the data or functions that each parameter represents.
Limitations and Other Considerations
The settings that you specify for an atomic, nonreusable subsystem with separate data apply only to the data and functions of that subsystem, not to data in similarly configured child subsystems. Atomic, nonreusable child subsystems with separate data can inherit memory sections from the containing model, not from the parent subsystem.
If you use Build This Subsystem or Build Selected Subsystem to generate code for an atomic subsystem that specifies memory sections, the code generator ignores the subsystem-level specifications and uses the model-level specifications instead. For information about building subsystems, see Generate Code and Executables for Individual Subsystems.
Share Memory Section Between Packages (Package Memory Sections Only)
Packages can access and use memory sections that are defined in other packages,
including user-defined packages and built-in packages such as Simulink
.
Only one copy of the memory section exists, in the package that defines it. Other packages
refer to the memory section by pointing to it in its original location. Changes to the
memory section, including changes to a built-in memory section in later MathWorks® product releases, are immediately available in every referencing package.
To configure a package to refer to a memory section that is defined in another package:
Open the Custom Storage Class Designer. At the command prompt, enter
cscdesigner
.Select the Memory Section tab.
Use Select Package to select the package in which you want to reference a class or section defined in another package.
In the Memory section 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 reference's initial properties.
Use the Name field to enter a name for the new reference. The name must be unique in the importing package, but can duplicate the name in the source package.
Set Refer to memory section in package to specify the package that contains the memory section that you want to reference.
Set Memory section to reference to specify the memory section to be referenced.
Click OK or Apply to save the changes to memory. To save the changes permanently, click Save.
Control Appearance of Memory Section Drop-Down List (Package Memory Sections Only)
When you apply a memory section that is defined in a package, select the memory section from a drop-down list. To control the order of the memory sections in the list, in the Custom Storage Class Designer, use the Up and Down buttons. The order of memory sections in drop-down lists matches the order in the Custom Storage Class Designer.
Protect Definitions of Package Memory Sections (Package Memory Sections Only)
When you click Save in the Custom Storage Class Designer, the
Designer saves memory section and custom storage class definitions into the
csc_registration.m
file in the package namespace folder. To determine
the location of this file, in the Custom Storage Class Designer, inspect the value of
Filename.
You can prevent changes to the memory section definitions of an entire package by
converting the csc_registration.m
file from a MATLAB file to a P-file. Use the pcode
function.
A best practice is to keep csc_registration.m
and
csc_registration.p
in your package namespace folder. That way, if you
need to modify the memory sections by using the Designer, you can delete
csc_registration.p
and later regenerate it after you finish the
modifications. Because the P-coded version of the file takes precedence, while both files
exist in the package folder, the memory sections are protected.
Limitations
The code generator does not apply memory sections to data that uses these built-in storage classes:
ExportedGlobal
ImportedExtern
ImportedExternPointer
In the Custom Storage Class Designer, the storage type qualifier that you specify for a memory section by using the Qualifier text box affects only data items that use a storage class setting other than these built-in storage classes:
ExportedGlobal
ImportedExtern
ImportedExternPointer
Model Default
when the default storage class setting for the data item is set toDefault
The code generator omits the qualifier from other data categories.
When you create a subsystem in a custom block library, you cannot specify memory sections for the subsystem definition in the library. Instead, specify memory sections for the subsystem instances that you place in your models.
Related Topics
- How Generated Code Stores Internal Signal, State, and Parameter Data
- Organize Parameter Data into a Structure by Using Struct Storage Class
- Define Service Interfaces, Storage Classes, Memory Sections, and Function Templates for Software Architecture
- Create Storage Classes by Using the Custom Storage Class Designer
- Protect Global Data with const and volatile Type Qualifiers
- Data Structures in the Generated Code