You can reuse the generated code for identical subsystems that occur in multiple instances within a model and across referenced models. For more information about code generation of subsystems for code reuse, see Control Generation of Functions for Subsystems.
To use S-function for code reuse for a subsystem, the S-function must meet these requirements:
The S-function must be inlined.
Code generated from the S-function must not use static variables.
The S-function must initialize its pointer work vector in only mdlStart
and not before.
The S-function must not be a sink that logs data to the workspace.
The S-function must register its parameters as run-time parameters in mdlSetWorkWidths
. For this purpose, the S-function must not use ssWriteRTWParameters
in its mdlRTW
function.
The S-function must not be a device driver.
Additionally, your S-function must set the SS_OPTION_WORKS_WITH_CODE_REUSE
flag in the ssSetOptions function. This flag indicates that your S-function meets the requirements for subsystem code reuse. If the flag is set and your S-function does not meet the requirements, the code generator does not generate a reusable function and you see a warning.
You can place S-functions inside reusable library subsystems. In the S-function file, set both of these flags:
SS_OPTION_WORKS_WITH_CODE_REUSE
flag in the ssSetOptions
function
ssSetSupportedForCodeReuseAcrossModels
set to 1
or true
If you use the legacy_code
tool to generate your S-function, the S-function option supportCodeReuseAcrossModels
specifies code reuse across models for the subsystem that contains the S-function.
Configure the S-function for code reuse across models only if the S-function does not access any model-specific data structures. This configuration is necessary because the generated code in _sharedutils
folder is compiled separately from the generated code in model_ert_rtw folder
. The reusable library subsystem code generated in the _sharedutils
folder does not have access to types and macros that are declared in model.h
. The reusable library subsystem code must be independent. For more information, see Generate Reusable Code from Library Subsystems Shared Across Models.
If your S-function uses custom functions defined in your external header files, add the LibAddtoSystemCustomIncludes(system, incFileName) function in your S-function's TLC file. For example, when you add LibAddtoSystemCustomIncludes("company_math.h")
in your .tlc
file, the reusable library subsystem code in the _sharedutils
folder includes the #company_math.h
header file.
1. Create a new MATLAB working folder. In the MATLAB Command Window, copy these external code files to your current MATLAB working folder:
currentDir = pwd; [~,cgDir] = rtwdemodir(); copyfile(fullfile(matlabroot,'toolbox','rtw','rtwdemos','doubleIt.c')); copyfile(fullfile(matlabroot,'toolbox','rtw','rtwdemos','doubleIt.h'));
2. Open example model rtwdemo_sfcn_rls
. This example model uses two instances of the reusable library subsystem rtwdemo_sfcn_rls_lib
. The S-function sfun_mySrc
inside the reusable library subsystem uses external files doubleIt.c
and doubleIt.h
.
rtwdemo_sfcn_rls;
3. Generate the S-function code by using legacy code tool. Use these commands in your MATLAB Command window:
def = legacy_code('initialize'); def.SFunctionName = 'sfun_mySrc'; def.SourceFiles = {'doubleIt.c'}; def.HeaderFiles = {'doubleIt.h'}; def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';
4. Specify the S-function for code reuse:
def.Options.supportCodeReuseAcrossModels = true;
5. Generate the S-function code TLC block file. Then compile the S-function.
legacy_code('sfcn_tlc_generate',def); legacy_code('sfcn_cmex_generate', def); legacy_code('compile', def);
### Start Compiling sfun_mySrc mex('-I/tmp/Bdoc21a_1631379_215288/tpe85d10cb_6bba_4da2_9442_02fb020c7e4c/coderdemo', '-c', '-outdir', '/tmp/Bdoc21a_1631379_215288/tp99e50c94_6215_4253_9690_4edcd6bc2601', '/tmp/Bdoc21a_1631379_215288/tpe85d10cb_6bba_4da2_9442_02fb020c7e4c/coderdemo/doubleIt.c') Building with 'gcc'. MEX completed successfully. mex('sfun_mySrc.c', '-I/tmp/Bdoc21a_1631379_215288/tpe85d10cb_6bba_4da2_9442_02fb020c7e4c/coderdemo', '/tmp/Bdoc21a_1631379_215288/tp99e50c94_6215_4253_9690_4edcd6bc2601/doubleIt.o') Building with 'gcc'. MEX completed successfully. ### Finish Compiling sfun_mySrc ### Exit
6. The code generator creates the S-function file sfun_mySrc.c
and its TLC file sfun_mySrc.tlc
in your MATLAB working folder. In the sfun_mySrc.c
file, the code generator adds these specifications:
file = fullfile('sfun_mySrc.c'); rtwdemodbtype(file,'* All options have the form SS_OPTION_<name>', ... 'ssSetSupportedForCodeReuseAcrossModels(S, 1);',1,1);
* All options have the form SS_OPTION_<name> and are documented in * matlabroot/simulink/include/simstruc.h. The options should be * bitwise or'd together as in * ssSetOptions(S, (SS_OPTION_name1 | SS_OPTION_name2)) */ ssSetOptions(S, SS_OPTION_USE_TLC_WITH_ACCELERATOR | SS_OPTION_CAN_BE_CALLED_CONDITIONALLY | SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_WORKS_WITH_CODE_REUSE | SS_OPTION_SFUNCTION_INLINED_FOR_RTW | SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME ); ssSetSupportedForCodeReuseAcrossModels(S, 1);
In the sfun_mySrc.c
, the SS_OPTION_WORKS_WITH_CODE_REUSE
flag is set in the ssSetOptions
function and ssSetSupportedForCodeReuseAcrossModels
is set to true.
7. On the Simulink toolstrip, open the Embedded Coder or Simulink Coder app.
8. Generate code for the model. On the C Code tab, click Build.
evalc('slbuild(''rtwdemo_sfcn_rls'')');
The code generator produces a reusable function that can be reused across models in the _sharedutils
folder. Models in a model reference hierarchy share this _sharedutils
folder to reuse code. For this example, the reusable function is generated in the slprj/grt/_sharedutils/sfunc.c
file:
file = fullfile('slprj','grt','_sharedutils','sfunc.c'); rtwdemodbtype(file,'Output and update for atomic system', ... 'rtb_sfun_mySrc',1,1);
* Output and update for atomic system: * 'ReusableSubsystem' ('rtwdemo_sfcn_rls_lib:60') * 'ReusableSubsystem' ('rtwdemo_sfcn_rls_lib:60') */ void sfunc(real_T rtu_In1, B_sfunc_T *localB, DW_sfunc_T *localDW) { /* local block i/o variables */ real_T rtb_sfun_mySrc;
By default, S-functions inside a subsystem are not configured for code reuse within a model. You can specify the S-functions inside a subsystem for code reuse within a model. In the S-function file, set the SS_OPTION_WORKS_WITH_CODE_REUSE
flag in the ssSetOptions
function. This flag indicates that your S-function meets the requirements for subsystem code reuse and is configured for code reuse. If the flag is set and your S-function does not meet the requirements, the code generator does not generate a reusable function and you see a warning.
1. Create a new MATLAB working folder and copy these external code files to your current MATLAB working folder:
currentDir = pwd; [~,cgDir] = rtwdemodir(); copyfile(fullfile(matlabroot,'toolbox','rtw','rtwdemos','doubleIt.c')); copyfile(fullfile(matlabroot,'toolbox','rtw','rtwdemos','doubleIt.h'));
2. For the example model rtwdemo_sfcn_rls
, generate the S-function code by using legacy code tool. Do not include the S-function option supportCodeReuseAcrossModels
. Use these commands in your MATLAB Command window:
def = legacy_code('initialize'); def.SFunctionName = 'sfun_mySrc'; def.SourceFiles = {'doubleIt.c'}; def.HeaderFiles = {'doubleIt.h'}; def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';
3. Generate the S-function code TLC block file. Then compile the S-function.
legacy_code('sfcn_tlc_generate',def); legacy_code('sfcn_cmex_generate', def); legacy_code('compile', def);
### Start Compiling sfun_mySrc mex('-I/tmp/Bdoc21a_1631379_215288/tpe3297e09_b054_44dd_b3f7_c497c753d70d/coderdemo', '-c', '-outdir', '/tmp/Bdoc21a_1631379_215288/tp10b90711_16a7_4de5_a7ca_591ef31e1682', '/tmp/Bdoc21a_1631379_215288/tpe3297e09_b054_44dd_b3f7_c497c753d70d/coderdemo/doubleIt.c') Building with 'gcc'. MEX completed successfully. mex('sfun_mySrc.c', '-I/tmp/Bdoc21a_1631379_215288/tpe3297e09_b054_44dd_b3f7_c497c753d70d/coderdemo', '/tmp/Bdoc21a_1631379_215288/tp10b90711_16a7_4de5_a7ca_591ef31e1682/doubleIt.o') Building with 'gcc'. MEX completed successfully. ### Finish Compiling sfun_mySrc ### Exit
4. The code generator creates the S-function file sfun_mySrc.c
and its TLC file sfun_mySrc.tlc
in your MATLAB working folder.
file = fullfile('sfun_mySrc.c'); rtwdemodbtype(file,'* All options have the form SS_OPTION_<name>', ... 'SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME',1,1);
* All options have the form SS_OPTION_<name> and are documented in * matlabroot/simulink/include/simstruc.h. The options should be * bitwise or'd together as in * ssSetOptions(S, (SS_OPTION_name1 | SS_OPTION_name2)) */ ssSetOptions(S, SS_OPTION_USE_TLC_WITH_ACCELERATOR | SS_OPTION_CAN_BE_CALLED_CONDITIONALLY | SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_WORKS_WITH_CODE_REUSE | SS_OPTION_SFUNCTION_INLINED_FOR_RTW | SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME
In the sfun_mySrc.c
file, the code generator adds SS_OPTION_WORKS_WITH_CODE_REUSE
flag in the ssSetOptions
function by default but does not include the ssSetSupportedForCodeReuseAcrossModels
specification that prevents the S-function from being reused across models.
5. On the Simulink toolstrip, open the Embedded Coder or Simulink Coder app.
6. Generate code for the model. On the C Code tab, click Build.
evalc('slbuild(''rtwdemo_sfcn_rls'')');
The code generator produces a reusable function for the subsystem in the rtwdemo_sfcn_rls.c
file, which is outside the _sharedutils
folder. This code can be reused within the model but not across the model reference hierarchy:
file = fullfile('rtwdemo_sfcn_rls_grt_rtw','rtwdemo_sfcn_rls.c'); rtwdemodbtype(file,'void sfunc', ... 'localDW->UnitDelay_DSTATE = rtb_sfun_mySrc;',1,1);
void sfunc_Init(DW_sfunc_T *localDW) { /* InitializeConditions for UnitDelay: '<S1>/Unit Delay' */ localDW->UnitDelay_DSTATE = 0.0; } /* * Output and update for atomic system: * '<Root>/ReusableSubsystem1' * '<Root>/ReusableSubsystem2' */ void sfunc(real_T rtu_In1, B_sfunc_T *localB, DW_sfunc_T *localDW) { /* local block i/o variables */ real_T rtb_sfun_mySrc; /* UnitDelay: '<S1>/Unit Delay' */ localB->UnitDelay = localDW->UnitDelay_DSTATE; /* S-Function (sfun_mySrc): '<S1>/sfun_mySrc' */ rtb_sfun_mySrc = doubleIt(rtu_In1); /* Update for UnitDelay: '<S1>/Unit Delay' */ localDW->UnitDelay_DSTATE = rtb_sfun_mySrc;