Generate C Code from a Control Algorithm for an Embedded System
Generate code for a control algorithm model, integrate the generated code with an existing system, and validate simulation and executable results.
- About the Examples
- Third-Party Software
- Understand the Model
- Understand the Functional Design of the Model
- Inspect the Top-Level Model
- Inspect Subsystems
- Inspect Configuration Options for Code Generation
- Save Configuration Parameters
- Understand the Simulation Testing Environment
- Run the Simulation Tests
- Generate Code from the Model
- Examine the Generated Code
About the Examples
Each example in this series focuses on a specific aspect of code generation or integration. For most tasks, you can complete the task on your own by following the instructions or executing a script by clicking a hyperlink. Some scripts take time to run. When the corresponding task is finished, these scripts generate a dialog box.
Each example has a unique model and data set so that the examples are independent. You do not have to run the examples in a specific order. When you transition between examples, the current model is saved locally so that each example captures your modifications to the model and model data.
To recover a model in its original state, delete the local copy of the model and the model data. The model data is saved as PCG_Demo_#_data.mat.
Use these hyperlinks to navigate to the other examples in the series.
Some examples use the Eclipse™ IDE and the Cygwin™/gcc compiler. Instructions to install and use Eclipse™ and Cygwin™/gcc are at the end of these examples.
Understand the Model
This example shows and describes the model from behavioral and structural perspectives. The example also shows how to configure a model for code generation and how to generate code. You learn how to:
- Understand the functional behavior of the example model.
- Understand how to validate the model.
- Become familiar with model-checking tools.
- Become familiar with configuration options that affect code generation.
- Generate code from a model.
Understand the Functional Design of the Model
This example uses a simple model of a throttle controller. The model features redundancy, which safety-critical, drive-by-wire applications commonly use. The model highlights a standard model structure and a set of basic blocks in algorithm design.
In the current configuration, the code that the model generates is not configured for a production target system. In this example, you change the target configuration and observe the resulting changes to the format of the generated code.
Inspect the Top-Level Model
The top-level model consists of:
- Four subsystems: PI_ctrl_1, PI_ctrl_2, Define_Throt_Param, and Pos_Command_Arbitration.
- Top-level inputs: pos_rqst, fbk_1, and fbk_2.
- Top-level outputs: pos_cmd_one, pos_cmd_two, and ThrotComm.
- Signal routing.
- No transformative blocks. Transformative blocks change the value of a signal, for example, Sum and Integrator blocks.
The layout shows a basic model architectural style.
- Separation of calculations from signal routing (lines and buses)
- Partitioning into subsystems
This style suits many types of models.
Two subsystems represent PI controllers: PI_ctrl_1 and PI_ctrl_2. The subsystems have identical content and, for now, use identical data. Later, you use the subsystems to learn how the code generator can create reusable functions.
The PI controllers come from a library, which is a group of related blocks or models that you intend to reuse. Libraries provide one of two methods for including and reusing models. You see the second method, model referencing, later in this series.
When you use a library block in a model, you cannot edit the instance of the block in the model. Instead, edit the block definition in the library. Then, instances of the block in different models remain consistent.
The Stateflow® chart Pos_Command_Arbitration performs basic error checking on the two command signals. If the command signals are too far apart, the chart sets the output to a fail_safe position.
Inspect Configuration Options for Code Generation
To prepare a model for code generation, first set model configuration parameters. The configuration parameters determine the method that the code generator uses to generate the code and the resulting code format.
Code Generation Objectives
You can manually configure the model configuration parameters. Alternatively, you can choose from predefined objectives to automatically configure the model configuration parameters.
You can choose from these high-level code generation objectives:
- Execution efficiency
- ROM efficiency
- RAM efficiency
- Safety precaution
Each objective checks the current model configuration parameters against the recommended values of the objectives. Each objective also includes a set of Code Generation Advisor checks. You can use these additional checks to verify that the model configuration parameters are set to create code that meets the objectives.
Some of the recommendations that the objectives make conflict with the Code Generation Advisor checks. The order in which you select objectives determines the result. Simulink® resolves conflicts by satisfying objectives that have a higher priority.
The figure shows how to set the priority to Execution efficiency > ROM efficiency > RAM efficiency. To open the dialog box, in the Configuration Parameters dialog box, select the Code Generation pane. Then, click Set objectives.
You can run the Code Generation Advisor to check the model based on the specified objectives. To launch the Code Generation Advisor, in the Configuration Parameters dialog box, on the Code Generation pane, click Check model.
The Code Generation Advisor creates a list of checks based on the objectives that you select. The first check reviews the current values of the configuration parameters and suggests alternative values based on the objectives. The check provides an automated method for setting the parameters to the recommended values.
Manual Configuration Options
In the Model Configuration Parameters dialog box, these panes are relevant to code generation:
- Hardware Implementation
- Code Generation
To generate code for a model, you must configure the model to use a fixed-step solver. The start and stop time do not affect the generated code.
- Parameter: Start time, Required Setting: Any, Effect on Code: No effect
- Parameter: Stop time, Required Setting: Any, Effect on Code: No effect
- Parameter: Type, Required Setting: Fixed-step, Effect on Code: Cannot generate code unless set to Fixed-step
- Parameter: Solver, Required Setting: Any, Effect on Code: Controls s elected integration algorithms
- Parameter: Fixed-step size, Required Setting: Lowest common multiple of rates in system, Effect on Code: Sets base rate of system
- Parameter: Treat each discrete rate as a separate task, Required Setting: Any, Effect on Code: If selected, generates an entry-point function for each rate in the system
The Optimization pane contains parameters that control these settings:
- Remove unused branches from the code and control the creation of temporary variables.
- control which signals have explicit initialization code.
- Enables and disables use of overflow and division-by-zero protection code.
Use hardware implementation parameters to specify a hardware board. Simulink® adjusts other settings on the pane, including hidden microprocessor device details, based on your board selection. To view or adjust the hidden parameter settings, such as the word size and byte ordering, click Device details.
Use the Code Generation pane to specify the system target file (STF). This example uses the Embedded Coder® STF (ert.tlc). You can extend this STF to create a customized configuration. Some of the basic configuration options on this pane include:
1. The code generator target:
- ert.tlc - "Base" Embedded Coder®
- grt.tlc - "Base" Generic Real-Time Target
- Hardware-specific targets
2. Make file
3. Code formatting options
- Use of parentheses
- Header file information
- Variable naming conventions
4. Inclusion of custom code:
- C files
- H files
- Object files
- Folder paths
5. Generation of ASAP2 files
Save Configuration Parameters
You can save the values of configuration parameters as a MATLAB® function. At the command prompt, enter:
hCs = getActiveConfigSet('rtwdemo_PCG_Eval_P1'); hCs.saveAs('ConfiguredData');
The MATLAB® function saves a textual representation of the configuration parameter object. You can use the generated file for archiving or comparing different versions of the files by using traditional diff tools. You can also visually inspect the content of the file.
You can run the function to set the configuration parameters of other models.
hCs2 = ConfiguredData; attachConfigSet('myModel', hCs2, true); setActiveConfigSet('myModel', hCs2.Name);
Understand the Simulation Testing Environment
You test the throttle controller model in a separate model called a test harness. A test harness is a model that evaluates the control algorithm. Using a test harness:
- Separates the test data from the control algorithm
- Separates the plant or feedback model from the control algorithm
- Provides a reusable environment for multiple versions of the control algorithm
A typical simulation testing environment consists of these parts:
- Unit under test
- Test vector source
- Evaluation and logging
- Plant or feedback system
- Input and output scaling
The control algorithm is the unit under test. The test harness model references the control algorithm through a Model block. With Model blocks, you can reuse components. The Model block refers to the control algorithm by name (rtwdemo_PCG_Eval_P1).
The Model block enables inclusion (referencing) of a model in another model as a compiled function. By default, Simulink® compiles the referenced model when you change it. Compiled functions have these advantages over libraries:
- Large models simulate faster.
- You can simulate compiled functions directly.
- The simulation requires less memory. When you add multiple instances of the model (multiple Model blocks), only one copy of the compiled model exists in memory.
The model uses a Signal Builder block as the test vector source. The block has data that drives the simulation (pos_rqst) and the expected results that the Verification subsystem uses. This example uses only one set of test data, though in a typical application you create a test suite that fully exercises the system.
The test harness compares the simulation results against golden data, which is a set of test results that indicate the desired behavior for the model. In this model, the V&V Assertion block compares the simulated throttle value position from the plant against the golden value that the test harness provides. If the difference between the two signals is greater than 5%, the test fails and the Assertion block stops the simulation.
Alternatively, you can evaluate the simulation data after the simulation completes execution. You can use either MATLAB® scripts or third-party tools to perform the evaluation. Post-execution evaluation provides greater flexibility in the analysis of the data, though you must wait until execution finishes. Combining the two methods can yield a highly flexible and efficient test environment.
This example models the throttle dynamics by breaking a transfer function down into a canonical form. You can create plant models to model any level of fidelity. Many applications use a different plant model at each stage of testing.
The subsystems that scale input and output perform these primary functions:
- Select signals to route to the unit under test and to the plant.
- Rescale signals between engineering units and units that the unit under test requires.
- Handle rate transitions between the plant and the unit under test.
Run the Simulation Tests
To run the test harness model simulation, click Start or click this hyperlink.
The first time the test harness runs, Simulink® must compile the referenced model. You can monitor the compilation progress in the Command Window.
When the model simulation is complete, Simulink® displays the results in a plot figure.
The lower-right plot shows the difference between the expected (golden) throttle position and the throttle position that the plant calculated.
Generate Code from the Model
Generate code from the model by using one of these techniques:
- In the model, press Ctrl+B.
- In the model, select Code > C/C++ Code > Build Model.
- Click this hyperlink:
Simulink® Coder™ generates several files. The resulting code, though computationally efficient, is not yet organized for integration into the production environment.
Examine the Generated Code
The code generation process creates multiple files that you can view from the Model Explorer. In addition to the standard C and H files, the code generator creates a set of HTML files. The HTML files provide hyperlinks between the code and the model.
In the generated code, observe that:
- All of the controller code exists in one function called ModelName_step, which is in the file rtwdemo_PCG_Eval_P1.c.
- The code generator folds the operations of multiple blocks into one statement of code.
- The function ModelName_initialize initializes variables.
- Simulink® Coder™ data structures define all of the data (for example, rtwdemo_PCG_Eval_P1_U.pos_rqst).
- rtwdemo_PCG_Eval_P1.c: C file that defines step and initialization functions
- ert_main.c: Example Main file that includes a simple scheduler
- rtwdemo_PCG_Eval_P1.h: H file that contains type definitions of the Simulink® Coder™ data structures
- PCG_Eval_p1_private.h: File that declares data that only the generated code uses
- rtwdemo_PCG_Eval_P1_types.h: H file that declares the real-time model data structure
For the next example in this series, see docid:ecoder_examples.example-rtwdemo_pcgd_stage_2_p1_script.