You can call and integrate your external C code into Simulink® models using C Function blocks. C Function blocks allow you to call external C code and customize the integration of your code using the Output Code, Start Code and Terminate Code panes in the block parameters dialog. Use C Function block to:
Call functions from external C code, and customize the code for your Simulink models.
Preprocess data to call a C function and postprocess data after calling the function.
Specify different code for simulation and code generation.
Call multiple functions.
Initialize and work with persistent data cached in the block.
Allocate and deallocate memory.
Use the C Function block to call external C algorithms into Simulink that you want to modify. To call a single C function from a Simulink model, use the C Caller block. To integrate dynamic systems that have continuous states or state changes, use the S-Function block.
The following examples use C Function blocks to calculate the sum and mean of inputs.
Begin by creating the external source files.
Create a header file named
data_array.h
.
/* Define a struct called DataArray */ typedef struct DataArray_tag { /* Define a pointer called pData */ double* pData; /* Define the variable length */ int length; } DataArray; /* Function declaration */ double data_sum(DataArray data);
In the same folder, create a new file, data_array.c
. In this
file, write a C function that calculates the sum of input
numbers.
#include "data_array.h" /* Define a function that takes in a struct */ double data_sum(DataArray data) { /* Define 2 local variables to use in the function */ double sum = 0.0; int i; /* Calculate the sum of values */ for (i = 0; i < data.length; i++) { sum = sum + data.pData[i]; } /* Return the result to the block */ return sum; }
In a new, blank model, add a C Function block. The C Function block is in the User-Defined Functions library of the Library Browser.
Double-click the C Function block to open the block dialog. Click to open the Configuration
Parameters dialog. In the Simulation Target
pane, define your header file under Insert custom C code in generated: > Header file.
Define the source file under Additional build information > Source files.
Click OK to close the Configuration Parameters.
In the Output Code pane of the C Function block
parameters dialog, write the code that the block executes during simulation. In this
example, the external C function computes a sum. In the Output Code
pane, write code that calls the data_array.c
function to compute the
sum, then computes the mean.
/* declare the struct dataArr */ DataArray dataArr; /* store the length and data coming in from the input port */ dataArr.pData = &data; dataArr.length = length; /* call the function from the external code to calculate sum */ sum = data_sum(dataArr); /* calculate the mean */ mean = sum / length;
You can specify code that runs at the start of a simulation and at the end of a simulation in the Start Code and Terminate Code panes.
Use the Symbols table to define the symbols used in the external C code. Add or delete a symbol using the Add and Delete buttons. Define all symbols used in the Output Code, Start Code, and Terminate Code panes to ensure that ports display correctly.
In the Symbols table, define the following.
Name — Symbol name in the source code.
Scope — Scope of the symbols and the order in which they appear. You can change the scope of a symbol at any time.
Input
— Input symbol to the C Function
block.
Output
— Output symbol to the C
Function block.
InputOutput
— Define a symbol as both input and
output to the C Function block.
Use the InputOutput
scope to map an input
passed by a pointer in your C code. Ports created using an
InputOutput
scope have the same name for input
and output ports. InputOutput
scope enables the
reuse of buffer for input and output ports. Reusing buffer may optimize
memory use and improve code simulation and code generation efficiency,
depending on the signal size and the block layout. Limitations
include:
InputOutput
symbol cannot be used in
Start
and Terminate
code.
InputOutput
port does not support
void*
data type.
InputOutput
port does not support
size()
expressions.
Persistent
— Define a symbol as persistent
data.
You can define a void pointer using the Persistent
scope in the C Function block. A void
pointer is a pointer that can store any type of data that you
created or allocated.
Constant
— Define a symbol as constant using
value-size or numeric expressions.
Parameter
— Define a symbol as parameter. The
parameter name is defined by the Label of the
symbol.
Label — Label of the symbol. For symbols with
their scope set to Input
or
Output
, this label appears as the port name on the
block. For symbols with their scope set to Parameter
,
this label is the label that appears on the block parameter mask. You cannot
define a label for Persistent
symbols. If the scope is
Constant
, the label is the constant
expression.
Type — Data type of the symbol. Select a data type from the drop-down list or specify custom data type.
To use a custom type such as Simulink.Bus
, Simulink Enum or Simulink.AliasType
that does not have an external header
definition associated with a C Function block, set the type
correctly on the Symbol table.
Size — Size of the symbol data. The C
Function block supports only scalars and vectors are supported. Matrices
and higher-dimension arrays are not supported. You can use a size expression to
define the size of an output. Use -1
to inherit size.
Port — For input and output symbols,
Port
indicates the port index on the block of the symbol
data. For parameter symbols, Port
indicates the order that the
symbol appears in the block parameter mask.
Close the block parameters dialog. After filling in the data in the table, the C Function block now has one input port, and two output ports with the labels specified in the table.
Add a Constant block to the Simulink canvas that will be the input to the C Function block. In the Constant block, create a random row array with 100 elements. To display the results, attach display blocks to the outputs of the C Function block.
You can call this subset of the C Math Library functions from the C Function block:
abs | acos | asin | atan | atan2 | ceil |
cos | cosh | exp | fabs | floor | fmod |
labs | ldexp | log | log10 | pow | sin |
sinh | sqrt | tan | tanh |
When you call these functions, double precision applies unless all the input arguments
are explicitly single precision. When a type mismatch occurs, a cast of the input arguments
to the expected type replaces the original arguments. For example, if you call the
sin
function with an integer argument, a cast of the input argument to
a floating-point number of type double
replaces the original
argument.
If you want to call other C library functions that are not listed above, create an external wrapper function that calls the C library function.
abs
, fabs
, and labs
FunctionInterpretation of the abs
, fabs
, and
labs
functions in C Function block goes beyond the
standard C version to include integer and floating-point arguments:
If x
is an integer, the standard C function applies to
x
, or abs(x)
.
If x
is a double, the standard C function
labs
applies to x
, or
labs(x)
.
If x
is a single, the standard C function
fabs
applies to x
, or
fabs(x)
.
The call to the function should call the correct CRL based on the type of data passed into the function. If no CRL is specified, the call to the function should call to type-specific library. The CRL for C99 generates a type-specific function. For example:
Type passed in | Code generation call |
---|---|
sin(doubleIn) | sin(doubleIn) |
sin(floatIn) | sinf(floatIn) |
You can specify different output code for simulation and code generation for the
C Function block by defining MATLAB_MEX_FILE
. For
example, to specify code that only runs during the model simulation, you use the following.
#ifdef MATLAB_MEX_FILE /* Enter Sim Code */ #else /* Enter code generation code */ #endif