Main Content

Call and Integrate External C Algorithms into Simulink Using C Function Blocks

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.

Note

C99 is the standard version of C language supported for custom C code integration into Simulink.

The following examples use C Function blocks to calculate the sum and mean of inputs.

Write External Source Files

Begin by creating the external source files.

  1. 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);

  2. 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;
    }

Enter the External Code Into Simulink

  1. Create a new, blank model and add a C Function block. The C Function block is in the User-Defined Functions library of the Library Browser.

  2. 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 Header file.

    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.

  3. Define the source file under Additional build information > Source files. To verify that your custom code can be parsed and built successfully, click Validate.

    Note

    To use a C Function block in a For Each subsystem or with continuous sample time, or to optimize the use of the block in conditional input branch execution, all custom code functions 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. If the block references any custom code global variables, then Deterministic functions must set to All in order for the block to be used in a For Each subsystem, in conditional input branch execution, or with continuous sample time.

    For an example showing a C Function block in a For Each subsystem, see Use C Function Block Within For Each Subsystem.

  4. 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[0];
    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.

  5. 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. 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.

  6. 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.

Call C Library Functions From C Function Block

You can call this subset of the C Math Library functions from the C Function block:

absacosasinatanatan2ceil
coscoshexpfabsfloorfmod
labsldexploglog10powsin
sinhsqrttantanh  

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.

Call the abs, fabs, and labs Functions

Interpretation 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 abs 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).

Code Replacement Library (CRL) Based on Type

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 inCode generation call
sin(doubleIn)sin(doubleIn)
sin(floatIn)sinf(floatIn)

Specify Simulation or Code Generation Code

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, use the following.

#ifdef MATLAB_MEX_FILE
/* Enter Sim Code */
#else 
/* Enter code generation code */
#endif

Specify Declaration for Target-Specific Function for Code Generation

For code generation purposes, if you do not have the external header file with the declaration of a function (such as a target-specific device driver) that you want to call from the C Function block, you can include a declaration with the correct signature in the Output Code pane of the block. This action creates a function call to the expected function when code is generated, as in the following example:

#ifndef MATLAB_MEX_FILE
extern void driverFcnCall(int16_T in, int16_T * out);
driverFcnCall(blockIn, &blockOut);
#endif

Simulate Custom Code in a Separate Process

When simulating a model containing custom C or C++ code, you have the option to run the custom code in a separate process outside of MATLAB®. This option may be useful when debugging your custom code. By running in a separate process, problems with the custom code do not cause MATLAB to crash, and you can more easily debug and resolve such problems. Problems could arise due to unexpected exceptions in the custom code or errors in the interface between Simulink and the custom code. For more information, see Simulate Custom Code in a Separate Process.

See Also

Functions

Objects

Blocks