When to use:
When to use:
__delay_ms(), __builtin_dmaoffset(), etc.)When NOT to use:
The MCHP_C_function_Call block enables integration of custom C functions into Simulink models with automatic code generation for Microchip targets. It provides a bridge between Simulink visual programming and custom C code.
Key Features:
__delay_ms(), __builtin_dmaoffset()

| Parameter | Variable | Description |
|---|---|---|
| Parse user file to list functions | ParseFilesChkbx | When enabled, scans user C files and populates function list dropdown |
| Functions found | ListFunctions1 | Dropdown populated with parsed functions or “Custom Function” for manual entry |
| Function Declaration | Function1 | C function signature (e.g., extern void my_func(int x);) |
| Add this function declaration in header file | AddHeaderDeclaration | When enabled, adds declaration to generated header |
| Execute function | Function1Type | when block is updated (default): Called every sample time only once at power-up time: Called once during initialization |
| Block Input (comma separated function parameters) | Fct1BlockIn | Comma-separated list of parameters passed from Simulink input ports |
| Function returned value is a block output | FctReturnBlockOut | When enabled, function return value becomes a Simulink output port |
| Block Output (comma separated function parameters) | Fct1BlockOut | Comma-separated list of parameters passed by pointer/reference for outputs |
| Block execution ordering | ORDERING | None: Default Simulink ordering Input: Force execution after input dependencies Output: Force execution before outputs consumed Input & Output: Explicit ordering control |
| Sample Time | SampleTime | Block sample time (-1 for inherited) |
| Parameter | Variable | Description | Format |
|---|---|---|---|
| List of port used as Digital Input | PinDigitalInput | GPIO pins configured as digital inputs | e.g., A[1 2] B12 |
| List of port used as Digital Output | PinDigitalOutput | GPIO pins configured as digital outputs | e.g., A[1 2] B12 |
| List of port used as Analog Input | PinAnalogInput | GPIO pins configured as analog inputs | e.g., A[1 2] B12 |
Note: Pin configuration automatically generates TRIS and ANSEL register initialization code.
Symptom: Linker error undefined reference to 'my_function'
Causes:
Solution:
Symptom: Function receives unexpected values or garbage data
Causes:
Solution:
param1, param2, param3 (spaces optional)Symptom: Pin remains in default state (usually input)
Causes:
Solution:
A0 or A[0] for single pin, A[0 1 2] for multipleRA0, others A0)Symptom: Initialization function runs every step, or step function runs only once
Cause: Incorrect Execute function setting
Solution:
Goal: Add a software delay using Microchip XC16/XC-DSC __delay_ms() built-in function.
Configuration:
Function Declaration: extern void __delay_ms(unsigned long t_ms);
Execute function: when block is updated (default)
Block Input: (leave empty - parameter name is t_ms)
Function returned value is a block output: OFF
Sample Time: -1
Simulink Model:
[Constant: 10] โโ> [C Function Call]
(__delay_ms)
Generated Code:
// In model_step() function
__delay_ms(rtb_Constant);
User C File (user_functions.c):
void process_data(int16_t input1, int16_t input2, int16_t *output) {
*output = (input1 + input2) / 2;
}
Block Configuration:
Function Declaration: extern void process_data(int16_t input1, int16_t input2, int16_t *output);
Block Input: input1, input2
Block Output: output
Add declaration in header: ON
Simulink Model:
[Signal A] โโโ
โโโ> [C Function Call] โโ> [Output]
[Signal B] โโโ (process_data)
Generated Code:
// In model_private.h (if AddHeaderDeclaration enabled)
extern void process_data(int16_t input1, int16_t input2, int16_t *output);
// In model_step()
process_data(rtb_SignalA, rtb_SignalB, &rtb_Output);
Goal: Call a custom initialization function only once at power-up.
User C File:
void init_custom_hardware(void) {
// Hardware initialization code
}
Configuration:
Function Declaration: extern void init_custom_hardware(void);
Execute function: only once at power-up time
Block Input: (leave empty - no parameters)
Add declaration in header: ON
Generated Code:
// In model_initialize() function
init_custom_hardware();
User C File:
uint32_t get_cpu_load(void) {
// Calculate CPU utilization percentage
return cpu_load_percent;
}
Block Configuration:
Function Declaration: extern uint32_t get_cpu_load(void);
Function returned value is a block output: ON
Block Input: (leave empty - no parameters)
Block Output: (leave empty - return value becomes output)
Simulink Model:
[C Function Call] โโ> [Display]
(get_cpu_load)
Generated Code:
// In model_step()
rtb_Output = get_cpu_load();
User C File:
void set_led_pattern(uint8_t pattern) {
LATB = pattern & 0xFF;
}
Block Configuration - Function Tab:
Function Declaration: extern void set_led_pattern(uint8_t pattern);
Block Input: pattern
Block Configuration - Pins Configuration Tab:
List of port used as Digital Output: B[0:7]
Generated Code:
// In model_initialize()
TRISBbits.TRISB0 = 0;
TRISBbits.TRISB1 = 0;
// ... (B2-B6) ...
TRISBbits.TRISB7 = 0;
ANSELBbits.ANSB0 = 0; // If device has ANSEL registers
ANSELBbits.ANSB1 = 0;
// ... (B2-B6) ...
ANSELBbits.ANSB7 = 0;
// In model_step()
set_led_pattern(rtb_Pattern);
When “Parse user file” is enabled, the block scans C files specified in:
The parser uses regular expressions to match function declarations of the form:
[extern] [unsigned|signed] <return_type> [*] <function_name>(<parameter_list>);
Recognized data types include:
void, char, int, short, long, float, doubleint8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_tboolean_T, int16_T, uint16_T, etc.Simulink.Bus objects defined in base workspaceThe block generates code using the TLC file MCHP_C_function_Call.tlc:
If AddHeaderDeclaration is enabled, the function prototype is added to the generated header:
// In model_private.h
extern void my_function(int x);
Depends on Function1Type parameter:
When “when block is updated (default)”:
// In model_step() via Outputs() section
void model_step(void) {
// ... other code ...
my_function(input_value);
// ... other code ...
}
When “only once at power-up time”:
// In model_initialize() via Start() section
void model_initialize(void) {
// ... other initialization ...
init_function();
// ... other initialization ...
}
| Configuration | Generated Code | Description |
|---|---|---|
| Scalar input parameter | LibBlockInputSignal() | Pass by value |
| Pointer/array input parameter | LibBlockInputSignalAddr() | Pass by address |
| Scalar output parameter | LibBlockOutputSignal() | Direct assignment (error if used as parameter) |
| Pointer/array output parameter | LibBlockOutputSignalAddr() | Pass by address |
| Literal value in Block Input | Direct value | Constant passed directly |
| Function return value | output = function(...) | Assigned to first output port if enabled |
Example with mixed parameter types:
Function: extern int my_func(int a, float *b, uint16_t c);
Block Input: a, b, c
Function returned value is a block output: ON
Generated call:
rtb_Output = my_func(rtb_InputA, &rtb_InputB, rtb_InputC);
The Pins Configuration tab generates initialization code based on port type:
| Port Type | TRIS Configuration | ANSEL Configuration |
|---|---|---|
| Digital Input | TRISx = 1 (input) | ANSELx = 0 (digital mode) |
| Digital Output | TRISx = 0 (output) | ANSELx = 0 (digital mode) |
| Analog Input | TRISx = 1 (input) | ANSELx = 1 (analog mode) |
Pin Format:
A5, B12A[0 1 2], B[5:10]A[1 2] B5 C[7:9]Generated code example:
PinDigitalInput: A[0 1] B5
โ Generates in model_initialize():
TRISAbits.TRISA0 = 1;
TRISAbits.TRISA1 = 1;
TRISBbits.TRISB5 = 1;
ANSELAbits.ANSA0 = 0; // If device supports ANSEL
ANSELAbits.ANSA1 = 0;
// ANSELB may not exist depending on device
User Functions Overview: Introduction to custom code integration
Master Block: Device configuration and compiler settings
Code Generation: Custom code integration options
Embedded Coder: Custom code integration
S-Function Builder: Advanced custom block functionality