S-Functions for Code Reuse
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 Generate Subsystem Code as Separate Function and Files.
S-Function Code Reuse Requirements
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 usessWriteRTWParameters
in itsmdlRTW
function.The S-function must not be a device driver.
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.
S-Functions Reused Across Models
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 thessSetOptions
functionssSetSupportedForCodeReuseAcrossModels
set to1
ortrue
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. Open example model SFunctionForCodeReuse
. This example model uses two instances of the reusable library subsystem SFunctionForCodeReuseLibrary
. The S-function sfun_mySrc
inside the reusable library subsystem uses external files doubleIt.c
and doubleIt.h
.
SFunctionForCodeReuse;
2. 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)';
3. Specify the S-function for code reuse:
def.Options.supportCodeReuseAcrossModels = true;
4. 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/Bdoc24b_2725827_4048607/tpbfd3953d/simulinkcoder-ex43633418', '-c', '-outdir', '/tmp/Bdoc24b_2725827_4048607/tp5059f8b4_aa85_4904_85d4_39d497b5886d', '/tmp/Bdoc24b_2725827_4048607/tpbfd3953d/simulinkcoder-ex43633418/doubleIt.c') Building with 'gcc'. MEX completed successfully. mex('sfun_mySrc.c', '-I/tmp/Bdoc24b_2725827_4048607/tpbfd3953d/simulinkcoder-ex43633418', '/tmp/Bdoc24b_2725827_4048607/tp5059f8b4_aa85_4904_85d4_39d497b5886d/doubleIt.o') Building with 'gcc'. MEX completed successfully. ### Finish Compiling sfun_mySrc ### Exit
5. 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'); coder.example.extractLines(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.
6. On the Simulink® toolstrip, open the Embedded Coder or Simulink Coder app.
7. Generate code for the model. On the C Code tab, click Build.
evalc('slbuild(''SFunctionForCodeReuse'')');
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'); coder.example.extractLines(file,'Output and update for atomic system', ... 'rtb_sfun_mySrc',1,1); %
/* Output and update for atomic system: 'ReusableSubsystem' ('SFunctionForCodeReuseLibrary: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;
S-Functions Reused Within a Model
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. For the example model SFunctionForCodeReuse
, 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)';
2. 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/Bdoc24b_2725827_4048607/tpbfd3953d/simulinkcoder-ex69241103', '-c', '-outdir', '/tmp/Bdoc24b_2725827_4048607/tp462048d6_8f15_42e0_b8a5_a4cbe71100f9', '/tmp/Bdoc24b_2725827_4048607/tpbfd3953d/simulinkcoder-ex69241103/doubleIt.c') Building with 'gcc'. MEX completed successfully. mex('sfun_mySrc.c', '-I/tmp/Bdoc24b_2725827_4048607/tpbfd3953d/simulinkcoder-ex69241103', '/tmp/Bdoc24b_2725827_4048607/tp462048d6_8f15_42e0_b8a5_a4cbe71100f9/doubleIt.o') Building with 'gcc'. MEX completed successfully. ### Finish Compiling sfun_mySrc ### Exit
3. 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'); coder.example.extractLines(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.
4. On the Simulink toolstrip, open the Embedded Coder or Simulink Coder app.
5. Generate code for the model. On the C Code tab, click Build.
evalc('slbuild(''SFunctionForCodeReuse'')');
The code generator produces a reusable function for the subsystem in the SFunctionForCodeReuse.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('SFunctionForCodeReuse_grt_rtw','SFunctionForCodeReuse.c'); coder.example.extractLines(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>/ReusableSubsystem' * '<Root>/ReusableSubsystem1' */ 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;