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.
In this example, you configure the default memory placement for
all of the data and functions of the algorithm represented by the
example model rtwdemo_roll
. Then, for some signal data, you override the
default placement.
Open the example model.
open_system('rtwdemo_roll')
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
rtwdemo_roll.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 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_rtwdemo_roll_T;
The file also declares entry-point functions for the model.
/* Model entry point functions */ extern void rtwdemo_roll_initialize(void); extern void rtwdemo_roll_step(void);
Inspect rtwdemo_roll.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)
In this example, you use two pragmas with different syntaxes, so you must create two memory sections.
Underneath the block diagram, under Code Mappings - C > Data Defaults, click the Embedded Coder Dictionary icon .
In the Embedded Coder Dictionary dialog box, select the Memory Sections tab.
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
.
In the model, inspect the Code Mappings - C > Data Defaults tab.
In the table, select the Inports row.
In the Property Inspector, 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.
Generate code from the model.
Now, the rtwdemo_roll.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 states (default storage) */ #pragma SEC_MYALGORITHM_DATA("rtwdemo_roll_DW") DW_rtwdemo_roll_T rtwdemo_roll_DW; /* External inputs (root inport signals with default storage) */ #pragma SEC_MYALGORITHM_DATA("rtwdemo_roll_U") ExtU_rtwdemo_roll_T rtwdemo_roll_U; /* External outputs (root outports fed by signals with default storage) */ #pragma SEC_MYALGORITHM_DATA("rtwdemo_roll_Y") ExtY_rtwdemo_roll_T rtwdemo_roll_Y;
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 all of the
rows except:
External parameter objects
Model parameters
Global data stores
Constants
Generate code from the model.
Inspect rtwdemo_roll.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_rtwdemo_roll") rtwdemo_roll_STRUCT_DATA STRUCT_DATA_rtwdemo_roll;
To override the default storage classes that you specify in Code Mappings - C > Data Defaults, you can apply a storage class directly to a data item by using the Model
Data Editor. Directly applying any storage class other than
Auto
or Model default
bypasses the
default memory section that you specify in Data Defaults. To retain
the memory section, you must migrate the memory section definition out of the Embedded
Coder Dictionary and into a package, which is a folder that can contain storage class and
memory section definitions. Then, you can create a storage class in the package, apply the
memory section to the storage class, and apply the storage class directly to individual
data items in the Model Data Editor.
In rtwdemo_roll
, in the BasicRollMode
subsystem,
the three Gain blocks represent the parameters of a PID control algorithm. In this
example, you configure the output signals of these blocks so that the generated code
allocates memory for them and places the memory in the MYALGORITHM_DATA
section. You also configure the signals so that the code defines them in
mySigs.c
and declares them in mySigs.h
.
To create the memory section and the storage class:
In your current folder, create a folder named +myPackage
. The
folder defines a package named myPackage
.
To make the package available outside of your current folder, optionally, you
can add the folder containing the +myPackage
folder to the MATLAB
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, which match the options that you
set for MYALGORITHM_DATA
in the Embedded Coder Dictionary:
Name to MYALGORITHM_DATA
.
Statements surround to Each
variable
.
Pre statement to #pragma
SEC_MYALGORITHM_DATA("$N")
.
Click Apply and Save.
In the myPackage
package folder, create a folder named
@Signal
.
In the @Signal
folder, create a file named
Signal.m
.
classdef Signal < Simulink.Signal methods function setupCoderInfo(h) useLocalCustomStorageClasses(h, 'myPackage'); end function h = Signal() % SIGNAL Class constructor. end % End of constructor end % methods end % classdef
The file defines a class named myPackage.Signal
, which is
derived from the built-in class Simulink.Signal
. The class
definition overrides the setupCoderInfo
method, which the
Simulink.Signal
class already implements. The new
implementation specifies that objects of the myPackage.Signal
class use custom storage classes from the myPackage
package
instead of custom storage classes from the built-in Simulink
package.
Set your current folder to the folder that contains the
+myPackage
folder.
In the Custom Storage Class Designer for myPackage
, select
the Custom Storage Class tab.
Click New.
For the new custom storage class, set these properties:
Name to myCSC
.
Clear For parameters.
Memory section to
MYALGORITHM_DATA
.
Data scope to
Exported
.
Header file to mySigs.h
.
Definition file to mySigs.c
.
Click Apply and Save.
To apply the storage class in the model:
In the model, on the Modeling tab, select Model Explorer.
In the Model Explorer Model Hierarchy pane, select Base Workspace.
In the Model Explorer toolbar, click the arrow next to the Add Signal button and select Customize class lists.
In the Customize class lists dialog box, under Signal classes, select the check box next to myPackage.Signal and click OK.
In the Model Explorer, click the arrow next to Add Signal
again and select myPackage Signal. A
myPackage.Signal
object appears in the base workspace.
Delete the myPackage.Signal
object from the base workspace.
Now, when you use the Model Data Editor to apply storage classes to signals, you can
choose storage classes from the myPackage
package.
In the model, navigate into the BasicRollMode
subsystem.
Underneath the block diagram, select the Model Data Editor > Signals tab.
In the model, select the three Gain blocks.
In the Model Data Editor, in the data table, for any
of the highlighted rows, set Storage Class to
myCSC
.
Generate code from the model.
Inspect the generated file mySigs.c
. The file defines the
global variables that correspond to the Gain block outputs in the
model. The pragma applies to the definitions.
/* Definition for custom storage class: myCSC */ #pragma SEC_MYALGORITHM_DATA("DispGain") real32_T DispGain; #pragma SEC_MYALGORITHM_DATA("IntGain") real32_T IntGain; #pragma SEC_MYALGORITHM_DATA("RateGain") real32_T RateGain;
Now, two definitions of the MYALGORITHM_DATA
memory section exist:
One in the Embedded Coder Dictionary and one in myPackage
. When you
make changes to the memory section, make the same changes for each definition.
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).
After you configure memory section defaults in the Code Mappings editor (see Configure Default C Code Generation for Categories of Model Data 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 Custom Storage Class Designer. In the Designer, when you create the storage class, set the Memory section property to the appropriate memory section. Then, use the Model Data Editor to apply the storage class to individual data elements.
To define a memory section, you must choose where to create it: in an Embedded Coder Dictionary or in a package (by using the Custom Storage Class Designer).
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 outside of the Code Mappings editor, for example, in the Model Data Editor, define the memory section in a package.
Optionally, you can enable use of the package memory section in the Code Mappings editor by loading the package into an Embedded Coder Dictionary (see Refer to Code Generation Definitions in a Package). However, if you create storage classes in the dictionary, you cannot apply the package memory section to them. To associate a memory section with storage classes that you define in an Embedded Coder Dictionary and with other storage classes that you define in a package, maintain two definitions of the memory section: one in the dictionary and one in the package.
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 Share Embedded Coder Dictionary Definition Between Models.
If you define the memory section in a package, any model can use the memory section. Add the folder containing the package folder to the MATLAB® path (see What Is the MATLAB Search Path? (MATLAB)).
Packages can access and use memory sections that are defined in other packages,
including custom 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 some other 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.
When you apply a package memory section, you 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.
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 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 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, the memory sections are protected.
.
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 Not Use a Memory Section.
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 sections in a package. You cannot use a memory section that you define in an Embedded Coder Dictionary.
In the target model, set Configuration Parameters > Code Generation > Advanced parameters > Memory Sections > Package to the name of the package. If the package does not appear in the list, click Refresh package list.
Configure the Embedded Coder Dictionary of the model to load the target package as described in Refer to Code Generation Definitions in a Package.
Configure the target subsystem to use the memory section. In the subsystem parameters dialog box, on the Code Generation tab:
Set Function packaging to Nonreusable
function
or Reusable 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 inherit memory sections from
the model or, if applicable, a parent subsystem.
Use parameters such as Memory section for initialize/terminate functions to apply default memory sections to the subsystem functions and data.
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 not use a memory section:
In the target model, set Configuration Parameters > Code Generation > Advanced parameters > Memory Sections > Package to one of these values:
If the Embedded Coder Dictionary of the model does not refer to code
generation definitions in a package (see Refer to Code Generation Definitions in a Package), set
Package to Simulink
.
If the Embedded Coder Dictionary of the model refers to a package, set Package to that package.
In the target subsystem, on the Code Generation tab, set
parameters such as Memory section for initialize/terminate
functions to Default
. With this setting, the
subsystem does not use a memory section for the data or functions that each
parameter represents.
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 (Simulink Coder).
In the example Insert Pragmas by Using Memory Sections, to apply a memory section to individual signal data
items, you create a custom storage class by using the Custom Storage Class Designer. Suppose
you want to apply a different memory section to each of the signals. Instead of copying the
custom storage class (myCSC
) and associating a different memory section
with the copy, which results in two very similar custom storage classes, in the Custom
Storage Class Designer, for myCSC
, set Memory
section to Instance specific
. Then, when you apply
the custom storage class to a data item, you can choose a memory section for that data
item.
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
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.
This model shows how to insert pragmas for functions and data in generated code.
Explore Example Model
Open the example model.
open_system('rtwdemo_memsec')
Instructions
Learn about memory sections by clicking the documentation link in the model.
View the memory sections in the ECoderDemos package by clicking the button in the model and then selecting the Memory Sections tab.
View the memory sections selected for this model by clicking the button in the model. The model-level settings are also the default settings for atomic subsystems.
Open the SubSystem Parameters dialog for the subsystems to see the memory section settings for each of the atomic subsystems in the model.
Generate code by clicking the button in the model. A code generation report is displayed automatically. Inspect the data and function definitions in the .c
files and observe how the generated pragmas correspond to the specified memory sections.