Integrate C Code Using C Caller Blocks
You can integrate new or existing C code into Simulink® using the C Caller block. To create custom blocks in your Simulink models, the C Caller block allows you to call external C functions specified in external source code and libraries. The advantages of the C Caller block are:
Automated integration of simple C functions including functions defined under namespace
Integration with Simulink Coverage™, Simulink Test™, and Simulink Design Verifier™
Integration with Simulink Coder™
The C Caller block and the C Function block allow you to bring C algorithms into Simulink. To model dynamic systems, use the S-Function Builder instead. Next steps describe the workflow to integrate C code into Simulink using the C Caller block.
Note
C99 is the standard version of C language supported for custom C code integration into Simulink.
Specify Source Code and Dependencies
Specify your external source code file that contains your C functions.
From Simulink toolstrip, open the Configuration Parameters.
In the left pane, select Simulation Target.
Select Include headers and enter the name of your header file with the
#include
tag.The directories and file paths can be absolute and relative file paths to model directories or to the current working directory. See Specify Relative Paths to Custom Code (Stateflow).
Tip
After you have entered information for Source files in the next step, you can click Auto-fill from source files to have the header file name filled in automatically, using information contained in your source files.
Select Source files and enter the path and the name of the source file. If the model and the source files are in different directories, enter the directory that contains the source file before the file name.
Select Include directories, and enter the folders where additional build information, such as header files, are stored.
To verify that your custom code can be parsed and built successfully, click Validate.
Note
If your header file declares a function but your source files do not define the function, by default the function is not visible in the C Caller block dialog. You can set the Undefined function handling parameter in Configuration Parameters to specify other behaviors in this situation, including throwing an error, generating a stub function, or ignoring the condition.
Note
To use a C Caller block in a For Each subsystem or with continuous sample time, or to optimize the use of the block in conditional input branch execution, the custom code function called by the block must be deterministic, that is, always producing the same outputs for the same inputs. Identify which custom code functions are deterministic by using the Deterministic functions and Specify by function parameters in the Simulation target pane. For a conditional input branch execution example, see Use C Caller Block with Conditional Execution.
N-D Array Handling
Simulink can pass N-D array data to custom code functions in C Caller blocks, and receive data from such blocks. When you do so, you must specify the correct array layout to achieve the intended results. See Default function array layout and Exception by function. For examples of the use of array data with C Caller blocks, see Use Custom Image Filter Algorithms as Reusable Blocks in Simulink and Call Legacy Lookup Table Function Using C Caller Block.
You can specify the order of how matrix data is handled in your C functions. Matrix data passed to and from your C functions is converted if necessary to the array layout you specify. If the array layout is not specified, the matrix data is passed through the C function in the same order of your Simulink data, and computational errors may occur due to row-column major disagreement. Ensure that you follow the same default function array layout for all Simulink data.
Column-Major — The C function handles input array data in column-major order. Suppose that you have a 3-by-3 matrix. In the C function, this matrix is accessed in this sequence: first column, second column, and third column.
Row-Major — The C function handles input array data in row-major order. Suppose that you have a 3-by-3 matrix. In the C function, this matrix is accessed in this sequence: first row, second row, and third row.
Any — The C function is indifferent to the layout of input array data. This would be the case if, for example, the function performs only element-wise operations on the data.
Not specified — The C function makes no assumption about the layout of input array data. Compared to the Any setting, you can generate code only in column-major setting. Attempting to generate code in row-major setting produces an error. See Array layout (Simulink Coder). Select this option only if needed for compatibility with older models.
To learn more about the row-major and column-major array layouts in Simulink, see Default function array layout.
Select an array layout option under Default function array layout.
If you need to apply a specific array layout to some of the functions in your code, click Exception by function to select these functions.
Click Apply to accept your changes.
If your C functions accept only scalar and/or vector inputs, the Default function array layout setting has no effect.
Call C Caller Block and Specify Ports
You can start your custom C code integration into Simulink by typing C Caller
in the Simulink canvas. Alternatively, drag a C Caller block from the
User-Defined Functions library onto the canvas. Double-click the block to open the Block
Parameters dialog box to see the names of your functions and port specifications.
Click on the Refresh button to import your source code and its dependencies.
Your C functions are displayed under Function Name. If you do not see your full list of functions, click on the to reimport your source code.
To view function definitions in the source file, click the . The source code for the selected function is displayed in the MATLAB® Editor. If the source code is not available, the function declaration in the header file is displayed.
To change source files and their dependencies, or to define and select function array layouts, click the custom code settings button to open the Simulation Target pane in Model Configuration Parameters.
Map C Function Arguments to Simulink Ports
You can map C function arguments from your source code to Simulink ports using the Port specification table in the C
Caller block or by creating a FunctionPortSpecification
object through the command line. In your source code,
the header file includes the C function arguments to be connected to Simulink
ports.
extern void mean_filter(const unsigned char* src, unsigned char* dst, unsigned int width, unsigned int height, unsigned int filterSize);
The Port specification table shows the details of your arguments and how they connect to your C Caller block in Simulink.
The table has these columns:
Name
Specifies the name of input and output arguments. Name is the function argument or parameter name as defined in your C functions from source code. This column is for reference purposes only.
Scope
Specifies how C function arguments map to the Simulink scope. Your arguments have default scopes depending on the function definition, and you can change the scopes depending your function definition in the source code.
Simulink Scope | Scope to Block Mapping |
---|---|
Input | Block input port |
Output | Block output port |
InputOutput | Block input and output port |
Global | Not applicable |
Parameter | Block tunable parameter |
Constant | Constant value |
For an argument passed by pointer, when the argument has a constant qualifier
definition such as const double *u
, the argument can only be an input
or a parameter. When there is no constant qualifier, the argument is an
InputOutput
by default, and you can change it to an
Input
, Output
, or Parameter
scope. In the case of an Input
or Parameter
scope,
ensure that the C function does not modify the memory pointed to by the pointer. If the
argument is of an Output
scope, every element pointed to by this
pointer should be reassigned in every call for the function.
C Argument | Simulink Scope |
---|---|
Function return |
|
| Input , Parameter ,
Constant |
| InputOutput (default),
Output , Input ,
Parameter |
|
|
Use the InputOutput
scope to map an input passed by a
pointer in your C functions. Ports created using an InputOutput
scope have the same name for input and output ports. The
InputOutput
scope enables reuse of buffer for input and
output ports. This may optimize the memory use depending on the signal size and the block
layout.
To map a C function argument to an InputOutput
scope,
define the variable as a pointer in your function.
extern void mean_filter(unsigned char* src, unsigned int width, unsigned int height, unsigned int filterSize);
Then set the scope to InputOutput
in the Port
Specification table and assign the resulting function output to the input
variable in the custom function.
You can use global variables in your custom code, mapping them to the appropriate
Simulink scope. To enable the use of global variables in your model, select Automatically infer global variables as function interfaces from Model Settings > Configuration Parameters > Simulation Target. You can map the global variables to an Input
,
Output
, InputOutput
or
Global
scope on the C Caller block. The
availability of these scopes depends on the use of the global variable in your custom
code.
A Global
scope enables you to transfer data between custom
code and the C Caller block and lets you use the global variable during
calculations on the block. Values transferred using Global
scope are not visible on the block interface. This table shows example code snippets and
their default and available ports.
Example Code | Simulink Scope |
---|---|
double data; void foo(void) { int temp = data; } | Global variable data only reads the variable
|
double data; void bar(void) { data = 0; } | Data is written to a global variable. Available scopes are:
|
double data; void foo2(void) { data = data + 1; } | Data is both read and written on a global variable. Available scopes are:
|
Label
Indicates the label for the corresponding argument in a Simulink block. By default, your argument label is the same as the argument name, unless you change it. Change the Scope to configure the options for the port labels.
Scope | Simulink Port Label |
---|---|
| Port name |
InputOutput | Port name in both input and output ports |
Global | Port name and global variable name |
| Parameter name |
| Expression for the constant value. size expressions using
input argument names, for example
|
Type
Specifies the data type of the argument. Data types in the C function must match equivalent data types in Simulink. This table shows the supported C data types you can use in the C Caller block, and the equivalent Simulink data types.
C Argument Data Type | Simulink Data Type |
---|---|
signed char /unsigned char | int8 /uint8 |
char | int8 or uint8 , depending on the
compiler |
int /unsigned
int * | int32 /uint32 |
short /unsigned
short * | int16 /uint16 |
long /unsigned
long * | int32 /uint32 or
int64 /uint64 , depending on the operating
system |
long long /unsigned long
long * | int64 /uint64 |
float | single |
double | double |
int8_t /uint8_t * | int8 /uint8 |
int16_t /uint16_t * | int16 /uint16 |
int32_t /uint32_t * | int32 /uint32 |
int64_t /uint64_t * | int64 /uint64 |
bool | boolean |
typedef struct {…}
AStruct ** | Bus: AStruct |
typedef enum {..}
AnEnum ** | Enum: AnEnum |
* If the C Caller takes an
integer type, for example, ** The C Caller sync button prompts you to import struct or enum types used by a C function as Simulink bus and enumeration types. |
Size
Specifies the data dimensions in the argument.
C Argument Dimensions | Simulink Port Dimensions |
---|---|
| scalar ( |
| inherited ( If the
argument is for an output port, its size must be specified and cannot be
inherited, unless the argument is mapped to an
|
| inherited ( If the
argument is for an output port, its size must be specified and cannot be
inherited, unless the argument is mapped to an
For global variables, size is
scalar ( |
| Size is |
Note
When using a pointer type as an output port, you must write to each element of the underlying buffer in your C function. For example, if you use a pointer to a five-by-six matrix as an output, you must write to all 30 elements. Otherwise, you may see unexpected values in the array.
Create a FunctionPortSpecification
Object and Edit C Caller Block Properties
To change Port Specification table properties programmatically,
you can create a FunctionPortSpecification
object and modify its properties. To create a
FunctionPortSpecification
object for a selected C Caller
block in a model, type in the command
line:
myCCallerConfigObj = get_param(gcb, 'FunctionPortSpecification')
myCCallerConfigObj = FunctionPortSpecification with properties: CPrototype: 'real_T add(real_T u1, real_T u2);' InputArguments: [1×2 Simulink.CustomCode.FunctionArgument] ReturnArgument: [1×1 Simulink.CustomCode.FunctionArgument] GlobalArguments: [1×0 Simulink.CustomCode.FunctionArgument]
CPrototype
property is read-only, and shows the declaration of C
function input variables. The InputArgument
and
ReturnArgument
properties create a FunctionArgument
object that you can further edit its properties according to the rules defined for
Port Specification table above. See FunctionPortSpecification
to learn more.To modify the global arguments in a C Caller block, create a handle to
the GlobalArguments
object using getGlobalArg
and modify its properties.
Create a Custom C Caller Library
It is recommended to create a library model to group your C Caller blocks and keep your models organized. You can also link a data dictionary to the library to hold custom types defined in your code. Using a library model is especially useful when you have multiple models or a model reference hierarchy that uses custom C code.
Open a new library model. On the Simulation tab, select New > Library.
On the Modeling tab, under Design, click Simulation Custom Code.
Select
C
orC++
in the Language option, depending on your code, and ensure the Import custom code box is selected.Follow the instructions in Specify Source Code and Dependencies to add your source files and their dependencies.
Create C Caller blocks to call C functions.
To insert a block from your library model to a Simulink model, simply drag the block into your model.
You can also create a library of C Caller blocks from your custom code using the Simulink Code Importer. See Create Block Library from C/C++ Code.
Debug Custom Code
You can debug your code from within Simulink by launching an external debugger and setting breakpoints in your custom code. For more information, see Debug Custom C/C++ Code.
Generate Code from Model
The C Caller supports code generation. In the code generated from your model, each execution of a C Caller block corresponds to a call to the external C function associated with the block. In order to build the generated code, the Code Generation > Custom Code pane of the Model Configuration Parameters must be populated with the correct information regarding the custom code. See Model Configuration Parameters: Code Generation Custom Code (Simulink Coder).
Limitations
Initialization/Termination of Custom Code Settings — If you need to allocate and deallocate memory for your custom code, insert allocate and deallocate in the Initialize function and Terminate function fields of custom code settings, or use a C Function block.
Complex Data Support — The C Caller block does not support complex data types in Simulink.
Variable Arguments — Variable arguments in C are not supported, for example,
int sprintf(char *str, const char *format, ...)
.C++ Syntax — The C Caller block does not support native C++ syntax directly. You need to write a C function wrapper to interface with C++ code.
To test models that include C Caller blocks, see Test Integrated C Code (Simulink Test).
Note
If a model has custom code, after the model is updated or run, the
slprj
folder may be locked due to the loaded custom code simulation
executable file. You cannot delete the folder when it is locked. To unload the executable
file and unlock the slprj
folder, use the clear mex
command. See clear
.