Configure Code Interface Packaging and Root-Level I/O Data for Model References
This example shows how to configure the function interface of model references using model configuration parameters. Depending on the number of instances of each model reference in your top model, you can configure the code generator to generate reusable or nonreusable code.
You can configure nonreusable model reference entry-point functions to receive root-level I/O data as individual arguments or as global variables. Passing root-level I/O data as global variables eliminates function arguments, simplifying the code and reducing stack memory usage.
For model references employing a service interface defined in an Embedded Coder Dictionary, you can similarly generate code that is reusable, or nonreusable by passing root-level I/O data as individual arguments or global variables.
Explore Example Model
Run the script prepare_sldemo_fuelsys_dd_ctrl_voidvoid.m
. The script opens the model sldemo_fuelsys_dd_controller
and prepares it for this example. It converts the existing subsystems into the model references airflow_calc
and fuel_calc
. One instance of each model reference appears in the top model.
prepare_sldemo_fuelsys_dd_ctrl_voidvoid
model = 'sldemo_fuelsys_dd_controller';
open_system(model)
Each model reference interfaces with a set of root-level I/O signals:
airflow_calc
acceptssensors
,O2_normal
, andfuel_mode
as inputs, and outputsest_airflow
andfb_correction
.fuel_calc
acceptsest_airflow
,fb_correction
, andfuel_mode
as inputs, and outputsfuel_rate
.
Depending on your configuration settings, the code generator passes root-level I/O data as either individual arguments or global variables to the entry-point functions of each model reference.
Generate Reusable Code for Model Reference
1. Open the airflow_calc
model.
open_system('airflow_calc')
2. Open the Configuration Parameters dialog box. In the Model Referencing pane, verify that the Total number of instances allowed per top model parameter is set to Multiple
.
3. In the Interface pane, in the Subcomponent section, verify that Code interface packaging is set to Reusable function
. By default, the code generator is configured to generate reusable code for model references. This setting is consistent with the current setting for Total number of instances allowed per top model.
4. Build the top model.
evalc('slbuild(model)');
5. Inspect the generated code for the model airflow_calc
. In airflow_calc.c
, the step function airflow_calc
is configured as a reusable function that passes root-level I/O data and other data such as the real-time model data structure as individual arguments.
file = fullfile('slprj','ert','airflow_calc','airflow_calc.c'); coder.example.extractLines(file,"/* Output and update for referenced model: 'airflow_calc' */",... '{',0,0)
void airflow_calc(const EngSensors *rtu_sensors, const boolean_T *rtu_O2_normal, const sldemo_FuelModes *rtu_fuel_mode, real32_T *rty_est_airflow, real32_T *rty_fb_correction, airflow_calc_rtDW *localDW)
Generate Nonreusable Code Passing Root-Level I/O Data as Individual Arguments
If your top model contains only a single instance of a model reference, you can configure the entry-point functions of that model reference to be nonreusable. A nonreusable function receives non-root-level I/O data such as block I/O signals, block states, and the real-time model data structure as global variables, reducing the number of arguments passed to it. Nonetheless, you can pass root-level I/O data to the nonreusable function as individual arguments.
1. In the airflow_calc
model, open the Configuration Parameters dialog box. In the Model Referencing pane, set the Total number of instances allowed per top model parameter to One
.
set_param('airflow_calc',ModelReferenceNumInstancesAllowed='Single');
2. In the Interface pane, in the Subcomponent section, verify that Code interface packaging is set to Nonreusable function
.
get_param('airflow_calc','SubcomponentCodeInterfacePackaging')
ans = 'Nonreusable function'
3. To pass root-level I/O data to model reference entry-point functions as function arguments, in the Subcomponent section, set Implement root-level I/O as to Individual arguments
.
set_param('airflow_calc',SubcomponentRootIOFormat='Individual arguments');
4. Save airflow_calc
and build the top model.
save_system('airflow_calc') evalc('slbuild(model)');
5. Inspect the generated code for the model reference airflow_calc
. In airflow_calc.c
, the step function airflow_calc
passes root-level I/O data as individual arguments.
file = fullfile('slprj','ert','airflow_calc','airflow_calc.c'); coder.example.extractLines(file,"/* Output and update for referenced model: 'airflow_calc' */",... '{',0,0)
void airflow_calc(const EngSensors *rtu_sensors, const boolean_T *rtu_O2_normal, const sldemo_FuelModes *rtu_fuel_mode, real32_T *rty_est_airflow, real32_T *rty_fb_correction)
Generate Nonreusable Code Passing Root-Level I/O Data as Global Variables
1. To pass root-level I/O data to model reference entry-point functions as global variables (that is, to create a void
-void
interface), in the Subcomponent section, set Implement root-level I/O as to Global variables
.
set_param('airflow_calc',SubcomponentRootIOFormat='Global variables');
2. Save airflow_calc
and build the top model.
save_system('airflow_calc') evalc('slbuild(model)');
3. Inspect the generated code for airflow_calc
. In airflow_calc.c
, the prototype for the step function airflow_calc
is void
-void
.
file = fullfile('slprj','ert','airflow_calc','airflow_calc.c'); coder.example.extractLines(file,"/* Output and update for referenced model: 'airflow_calc' */",... '{',0,0)
void airflow_calc(void)
The top model source file sldemo_fuelsys_dd_controller.c
defines the global variables carrying root-level I/O data to airflow_calc
.
file = fullfile('sldemo_fuelsys_dd_controller_ert_rtw','sldemo_fuelsys_dd_controller.c'); coder.example.extractLines(file,"/* Subcomponent root-level I/O */", ... '/* Real-time model */',1,0)
/* Subcomponent root-level I/O */ EngSensors es_o; /* '<Root>/control_logic' */ real32_T est_airflow; /* '<Root>/airflow_calc' */ real32_T fb_correction; /* '<Root>/airflow_calc' */ sldemo_FuelModes fuel_mode; /* '<Root>/control_logic' */ boolean_T O2_normal; /* '<Root>/control_logic' */
4. Apply the same settings to model reference fuel_calc
, and then build the top model.
open_system('fuel_calc') set_param('fuel_calc',ModelReferenceNumInstancesAllowed='Single'); set_param('fuel_calc',SubcomponentRootIOFormat='Global variables'); save_system('fuel_calc') evalc('slbuild(model)');
5. Inspect the generated code for fuel_calc
. In fuel_calc.c
, the prototype for the step function fuel_calc
is void
-void
.
file = fullfile('slprj','ert','fuel_calc','fuel_calc.c'); coder.example.extractLines(file,"/* Output and update for referenced model: 'fuel_calc' */",... '{',0,0)
void fuel_calc(void)
The top model source file sldemo_fuelsys_dd_controller.c
now defines global variables carrying root-level I/O data to both model references.
file = fullfile('sldemo_fuelsys_dd_controller_ert_rtw','sldemo_fuelsys_dd_controller.c'); coder.example.extractLines(file,"/* Subcomponent root-level I/O */", ... '/* Real-time model */',1,0)
/* Subcomponent root-level I/O */ EngSensors es_o; /* '<Root>/control_logic' */ real32_T est_airflow; /* '<Root>/airflow_calc' */ real32_T fb_correction; /* '<Root>/airflow_calc' */ real32_T fuel_rate; /* '<Root>/fuel_calc' */ sldemo_FuelModes fuel_mode; /* '<Root>/control_logic' */ boolean_T O2_normal; /* '<Root>/control_logic' */
Generate Nonreusable Code Passing Root-Level I/O Data as Global Variables for Service Interface
1. The Embedded Coder Dictionary in sldemo_fuelsys_dd_controller_service.sldd
is configured to use a service interface. Apply this configuration to the top model and its model references. For information about configuring service interfaces, see Create a Service Interface Configuration.
set_param(model,EmbeddedCoderDictionary="sldemo_fuelsys_dd_controller_service.sldd"); set_param('airflow_calc',EmbeddedCoderDictionary="sldemo_fuelsys_dd_controller_service.sldd"); set_param('fuel_calc',EmbeddedCoderDictionary="sldemo_fuelsys_dd_controller_service.sldd"); save_system(model,SaveDirtyReferencedModels='on');
2. Both model references are previously configured to generate a void
-void
interface. Clear model cache files and the slprj
directory, then build the top model.
delete *.slxc rmdir slprj s evalc('slbuild(model)');
3. Inspect the generated code for either model reference. For instance, in airflow_calc.c
, the prototype for the step function airflow_calc_step
is void
-void
.
file = fullfile('slprj','ert','airflow_calc','airflow_calc.c'); coder.example.extractLines(file,"/* Output and update for referenced model: 'airflow_calc' */",... '{',0,0)
void airflow_calc_step(void)
Additional Considerations
You cannot pass root-level I/O data as global variables to a model reference if you perform any of the following:
Customize the function prototype of the model reference
model_step
function using the Code Mappings Editor.Assign a storage class other than
Auto
to root-level I/O ports and signals that connect directly to the model reference.Configure the top model with a service interface or AUTOSAR target and connect root-level I/O ports directly to the model reference.
Passing root-level I/O data as global variables does not generate a void
-void
interface for a model reference if you configure parameter data to pass to the model reference as arguments. See Specify Instance-Specific Parameter Values for Reusable Referenced Model.