Driver integration using C Caller or C Function in i.MX RT MBDT

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Driver integration using C Caller or C Function in i.MX RT MBDT

1,851 Views
Maciek
Contributor V

Hi,

in the workflow used with i.MX RT MBDT (and also with Kinetis-KV MBDT: the use of NXP Config Tools for driver initialization etc.) - it should be much easier to integrate additional functionality from the SDK API, than it was for example in the case of S32K MBDT.
We are familiar with the 'old' ways of driver integration: using Legacy Code Tool or writing S-functions and TLC files by hand.
Lately, additional blocks were introduced by Mathworks to simplify the process: C Caller and C Function blocks.


Can You provide simple example workflow showing how to integrate additional API function calls in the generated code using C Caller or C Function blocks ?


For example: how to incorporate 'GPIO_ClearPinsOutput' or maybe 'GPIO_ClearPinsInterruptFlags' into the generated code...
How to make different peripheral data structures initialized by Config Tools (like 'GPIO_Type') available to the API functions incorporated into the model using C Caller or C Function blocks ?

If I'm wrong - and for some reason this workflow can't be used in this case - please let me know !

Thanks for help
Maciek

0 Kudos
3 Replies

1,813 Views
nxa11767
NXP Employee
NXP Employee

Hi @Maciek ,

 

We don't have an example with C Caller or C function that calls the SDK API C functions. I've tried to build one but with no success, yet. I'm still working on how to integrate the SDK structures/defines like 'GPIO_Type' into the model so that these blocks recognized them. I am talking also with Mathworks team, and I hope they can shed some light into this. When I will have a working example I will let you know.

Till then, what I usually do when I want to call a specific SDK function in my model is to use the Custom Code library blocks:

nxa11767_1-1634299912088.png

If I need to add something in initialize phase I use the System Initialize block and for actions happening on each step System Outputs.

And I just add there the code I want to call:

nxa11767_2-1634300020385.png

The GPIO9 will be recognized since is defined in the MIMXRT1170_cm7.h included in the SDK driver header files. You might need to add in the Hardware settings-> Code generation -> Custom code the specific driver header include for the peripheral you use and the C source of the driver if the model file does not contain at least a block for that peripheral (in this case the include is already added in the block tcl file and C source added to build path).

Also, for the variable inputs/outputs of the function I'm calling, I add in the model data memory storages with the same name and declared as volatile or extern so that it keeps the name I'm giving in the model.  

For structures data types for eg that are declared in the SDK headers, you can import them as Simulink Bus into the workspace and define data storage memory with this imported type.

I hope this helps,

Alexandra

 

 

0 Kudos

1,797 Views
Maciek
Contributor V

Hi @nxa11767 ,

thanks for the tip! We have never used the Custom Code blocks this way before. It's simple and it works! It is however more difficult to control the exact code placement in the generated code. Also the global variable interface to the called external code is harder to track/maintain in the model. At this moment we will use this method for quick experimentation with not supported SDK API functions.

In regard to my original question: we have experimented a little with 'C Function' block and it is very easy to add custom code. It is also very easy to make a block that generates custom code and at the same time can be used in simulation in a different way. But, as you also have pointed out, we don't know how to integrate SDK structs and defines into the model to be used in the called (via 'C Function' block) functions.

Please let me know when something becomes clear in this matter...

Thanks
Maciek

0 Kudos

1,762 Views
nxa11767
NXP Employee
NXP Employee

Hi @Maciek ,

I'm coming back with information on integrating device driver code with C function from Mathworks team.
One of the issues I had on C function was the host simulation steps did before code generation - it was trying to build the MCU SDK driver sources with the setup host MEX compiler.
Following the steps from a simple tutorial on this block, it mentioned that in Simulated Target must be specified the sources and header files that included the custom code I wanted to integrate.
Since I just wanted code generation,  the settings done in Simulation Target must be cleared(or uncheck the Import Custom Code) and for Code Generation only, the code inside C Function block must be placed inside of “#ifndef MATLAB_MEX_FILE <output code> #endif” macro control.
https://www.mathworks.com/help/simulink/ug/call-and-integrate-external-c-algorithms-into-simulink-us...

As for the external structures/datatypes used in SDK, this was their suggestion (I used as example the GPIO_GetPinsInterruptFlags fct call):


"C Function block still has to able to parse the Code Generation code using host machine MEX compiler.
For the following device driver call, I need to define and declare dependent types, functions, variables used by the call. All declarations must be compatible and understood with selected MEX compiler.

“out = GPIO_GetPinsInterruptFlags(GPIO9);”

So, this is the code I wrote in the C Function block that worked with code generation.
==================== BEGIN =========================
#ifndef MATLAB_MEX_FILE
/* Code generation only. Target specific code. */

#define __I volatile const
#define __O volatile
#define __IO volatile
#define uint32_t unsigned int
#define uint8_t unsigned char

/* Define required types used by C function declaration */
typedef struct {
__IO uint32_t DR;
__IO uint32_t GDIR;
__I uint32_t PSR;
__IO uint32_t ICR1;
__IO uint32_t ICR2;
__IO uint32_t IMR;
__IO uint32_t ISR;
__IO uint32_t EDGE_SEL;
uint8_t RESERVED_0[100];
__O uint32_t DR_SET;
__O uint32_t DR_CLEAR;
__O uint32_t DR_TOGGLE;
} GPIO_Type;

/* Declare external C functions, variables accessed in output code */
extern uint32_t GPIO_GetPinsInterruptFlags(GPIO_Type *base);
extern GPIO_Type* GPIO9;

/* Output code: Call driver function */
out = GPIO_GetPinsInterruptFlags(GPIO9);

#endif
If structure type “GPIO_Type” is not used as any model signal, parameter etc. type, or in another word, it is entirely opaque to the model, then you can typedef it to any type for simplification.
Otherwise, the typedef in the above example code has to be consistent to the original type in external C header file.

Following is the simplified code also worked
==================== BEGIN =========================
#ifndef MATLAB_MEX_FILE
/* Code generation only. Target specific code. */

/* Define required types used by C function declaration */
/* if GPIO_Type is not used as model signal type, and is entirely opaque to model, you can typedef it to any type. */
typedef int GPIO_Type;

/* Declare external C functions, variables accessed in output code */
extern unsigned int GPIO_GetPinsInterruptFlags(GPIO_Type *base);
extern GPIO_Type* GPIO9;

/* Output code: Call driver function */
out = GPIO_GetPinsInterruptFlags(GPIO9);

#endif


I tried both forms on my side and I got the same results when running on the board.
Comparing with System Outputs block, C function block involves some additional adjustments.

 

I hope this helps,

Best regards,

Alexandra

0 Kudos