The aim of this article is to help any user of Model-Based Design to enjoy his/her own custom C libraries or to call any C drivers or components that are not yet supported by NXP's toolbox. This uses the Matlab Coder and requires to include only a MATLAB function block in which the model will call a C function. For more details, you can have a look on the Mathworks Help Center at Integrate C Code Using the MATLAB Function Block- MATLAB & Simulink.
In my opinion, the greatest way to learn something is "learning-by-doing". So in this tutorial, we will add support for the BMS System in Model-Based Design for S32K. You are already familiar with our toolbox supported boards so let's talk a bit about this BMS system.
NXP has a great cell controller IC designed for automotive and industrial applications, more details can be found here MC33772B | 6-Channel Li-ion Battery Cell Controller IC | NXP. For this tutorial, we will use the FRDM33772BSPIEVB | MC33772 SPI EVB | NXP board, which handles up to 6 battery cells and connects to many NXP controllers via SPI. This is also compatible with the S32K family with some minor jumpers adjustments, but all the instructions can be found on the product page.
So the goal of this project is to be able to read the cell voltages from an MBDT Simulink model.
In order to include custom code, the user should follow these steps:
1. Add the directory path from which the Simulink will include the directories under Settings > Code Generation > Custom code > Include directories.
2. Insert a Matlab Function block in the Simulink model. This will be used for initialization. The goal here is to include the c headers in the generated code files. This requires to declare coder constant using the coder.const function. That has to be updated in the Build info using coder.updateBuildInfo . Here, the headers and the sources has to be included following this template:
%% Adding header information to the generated code
%% Adding source files to MakeFile
coder.updateBuildInfo( 'addSourceFiles', 'driver.c' );
This operation has to be performed only once.
3. When the user needs to call a custom function from the Simulink, the user must add a Matlab Function block, declare the inputs and outputs as required. Inside the Matlab Function code, the coder.ceval function must be called using the parameters provided as inputs.
For example, if the user needs to call a C function called BMS_Init with no parameters, the following line of code will perform that:
%% Initializing the BMS driver
if( coder.target( 'Rtw' ) )
This will generate the following code:
But if the code is more complex, the easiest way is to declare a wrapper function and to call the wrapper using the coder.ceval.
This scenario fits on most of our users requirements: to use a piece of code unsupported yet on MBDT. For this IC, NXP already provides the KIT3377x_DRV driver together with an example in S32DS which measures cell voltages and displays it using FreeMaster.
We created an S32K project for the S32K144 board, added the FreeMaster block and an LPSPI Instance according to the settings and the pin requirements by the MC33772 board. The Initialize variable will only be used to call the initialization sequence for the BMS.
Now, as we described in the previous chapter, we declared a folder "bcc" that contains the required drivers and some wrappers, also inserted in the Configuration parameters.
The initialize function contains a Matlab Call Function. This one includes all the steps described at the second point. What should be noticed here is the check from line 7. All that cinclude code will be called only when the coder.target is Rtw. If the user adds an else condition, that code will be called only when simulate. Now, MBD_MCC_Init is wrapper designed to perform all the initialization steps from the driver. It was easier like this.
The MC33772 has been initialized so whenever the user needs the values, he/she must add a Matlab Function block that will provide the values to the model.
The code behind this block has been attached in the next image. The output values from the getCellMeasurements are provided as outputs and inside the get_cellVoltages, it will call the C updateMeasurements function using the coder.wref function.
Now, after we solved some bugs during code generation and had successfully built the code, we can run the generated code on the board. The following screenshot represents the Voltages and a variable Current measurement converted by the MC33772.
In this article, we presented a method of getting the needed C libraries/drivers/code in the Simulink model using custom code and Matlab Coder. We provided a short step list and a more detailed tutorial for an actual application, a Battery Management System, using NXP hardware. This approach can be successfully achieved either if we use the S32K or MPC Toolboxes.