Writing S-Functions | ![]() ![]() |
TLC S-Function Wrapper
This section describes how to inline the call to my_alg
in the mdlOutputs
section of the generated code. In the above example, the call to my_alg
is embedded in the mdlOutputs
section as
When you are creating a TLC S-function wrapper, the goal is to have the Real-Time Workshop embed the same type of call in the generated code.
It is instructive to look at how the Real-Time Workshop executes S-functions that are not inlined. A noninlined S-function is identified by the absence of the file sfunction
.tlc
and the existence of sfunction.
mex
. When generating code for a noninlined S-function, the Real-Time Workshop generates a call to mdlOutputs
through a function pointer that, in this example, then calls my_alg
.
The wrapper example contains one S-function, wrapsfcn.mex
. You must compile and link an additional module, my_alg
, with the generated code. To do this, specify
The code generated when using grt.tlc
as the system target file without wrapsfcn.tlc
is
<Generated code comments for wrapper model with noninlined wrapsfcn S-function> #include <math.h> #include <string.h> #include "wrapper.h" #include "wrapper.prm" /* Start the model */ void mdlStart(void) { /* (no start code required) */ } /* Compute block outputs */ void mdlOutputs(int_T tid) { /* Sin Block: <Root>/Sin */ rtB.Sin = rtP.Sin.Amplitude * sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase); /* Level2 S-Function Block: <Root>/S-Function (wrapsfcn) */{ SimStruct *rts = ssGetSFunction(rtS, 0); sfcnOutputs(rts, tid); } /* Outport Block: <Root>/Out */ rtY.Out = rtB.S_Function; } /* Perform model update */ void mdlUpdate(int_T tid) { /* (no update code required) */ } /* Terminate function */ void mdlTerminate(void) { /* Level2 S-Function Block: <Root>/S-Function (wrapsfcn) */
{ SimStruct *rts = ssGetSFunction(rtS, 0); sfcnTerminate(rts); } } #include "wrapper.reg" /* [EOF] wrapper.c */
In addition to the overhead outlined above, the wrapper.reg
generated file contains the initialization of the SimStruct
for the wrapper S-Function block. There is one child SimStruct
for each S-Function block in your model. You can significantly reduce this overhead by creating a TLC wrapper for the S-function.
How to Inline
The generated code makes the call to your S-function, wrapsfcn.c
, in mdlOutputs
by using this code:
This call has a significant amount of computational overhead associated with it. First, Simulink creates a SimStruct
data structure for the S-Function block. Second, the Real-Time Workshop constructs a call through a function pointer to execute mdlOutputs
, then mdlOutputs
calls my_alg
. By inlining the call to your C algorithm, my_alg
, you can eliminate both the SimStruct
and the extra function call, thereby improving the efficiency and reducing the size of the generated code.
Inlining a wrapper S-function requires an sfunction
.tlc
file for the S-function; this file must contain the function call to my_alg
. This picture shows the relationships between the algorithm, the wrapper S-function, and the sfunction
.tlc
file.
Figure 8-2: Inlining an Algorithm by Using a TLC File
To inline this call, you have to place your function call in an sfunction
.tlc
file with the same name as the S-function (in this example, wrapsfcn.tlc
). This causes the Target Language Compiler to override the default method of placing calls to your S-function in the generated code.
This is the wrapsfcn.tlc
file that inlines wrapsfcn.c
.
%% File : wrapsfcn.tlc %% Abstract: %% Example inlined tlc file for S-function wrapsfcn.c %% %implements "wrapsfcn" "C" %% Function: BlockTypeSetup ==================================================== %% Abstract: %% Create function prototype in model.h as: %% "extern real_T my_alg(real_T u);" %% %function BlockTypeSetup(block, system) void %openfile bufferextern real_T my_alg(real_T u); %closefile buffer %<LibCacheFunctionPrototype(buffer)> %endfunction %% BlockTypeSetup %% Function: Outputs =========================================================== %% Abstract: %% y = my_alg( u ); %% %function Outputs(block, system) Output /* %<Type> Block: %<Name> */ %assign u = LibBlockInputSignal(0, "", "", 0) %assign y = LibBlockOutputSignal(0, "", "", 0) %% PROVIDE THE CALLING STATEMENT FOR "algorithm"
%<y> = my_alg(%<u>); %endfunction %% Outputs
The first section of this code directs the Real-Time Workshop to inline the wrapsfcn
S-Function block and generate the code in C:
The next task is to tell the Real-Time Workshop that the routine my_alg
needs to be declared external in the generated wrapper.h
file for any wrapsfcn
S-Function blocks in the model. You only need to do this once for all wrapsfcn
S-Function blocks, so use the BlockTypeSetup
function. In this function, you tell the Target Language Compiler to create a buffer and cache the my_alg
as extern
in the wrapper.h
generated header file.
The final step is the inlining of the call to the function my_alg
. This is done by the Outputs
function. In this function, you load the input and output and place a direct call to my_alg
. The call is embedded in wrapper.c
.
![]() | MEX S-Function Wrapper | The Inlined Code | ![]() |