External C Functions
This example shows several methods for integrating legacy C functions into generated code. These methods create an S-function or make a call to an external C function. For more information on S-functions, see S-Functions and Code Generation.
C Construct
extern double add(double, double); #include "add.h" double add(double u1, double u2) { double y1; y1 = u1 + u2; return (y1); }
Create S-Functions by Using Legacy Code Tool
Use the Legacy Code Tool to create an S-function and generate a TLC file. The code generation software uses the TLC file to generate code from this S-function. The advantage to using the Legacy Code Tool is that the generated code is fully inlined and does not need wrapper functions to access the custom code.
1. Create a C header file named add.h
that contains the function signature:
extern double add(double, double);
2. Create a C source file named add.c
that contains the function body:
double add(double u1, double u2) { double y1; y1 = u1 + u2; return (y1); }
3. To build an S-function for use in simulation and code generation, run the following script or execute each of these commands at the MATLAB® command line:
%% Initialize legacy code tool data structure def = legacy_code('initialize'); %% Specify Source File def.SourceFiles = {'add.c'}; %% Specify Header File def.HeaderFiles = {'add.h'}; %% Specify the Name of the generated S-function def.SFunctionName = 'add_function'; %% Create a c-mex file for S-function legacy_code('sfcn_cmex_generate', def); %% Define function signature and target the Output method def.OutputFcnSpec = ['double y1 = add(double u1, double u2)']; %% Compile/Mex and generate a block that can be used in simulation legacy_code('generate_for_sim', def); %% Create a TLC file for Code Generation legacy_code('sfcn_tlc_generate', def); %% Create a Masked S-function Block legacy_code('slblock_generate', def);
### Start Compiling add_function mex('-I/tmp/Bdoc24b_2679053_1944251/tp3f3037fc/ecoder-ex61094511', '-c', '-outdir', '/tmp/Bdoc24b_2679053_1944251/tpbd0f48d7_162a_4dca_bdaa_17b8e1dda6b6', '/tmp/Bdoc24b_2679053_1944251/tp3f3037fc/ecoder-ex61094511/add.c') Building with 'gcc'. MEX completed successfully. mex('add_function.c', '-I/tmp/Bdoc24b_2679053_1944251/tp3f3037fc/ecoder-ex61094511', '/tmp/Bdoc24b_2679053_1944251/tpbd0f48d7_162a_4dca_bdaa_17b8e1dda6b6/add.o') Building with 'gcc'. MEX completed successfully. ### Finish Compiling add_function ### Exit
The output of this script produces:
A new model containing the S-function block.
A TLC file named
add_function.tlc
.A C source file named
add_function.c
.A mexw32 dll file named
add_function.mexw32
.
4. Add inport blocks and an outport block and make the connections, as shown in the model.
5. Name and save your model. In this example, the model is named ex_function_call_lct
.
6. To build the model and generate code, press Ctrl+B.
This code is generated in ex_function_call_lct.c
:
/* Exported block signals */ real_T u1; /* '<Root>/u1' */ real_T u2; /* '<Root>/u2' */ /* External outputs (root outports fed by signals with default storage) */ ExternalOutputs rtY; /* Model step function */ void ex_function_call_lct_step(void) { /* Outport: '<Root>/y1' incorporates: * Inport: '<Root>/u1' * Inport: '<Root>/u2' * S-Function (add_function): '<Root>/add_function' */ rtY.y1 = add(u1, u2); }
The user-specified header file add.h
is included in ex_function_call_lct.h
:
#include "add.h"
Call C Functions by Using a Stateflow Chart
1. Create a C header file named add.h
that contains the example function signature. Refer to the preceding example.
2. Create a C source file named add.c
that contains the function body. Refer to the preceding example.
3. Add inport blocks and an outport block and make the connections, as shown in the model. In this example, the model is named ex_function_call_SF
.
4. Double-click the Stateflow® chart and edit the chart as shown. Place the call to the add
function within a transition action.
5. Select the Configuration Parameters > Code Generation > Custom Code pane. On the Code information tab, select Include headers. In the Include headers field, enter the #include
statement:
#include "add.h"
6. Select Source files. In the Source files field, enter:
add.c
7. Select the Configuration Parameters > Code Generation > Custom Code > Use the same custom code settings as Simulation Target parameter.
8. To build the model and generate code, press Ctrl+B.
ex_exfunction_call_SF.c
contains the following code in the step function:
/* Definition for custom storage class: Global */ real_T u1; /* '<Root>/u1' */ real_T u2; /* '<Root>/u2' */ real_T y1; /* '<Root>/Chart' */ /* Model step function */ void ex_function_call_SF_step(void) { /* Chart: '<Root>/Chart' incorporates: * Inport: '<Root>/u1' * Inport: '<Root>/u2' */ y1 = (real_T)add(u1, u2); }
ex_exfunction_call_SF.h
contains the include statement for add.h
:
#include "add.h"
Use MATLAB Function Block to Call C Functions
1. Create a C header file named add.h
that contains the example function signature. Refer to the preceding example.
2. Create a C source file named add.c
that contains the function body. Refer to the preceding example.
3. In the Simulink Library Browser, click Simulink > User Defined Functions. Drag a MATLAB Function block into your model.
4. Double-click the MATLAB Function block. Edit the function to include:
function y1 = add_function(u1, u2) % Set the class and size of output y1 = u1; % Call external C function y1 = coder.ceval('add',u1,u2); end
5. Select the Configuration Parameters > Code Generation > Custom Code pane. On the Code information tab, select Include headers. In the Include headers field, enter the #include
statement:
#include "add.h"
6. In the Code information tab, select Source files. In the Source files field, enter:
add.c
7. Add two Inport blocks and one Outport block to the model and connect it to the MATLAB Function block.
8. Save the model as ex_function_call_ML
.
9. To build the model and generate code, press Ctrl+B.
ex_exfunction_call_ML.c
contains the following code in the step function:
/* Definition for custom storage class: Global */ real_T u1; /* '<Root>/u1' */ real_T u2; /* '<Root>/u2' */ real_T y1; /* '<Root>/MATLAB Function' */ /* Model step function */ void ex_function_call_ML_step(void) { /* MATLAB Function: '<Root>/MATLAB Function' incorporates: * Inport: '<Root>/u1' * Inport: '<Root>/u2' */ y1 = add(u1, u2); }
ex_exfunction_call_ML.h
contains the include statement for add.h
:
#include "add.h"