Print Preview C:\TEMP\Apdf_2541_3068\home\AppData\Local\PTC\Arbortext\Editor\.aptcache\ae1qwjtr/tf1qwcnj Simulink Coder User's Guide
User Manual:
Open the PDF directly: View PDF .
Page Count: 1365
Download | |
Open PDF In Browser | View PDF |
Simulink® Coder™ User’s Guide R2012b How to Contact MathWorks Web Newsgroup www.mathworks.com/contact_TS.html Technical Support www.mathworks.com comp.soft-sys.matlab suggest@mathworks.com bugs@mathworks.com doc@mathworks.com service@mathworks.com info@mathworks.com Product enhancement suggestions Bug reports Documentation error reports Order status, license renewals, passcodes Sales, pricing, and general information 508-647-7000 (Phone) 508-647-7001 (Fax) The MathWorks, Inc. 3 Apple Hill Drive Natick, MA 01760-2098 For contact information about worldwide offices, see the MathWorks Web site. Simulink® Coder™ User’s Guide © COPYRIGHT 2011–2012 by The MathWorks, Inc. The software described in this document is furnished under a license agreement. The software may be used or copied only under the terms of the license agreement. No part of this manual may be photocopied or reproduced in any form without prior written consent from The MathWorks, Inc. FEDERAL ACQUISITION: This provision applies to all acquisitions of the Program and Documentation by, for, or through the federal government of the United States. By accepting delivery of the Program or Documentation, the government hereby agrees that this software or documentation qualifies as commercial computer software or commercial computer software documentation as such terms are used or defined in FAR 12.212, DFARS Part 227.72, and DFARS 252.227-7014. Accordingly, the terms and conditions of this Agreement and only those rights specified in this Agreement, shall pertain to and govern the use, modification, reproduction, release, performance, display, and disclosure of the Program and Documentation by the federal government (or other entity acquiring for or through the federal government) and shall supersede any conflicting contractual terms or conditions. If this License fails to meet the government’s needs or is inconsistent in any respect with federal procurement law, the government agrees to return the Program and Documentation, unused, to The MathWorks, Inc. Trademarks MATLAB and Simulink are registered trademarks of The MathWorks, Inc. See www.mathworks.com/trademarks for a list of additional trademarks. Other product or brand names may be trademarks or registered trademarks of their respective holders. Patents MathWorks products are protected by one or more U.S. patents. Please see www.mathworks.com/patents for more information. Revision History April 2011 September 2011 March 2012 September 2012 Online Online Online Online only only only only New for Version 8.0 (Release 2011a) Revised for Version 8.1 (Release 2011b) Revised for Version 8.2 (Release 2012a) Revised for Version 8.3 (Release 2012b) Check Bug Reports for Issues and Fixes Software is inherently complex and is not free of errors. The output of a code generator might contain bugs, some of which are not detected by a compiler. MathWorks reports critical known bugs brought to its attention on its Bug Report system at www.mathworks.com/support/bugreports/. Use the Saved Searches and Watched Bugs tool with the search phrase ‘‘Incorrect Code Generation’’ to obtain a report of known bugs that produce code that might compile and execute, but still produce wrong answers. The bug reports are an integral part of the documentation for each release. Examine periodically all bug reports for a release, as such reports may identify inconsistencies between the actual behavior of a release you are using and the behavior described in this documentation. In addition to reviewing bug reports, you should implement a verification and validation strategy to identify potential bugs in your design, code, and tools. Contents Model Architecture and Design Modeling 1 ............. 1-2 Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Single-Tasking and Multitasking Execution Modes . . . . . . Handle Rate Transitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . Single-Tasking and Multitasking Model Execution . . . . . . Handle Asynchronous Events . . . . . . . . . . . . . . . . . . . . . . . . Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Configure Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4 1-4 1-5 1-13 1-27 1-34 1-79 1-90 Configure a Model for Code Generation Supported Products and Block Usage . . . . . . . . . . . . . . . 1-92 Related Products . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-92 Simulink Built-In Blocks That Support Code Generation . . 1-94 Block Set Support for Code Generation . . . . . . . . . . . . . . . . 1-116 Fixed-Point Tool Data Type Override . . . . . . . . . . . . . . . . . 1-116 Data Type Overrides Unavailable for Most Blocks in Embedded Targets and Desktop Targets . . . . . . . . . . . . 1-116 Modeling Semantic Considerations . . . . . . . . . . . . . . . . . . Data Propagation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sample Time Propagation . . . . . . . . . . . . . . . . . . . . . . . . . . Latches for Subsystem Blocks . . . . . . . . . . . . . . . . . . . . . . . Block Execution Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Algebraic Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-117 1-117 1-119 1-120 1-120 1-122 v Subsystems 2 Code Generation of Subsystems . . . . . . . . . . . . . . . . . . . . . Subsystem Code Dependence . . . . . . . . . . . . . . . . . . . . . . . . 2-2 2-3 Generate Code and Executables for Individual Subsystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Subsystem Build Limitations . . . . . . . . . . . . . . . . . . . . . . . . 2-4 2-6 Inline Subsystem Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Configure Subsystem to Inline Code . . . . . . . . . . . . . . . . . . Exceptions to Inlining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-7 2-7 2-8 Generate Subsystem Code as Separate Function and Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-10 Generate Reusable Function for Identical Subsystems Within a Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-11 Considerations for Function Packaging Options Auto and Reusable function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-13 Optimize Code for Identical Nested Subsystems . . . . . . 2-14 Generate Reusable Code for Subsystems Containing S-Function Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-15 Generate Reusable Code from Stateflow Charts . . . . . . 2-16 Code Reuse Limitations for Subsystems . . . . . . . . . . . . . Blocks That Prevent Code Reuse . . . . . . . . . . . . . . . . . . . . . Code Reuse Limitations for Subsystems Shared Across Referenced Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-17 2-17 Code Reuse For Subsystems Shared Across Referenced Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-19 ....................... 2-20 Reusable Library Subsystem vi Contents 2-18 Code Generation of a Reusable Library Subsystem . . . . . . Reusable Library Subsystem Code Placement and Naming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Reusable Library Subsystem in the Top Model . . . . . . . . . . Reusable Library Subsystem Connected to Root Outport . . 2-20 Code Generation of Constant Parameters . . . . . . . . . . . . 2-22 Shared Constant Parameters for Code Reuse . . . . . . . . Shared Constant Parameters Limitations . . . . . . . . . . . . . . 2-23 2-24 Generate Reusable Code for Subsystems Shared Across Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-25 Determine Why Subsystem Code Is Not Reused . . . . . . Review the Subsystems Section of the HTML Code Generation Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Compare Subsystem Checksum Data . . . . . . . . . . . . . . . . . 2-21 2-21 2-21 2-32 2-32 2-32 Referenced Models 3 Code Generation for Referenced Models . . . . . . . . . . . . . 3-2 Generate Code for Referenced Models . . . . . . . . . . . . . . . About Generating Code for Referenced Models . . . . . . . . . . Create and Configure the Subsystem . . . . . . . . . . . . . . . . . Convert Model to Use Model Referencing . . . . . . . . . . . . . . Generate Model Reference Code for a GRT Target . . . . . . . Work with Project Folders . . . . . . . . . . . . . . . . . . . . . . . . . . 3-4 3-4 3-4 3-7 3-11 3-14 Project Folder Structure for Model Reference Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-16 Configure Referenced Models . . . . . . . . . . . . . . . . . . . . . . . 3-17 Build Model Reference Targets . . . . . . . . . . . . . . . . . . . . . 3-18 vii Reduce Change Checking Time . . . . . . . . . . . . . . . . . . . . . . 3-18 Simulink Coder Model Referencing Requirements . . . . Configuration Parameter Requirements . . . . . . . . . . . . . . . Naming Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Custom Target Requirements . . . . . . . . . . . . . . . . . . . . . . . 3-19 3-19 3-23 3-24 Storage Classes for Signals Used with Model Blocks . . Storage Classes for Parameters Used with Model Blocks . . Effects of Signal Name Mismatches . . . . . . . . . . . . . . . . . . . 3-25 3-26 3-27 Inherited Sample Time for Referenced Models . . . . . . . 3-29 Customize Library File Suffix and File Type . . . . . . . . . 3-31 Reusable Code and Referenced Models . . . . . . . . . . . . . . General Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . Code Reuse and Model Blocks with Root Inport or Outport Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-32 3-32 Simulink Coder Model Referencing Limitations . . . . . . Customization Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . Data Logging Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . State Initialization Limitation . . . . . . . . . . . . . . . . . . . . . . . Reusability Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . S-Function Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Simulink Tool Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . Subsystem Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Target Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Other Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-36 3-36 3-36 3-37 3-38 3-39 3-39 3-39 3-39 3-40 3-33 Combined Models 4 viii Contents Combined Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2 Use GRT Malloc to Combine Models . . . . . . . . . . . . . . . . . 4-4 Share Data Across Models . . . . . . . . . . . . . . . . . . . . . . . . . . Timing Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Data Logging and External Mode Support . . . . . . . . . . . . . 4-4 4-4 4-5 Configure Model Parameters 5 Platform Options for Development and Deployment . . Configure Emulation and Embedded Target Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Identify the Device Vendor . . . . . . . . . . . . . . . . . . . . . . . . . . Identify the Device Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . Register Additional Device Vendor and Device Type Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Set Native Word Size for the Device . . . . . . . . . . . . . . . . . . Set Byte Ordering Used By Device . . . . . . . . . . . . . . . . . . . Set Quotient Rounding Technique for Signed Integer Division . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Set Arithmetic Right Shift Behavior for Signed Integers . . 5-2 5-3 5-4 5-5 5-5 5-9 5-10 5-11 5-12 Configure Embedded Hardware Characteristics . . . . . . 5-13 Configure Emulation Hardware Characteristics . . . . . . Update Release 14 Hardware Configuration . . . . . . . . . . . . 5-15 5-17 Control the Location for Generated Files . . . . . . . . . . . . 5-18 Control Generated Files Location Used for Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-20 Control the Location for Code Generation Files . . . . . . 5-22 Override Build Folder Settings for Current Session . . . 5-24 ix Model Protection 6 Protect a Referenced Model . . . . . . . . . . . . . . . . . . . . . . . . Requirements for Protecting a Model . . . . . . . . . . . . . . . . . 6-2 6-3 .................................... 6-4 Protected Model Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-5 Code Generation Support in a Protected Model . . . . . . Protected Model Requirements to Support Code Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-6 Protected Model File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-8 .......................... 6-9 Test the Protected Model . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-13 Save Base Workspace Definitions . . . . . . . . . . . . . . . . . . . 6-15 Package a Protected Model . . . . . . . . . . . . . . . . . . . . . . . . . 6-16 Harness Model Create a Protected Model 6-6 Data, Function, and File Definition Data Representation 7 Enumerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Enumerated Data Types . . . . . . . . . . . . . . . . . . . . . . Default Code for an Enumerated Data Type . . . . . . . . . . . . Type Casting for Enumerations . . . . . . . . . . . . . . . . . . . . . . Override Default Methods (Optional) . . . . . . . . . . . . . . . . . Enumerated Type Limitations . . . . . . . . . . . . . . . . . . . . . . . x Contents 7-2 7-2 7-2 7-3 7-4 7-7 Structure Parameters and Generated Code . . . . . . . . . . About Structure Parameters and Generated Code . . . . . . . Configure Structure Parameters for Generated Code . . . . Control Name of Structure Parameter Type . . . . . . . . . . . . 7-8 7-8 7-8 7-9 Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Nontunable Parameter Storage . . . . . . . . . . . . . . . . . . . . . . Tunable Parameter Storage . . . . . . . . . . . . . . . . . . . . . . . . . Tunable Parameter Storage Classes . . . . . . . . . . . . . . . . . . Declare Tunable Parameters . . . . . . . . . . . . . . . . . . . . . . . . Tunable Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Linear Block Parameter Tunability . . . . . . . . . . . . . . . . . . . Configuration Parameter Quick Reference Diagram . . . . . Generated Code for Parameter Data Types . . . . . . . . . . . . . Tunable Workspace Parameter Data Type Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tune Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameter Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Structure Parameters and Generated Code . . . . . . . . . . . . 7-10 7-10 7-11 7-13 7-14 7-17 7-22 7-26 7-27 7-28 Signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Signal Storage Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . Signals with Auto Storage Class . . . . . . . . . . . . . . . . . . . . . Signals with Test Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interface Signals to External Code . . . . . . . . . . . . . . . . . . . Symbolic Naming Conventions for Signals . . . . . . . . . . . . . Summary of Signal Storage Class Options . . . . . . . . . . . . . Interfaces for Monitoring Signals . . . . . . . . . . . . . . . . . . . . . Signal Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Initialize Signals and States Using Signal Objects . . . . . . . 7-52 7-52 7-53 7-55 7-59 7-60 7-62 7-63 7-64 7-65 7-74 States . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About States . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . State Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . State Storage Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interface States to External Code . . . . . . . . . . . . . . . . . . . . Symbolic Names for States . . . . . . . . . . . . . . . . . . . . . . . . . . Control Code Generation for Block States . . . . . . . . . . . . . . Summary of State Storage Class Options . . . . . . . . . . . . . . 7-83 7-83 7-83 7-84 7-85 7-87 7-90 7-91 7-34 7-36 7-38 7-49 xi Data Stores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Data Stores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Storage Classes for Data Store Memory Blocks . . . . . . . . . Generate Code for Data Store Memory Blocks . . . . . . . . . . Nonscalar Data Stores in Generated Code . . . . . . . . . . . . . Data Store Buffering in Generated Code . . . . . . . . . . . . . . . 7-93 7-93 7-93 7-96 7-97 7-99 Entry Point Functions and Scheduling 8 Entry Point Functions and Scheduling . . . . . . . . . . . . . . 8-2 ............................ 8-4 Non-Real-Time Single-Tasking Systems . . . . . . . . . . . . . . 8-6 Non-Real-Time Multitasking Systems . . . . . . . . . . . . . . . . 8-7 Real-Time Single-Tasking Systems . . . . . . . . . . . . . . . . . . 8-9 Real-Time Multitasking Systems . . . . . . . . . . . . . . . . . . . . 8-11 Multitasking Systems Using Real-Time Tasking Primitives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-14 Program Timing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-16 Program Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-18 External Mode Communication . . . . . . . . . . . . . . . . . . . . . 8-19 Data Logging in Single-Tasking and Multitasking Model Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-20 About Model Execution xii Contents Rapid Prototyping and Embedded Model Execution Differences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-22 Rapid Prototyping Model Functions . . . . . . . . . . . . . . . . . 8-23 Embedded Model Functions . . . . . . . . . . . . . . . . . . . . . . . . 8-30 Code Generation Configuration 9 Configuring a Model for Code Generation . . . . . . . . . . . Code Generation Configuration . . . . . . . . . . . . . . . . . . . . . . Open the Model Configuration for Code Generation . . . . . . Configure a Model Programmatically . . . . . . . . . . . . . . . . . 9-2 9-2 9-3 9-3 Application Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Code Generation Objectives . . . . . . . . . . . . . . . . . . . . Configure Code Generation Objectives Using Code Generation Advisor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-6 9-6 Target . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Hardware Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Available Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Targets and Code Formats . . . . . . . . . . . . . . . . . . . . Types of Target Code Formats . . . . . . . . . . . . . . . . . . . . . . . Targets and Code Formats . . . . . . . . . . . . . . . . . . . . . . . . . . Targets and Code Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . Backwards Compatibility of Code Formats . . . . . . . . . . . . . Selecting a Target . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Template Makefiles and Make Options . . . . . . . . . . . . . . . . Custom Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Describing the Emulation and Embedded Targets . . . . . . . Describing Embedded Hardware Characteristics . . . . . . . . Describing Emulation Hardware Characteristics . . . . . . . . Specifying Target Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . Selecting and Viewing Code Replacement Libraries . . . . . 9-9 9-9 9-10 9-15 9-16 9-29 9-29 9-31 9-34 9-38 9-44 9-45 9-54 9-55 9-58 9-61 9-7 xiii Select the Target Language . . . . . . . . . . . . . . . . . . . . . . . . . 9-71 Code Appearance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Configure Code Comments . . . . . . . . . . . . . . . . . . . . . . . . . . Configure Generated Identifiers . . . . . . . . . . . . . . . . . . . . . 9-72 9-72 9-73 Debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-80 Source Code Generation 10 Initiate Code Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-2 Reload Generated Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-3 Generated Source Files and File Dependencies . . . . . . . 10-4 About Generated Files and File Dependencies . . . . . . . . . . 10-4 Header Dependencies When Interfacing Legacy/Custom Code with Generated Code . . . . . . . . . . . . . . . . . . . . . . . . 10-6 Dependencies of the Generated Code . . . . . . . . . . . . . . . . . . 10-16 Specify Include Paths in Simulink Coder Generated Source Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-21 Files and Folders Created by Build Process . . . . . . . . . . 10-24 Files Created During the Build Process . . . . . . . . . . . . . . . 10-24 Folders Used During the Build Process . . . . . . . . . . . . . . . . 10-28 How Code Is Generated From a Model . . . . . . . . . . . . . . . 10-31 Model Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-31 Code Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-31 Code Generation of Matrices and Arrays . . . . . . . . . . . . . 10-33 Simulink Coder Matrix Parameters . . . . . . . . . . . . . . . . . . . 10-34 Internal Data Storage for Complex Number Arrays . . . . . . 10-36 Shared Utility Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-37 About Shared Utility Code . . . . . . . . . . . . . . . . . . . . . . . . . . 10-37 xiv Contents Controlling Shared Utility Code Placement . . . . . . . . . . . . rtwtypes.h and Shared Utility Code . . . . . . . . . . . . . . . . . . Incremental Shared Utility Code Generation and Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Shared Utility Checksum . . . . . . . . . . . . . . . . . . . . . . . . . . . Shared Fixed-Point Utility Functions . . . . . . . . . . . . . . . . . Share User-Defined Data Types Across Models . . . . . . . . . Generating Code Using Simulink Coder™ 10-38 10-38 10-39 10-39 10-41 10-43 . . . . . . . . . . . 10-49 Report Generation 11 Reports for Code Generation . . . . . . . . . . . . . . . . . . . . . . . 11-2 HTML Code Generation Report Location . . . . . . . . . . . . 11-3 HTML Code Generation Report for Referenced Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-4 Generate a Code Generation Report . . . . . . . . . . . . . . . . . 11-5 Generate Code Generation Report After Build Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-6 Open Code Generation Report . . . . . . . . . . . . . . . . . . . . . . Limitation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-8 11-8 Generate Code Generation Report Programmatically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-10 Search in the Code Generation Report . . . . . . . . . . . . . . 11-11 View Code Generation Report in Model Explorer . . . . . 11-12 Package and Share the Code Generation Report . . . . . 11-14 xv Package the Code Generation Report . . . . . . . . . . . . . . . . . 11-14 View the Code Generation Report . . . . . . . . . . . . . . . . . . . . 11-15 Document Generated Code with Simulink Report Generator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Generate Code for the Model . . . . . . . . . . . . . . . . . . . . . . . . Open the Report Generator . . . . . . . . . . . . . . . . . . . . . . . . . Set Report Name, Location, and Format . . . . . . . . . . . . . . . Include Models and Subsystems in a Report . . . . . . . . . . . . Customize the Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Generate the Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-16 11-17 11-18 11-20 11-21 11-22 11-23 Deployment Desktops 12 Rapid Simulations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-2 About Rapid Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-2 Rapid Simulation Performance . . . . . . . . . . . . . . . . . . . . . . 12-3 General Rapid Simulation Workflow . . . . . . . . . . . . . . . . . . 12-3 Identify Rapid Simulation Requirements . . . . . . . . . . . . . . 12-4 Configure Inports to Provide Simulation Source Data . . . . 12-6 Configure and Build Model for Rapid Simulation . . . . . . . . 12-6 Set Up Rapid Simulation Input Data . . . . . . . . . . . . . . . . . 12-9 Scripts for Batch and Monte Carlo Simulations . . . . . . . . . 12-19 Run Rapid Simulations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-20 Rapid Simulation Target Limitations . . . . . . . . . . . . . . . . . 12-33 Generated S-Function Block . . . . . . . . . . . . . . . . . . . . . . . . About Object Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Create S-Function Blocks from a Subsystem . . . . . . . . . . . Tunable Parameters in Generated S-Functions . . . . . . . . . System Target File and Template Makefiles . . . . . . . . . . . . Checksums and the S-Function Target . . . . . . . . . . . . . . . . S-Function Target Limitations . . . . . . . . . . . . . . . . . . . . . . . xvi Contents 12-34 12-34 12-37 12-42 12-44 12-45 12-45 Real-Time Systems 13 Real-Time System Rapid Prototyping . . . . . . . . . . . . . . . About Real-Time Rapid Prototyping . . . . . . . . . . . . . . . . . . Goals of Real-Time Rapid Prototyping . . . . . . . . . . . . . . . . . Refine Code With Real-Time Rapid Prototyping . . . . . . . . . 13-2 13-2 13-3 13-3 Hardware-In-the-Loop (HIL) Simulation . . . . . . . . . . . . . About Hardware-In-the-Loop Simulation . . . . . . . . . . . . . . Set Up and Run HIL Simulations . . . . . . . . . . . . . . . . . . . . 13-5 13-5 13-6 External Code Integration 14 Integration Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Integration Options . . . . . . . . . . . . . . . . . . . . . . . . . . Types of External Code Integration . . . . . . . . . . . . . . . . . . . 14-2 14-2 14-2 Reuse Algorithmic Components in Generated Code . . . 14-5 Reusable Algorithmic Components . . . . . . . . . . . . . . . . . . . 14-5 Integrate External MATLAB Code . . . . . . . . . . . . . . . . . . . 14-5 Integrate External C or C++ Code . . . . . . . . . . . . . . . . . . . . 14-8 Integrate Fortran Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-11 Integration Considerations for Reusable Algorithmic Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-11 Deploy Algorithm Code Within a Target Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-14 Export Generated Algorithm Code for Embedded Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-18 Export Algorithm Executables for System Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-21 Modify External Code for Language Compatibility . . . 14-22 xvii Automate S-Function Generation . . . . . . . . . . . . . . . . . . . 14-23 Integrate External Code Using Legacy Code Tool . . . . . Legacy Code Tool and Code Generation . . . . . . . . . . . . . . . Generate Inlined S-Function Files for Code Generation . . Apply Code Style Settings to Legacy Functions . . . . . . . . . Address Dependencies on Files in Different Locations . . . . Deploy S-Functions for Simulation and Code Generation . . 14-28 14-28 14-29 14-30 14-31 14-32 Configure Model for External Code Integration . . . . . . 14-33 Insert Custom Code Blocks . . . . . . . . . . . . . . . . . . . . . . . . . Custom Code Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Embed Custom Code Directly Into MdlStart Function . . . . Custom Code in Subsystems . . . . . . . . . . . . . . . . . . . . . . . . Preserve User Files in Build Folder . . . . . . . . . . . . . . . . . . . 14-36 14-36 14-40 14-43 14-44 Insert S-Function Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About S-Functions and Code Generation . . . . . . . . . . . . . . Write Noninlined S-Functions . . . . . . . . . . . . . . . . . . . . . . . Write Wrapper S-Functions . . . . . . . . . . . . . . . . . . . . . . . . . Write Fully Inlined S-Functions . . . . . . . . . . . . . . . . . . . . . Write Fully Inlined S-Functions with mdlRTW Routine . . Guidelines for Writing Inlined S-Functions . . . . . . . . . . . . Write S-Functions That Support Expression Folding . . . . . S-Functions That Specify Port Scope and Reusability . . . . S-Functions That Specify Sample Time Inheritance Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . S-Functions That Support Code Reuse . . . . . . . . . . . . . . . . S-Functions for Multirate Multitasking Environments . . . Build Support for S-Functions . . . . . . . . . . . . . . . . . . . . . . . 14-46 14-46 14-52 14-54 14-64 14-65 14-91 14-91 14-105 14-111 14-113 14-113 14-120 Program Building, Interaction, and Debugging 15 Compiler or IDE Selection and Configuration . . . . . . . . Choose and Configure a Compiler . . . . . . . . . . . . . . . . . . . . Troubleshoot Compiler Configurations . . . . . . . . . . . . . . . . xviii Contents 15-2 15-2 15-9 Program Builds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Configure the Build Process . . . . . . . . . . . . . . . . . . . . . . . . . Initiate the Build Process . . . . . . . . . . . . . . . . . . . . . . . . . . . Build a Generic Real-Time Program . . . . . . . . . . . . . . . . . . Rebuild a Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Control Regeneration of Top Model Code . . . . . . . . . . . . . . Reduce Build Time for Referenced Models . . . . . . . . . . . . . Relocate Code to Another Development Environment . . . . How Executable Programs Are Built From Models . . . . . . 15-12 15-12 15-14 15-14 15-27 15-27 15-28 15-33 15-38 Build and Run a Program . . . . . . . . . . . . . . . . . . . . . . . . . . 15-43 Profile Code Performance . . . . . . . . . . . . . . . . . . . . . . . . . . About Profiling Code Performance . . . . . . . . . . . . . . . . . . . . How to Profile Code Performance . . . . . . . . . . . . . . . . . . . . Run Profiling Hooks for Generated Code . . . . . . . . . . . . . . . Profiling Limitation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15-45 15-45 15-45 15-48 15-49 Data Exchange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Host/Target Communication . . . . . . . . . . . . . . . . . . . . . . . . Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameter Tuning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Data Interchange Using the C API . . . . . . . . . . . . . . . . . . . ASAP2 Data Measurement and Calibration . . . . . . . . . . . . Direct Memory Access to Generated Code . . . . . . . . . . . . . . 15-50 15-50 15-105 15-119 15-137 15-174 15-189 Performance Optimizations for Generated Code 16 Optimization Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-2 Advice About Optimizing Models for Code Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-5 Control Compiler Optimizations . . . . . . . . . . . . . . . . . . . . 16-6 xix Optimization Tools and Techniques . . . . . . . . . . . . . . . . . 16-7 Control Memory Allocation for Time Counters . . . . . . . 16-9 Optimization Dependencies . . . . . . . . . . . . . . . . . . . . . . . . 16-10 Defensive Programming 17 Optimize Code for Floating-Point to Integer Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Remove Code That Wraps Out-of-Range Values . . . . . . . . . Remove Code That Maps NaN to Integer Zero . . . . . . . . . . 17-2 17-2 17-3 Disable Nonfinite Checks or Inlining for Math Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-4 Data Copy Reduction 18 xx Contents Optimizing Generated Code . . . . . . . . . . . . . . . . . . . . . . . . About Optimizing Generated Code . . . . . . . . . . . . . . . . . . . Setting Up the Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-2 18-2 18-2 Generate Code Without Buffer Optimization . . . . . . . . . 18-4 Generate Code With Buffer Optimization . . . . . . . . . . . . 18-9 Minimize Computations and Storage for Intermediate Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Expression Folding . . . . . . . . . . . . . . . . . . . . . . . . . . . Expression Folding Example . . . . . . . . . . . . . . . . . . . . . . . . Enable Expression Folding . . . . . . . . . . . . . . . . . . . . . . . . . . 18-11 18-11 18-12 18-15 Declare Signals as Local Function Data . . . . . . . . . . . . . . 18-17 Inline Invariant Signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-18 Execution Speed 19 Inline Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Referenced Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19-2 19-3 Configure Loop Unrolling Threshold . . . . . . . . . . . . . . . . 19-4 Optimize Code Generated for Vector Assignments . . . . Configure Model to Optimize Code Generated for Vector Assignments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Optimize Code Generated for Vector Assignments Using memcpy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19-6 19-6 19-7 Generate Target Optimizations Within Algorithm Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19-10 Memory Usage 20 Minimize Memory Requirements During Code Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-2 ........... 20-3 Reduce Memory Requirements for Signals . . . . . . . . . . . 20-4 ................ 20-5 Implement Logic Signals as Boolean Data Reuse Memory Allocated for Signals xxi Use Stack Space Allocation . . . . . . . . . . . . . . . . . . . . . . . . . 20-6 Verification Simulation and Code Comparison 21 Comparing Output Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21-2 Configure Signal Data for Logging . . . . . . . . . . . . . . . . . . 21-3 Log Simulation Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21-5 Log Data from the Generated Program . . . . . . . . . . . . . . 21-7 Compare Numerical Results . . . . . . . . . . . . . . . . . . . . . . . . 21-9 Customization Build Process Integration 22 Control Build Process Compiling and Linking . . . . . . . . 22-2 Cross-Compile Code Generated on Microsoft Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-4 Control Library Location and Naming During Build . . 22-7 Specify the Location of Precompiled Libraries . . . . . . . . . . 22-8 Control the Location of Model Reference Libraries . . . . . . . 22-9 Control the Suffix Applied to Library File Names . . . . . . . 22-10 Recompile Precompiled Libraries . . . . . . . . . . . . . . . . . . . 22-12 xxii Contents Customize Post-Code-Generation Build Processing . . . Build Information Object . . . . . . . . . . . . . . . . . . . . . . . . . . . Program a Post Code Generation Command . . . . . . . . . . . . Define a Post Code Generation Command . . . . . . . . . . . . . . Suppress Makefile Generation . . . . . . . . . . . . . . . . . . . . . . . 22-13 22-14 22-14 22-16 22-17 Configure Generated Code with TLC . . . . . . . . . . . . . . . . About Configuring Generated Code with TLC . . . . . . . . . . Assigning Target Language Compiler Variables . . . . . . . . Set Target Language Compiler Options . . . . . . . . . . . . . . . 22-18 22-18 22-18 22-20 Customize Build Process with STF_make_rtw_hook File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About the STF_make_rtw_hook File . . . . . . . . . . . . . . . . . . Conventions for Using the STF_make_rtw_hook File . . . . STF_make_rtw_hook.m Function Prototype and Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Applications for STF_make_rtw_hook.m . . . . . . . . . . . . . . . Control Code Regeneration Using STF_make_rtw_hook.m . . . . . . . . . . . . . . . . . . . . . . . . . . Use STF_make_rtw_hook.m for Your Build Procedure . . . Customize Build Process with sl_customization.m . . . . About sl_customization.m . . . . . . . . . . . . . . . . . . . . . . . . . . . Register Build Process Hook Functions Using sl_customization.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Variables Available for sl_customization.m Hook Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Example Build Process Customization Using sl_customization.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Replace the STF_rtw_info_hook Mechanism 22-21 22-21 22-21 22-22 22-25 22-26 22-27 22-28 22-28 22-30 22-31 22-31 . . . . . . . . . 22-33 Customize Build to Use Shared Utility Code . . . . . . . . . 22-34 Modify Template Makefiles to Support Shared Utilities . . 22-35 xxiii Run-Time Data Interface Extensions 23 Customize an ASAP2 File . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-2 About ASAP2 File Customization . . . . . . . . . . . . . . . . . . . . 23-2 ASAP2 File Structure on the MATLAB Path . . . . . . . . . . . 23-2 Customize the Contents of the ASAP2 File . . . . . . . . . . . . . 23-3 ASAP2 Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-4 Use GROUP and SUBGROUP Hierarchies to Organize Signals and Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . 23-6 Customize Computation Method Names . . . . . . . . . . . . . . . 23-12 Suppress Computation Methods for FIX_AXIS . . . . . . . . . . 23-13 Create a Transport Layer for External Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Creating a Transport Layer for External Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Design of External Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . External Mode Communications Overview . . . . . . . . . . . . . External Mode Source Files . . . . . . . . . . . . . . . . . . . . . . . . . Implement a Custom Transport Layer . . . . . . . . . . . . . . . . 23-14 23-14 23-14 23-17 23-19 23-23 Custom Target Development 24 xxiv Contents About Embedded Target Development . . . . . . . . . . . . . . . Custom Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Types of Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Recommended Features for Embedded Targets . . . . . . . . . 24-2 24-2 24-2 24-5 Sample Custom Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-9 Target Development Mechanics . . . . . . . . . . . . . . . . . . . . . Folder and File Naming Conventions . . . . . . . . . . . . . . . . . Components of a Custom Target . . . . . . . . . . . . . . . . . . . . . Key Folders Under Target Root (mytarget) . . . . . . . . . . . . . Key Files in Target Folder (mytarget/mytarget) . . . . . . . . . Additional Files for Externally Developed Targets . . . . . . . 24-11 24-11 24-12 24-17 24-20 24-28 Target Development and the Build Process . . . . . . . . . . . . 24-29 Customize System Target Files . . . . . . . . . . . . . . . . . . . . . Control Code Generation With the System Target File . . . System Target File Naming and Location Conventions . . . System Target File Structure . . . . . . . . . . . . . . . . . . . . . . . . Define and Display Custom Target Options . . . . . . . . . . . . Tips and Techniques for Customizing Your STF . . . . . . . . Create a Custom Target Configuration . . . . . . . . . . . . . . . . 24-36 24-36 24-37 24-37 24-46 24-54 24-61 Customize Template Makefiles . . . . . . . . . . . . . . . . . . . . . . Template Makefiles and Tokens . . . . . . . . . . . . . . . . . . . . . Invoke the make Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . Structure of the Template Makefile . . . . . . . . . . . . . . . . . . . Customize and Create Template Makefiles . . . . . . . . . . . . . 24-75 24-75 24-82 24-83 24-87 Support Optional Features . . . . . . . . . . . . . . . . . . . . . . . . . Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Support Model Referencing . . . . . . . . . . . . . . . . . . . . . . . . . Support Compiler Optimization Level Control . . . . . . . . . . Support firstTime Argument Control . . . . . . . . . . . . . . . . . Support C Function Prototype Control . . . . . . . . . . . . . . . . Support C++ Encapsulation Interface Control . . . . . . . . . . 24-100 24-100 24-101 24-115 24-117 24-119 24-121 Interface to Development Tools . . . . . . . . . . . . . . . . . . . . . About Interfacing to Development Tools . . . . . . . . . . . . . . . Makefile Approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interface to an Integrated Development Environment . . . . 24-123 24-123 24-124 24-124 Device Drivers and Target Preferences . . . . . . . . . . . . . . 24-135 Integrate Device Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-135 Use Target Preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-135 xxv Desktop IDEs and Desktop Targets Project and Build Configurations for Desktop Targets 25 Model Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-2 Block Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-2 Target Preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-3 Configuration Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . 25-7 Model Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-14 IDE Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Support for Third Party Products . . . . . . . . . . . . . . . . . . . . Third Party Product Setup . . . . . . . . . . . . . . . . . . . . . . . . . . Code Generation and Build . . . . . . . . . . . . . . . . . . . . . . . . . Automation of IDE Tasks and Processes . . . . . . . . . . . . . . . 25-16 25-16 25-16 25-16 25-17 Makefiles for Software Build Tool Chains . . . . . . . . . . . . What is the XMakefile Feature . . . . . . . . . . . . . . . . . . . . . . Using Makefiles to Generate and Build Software . . . . . . . . Making an XMakefile Configuration Operational . . . . . . . . Working with Microsoft Visual Studio . . . . . . . . . . . . . . . . . Creating a New XMakefile Configuration . . . . . . . . . . . . . . XMakefile User Configuration Dialog Box . . . . . . . . . . . . . 25-19 25-19 25-21 25-24 25-24 25-25 25-31 Verification Code Generated for Desktop Targets 26 Processor-in-the-Loop (PIL) Simulation . . . . . . . . . . . . . 26-2 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26-2 PIL Approaches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26-3 Communications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26-8 Running Your PIL Application to Perform Simulation and Verification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26-11 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26-11 xxvi Contents PIL Issues and Limitations . . . . . . . . . . . . . . . . . . . . . . . . . 26-12 Working with Eclipse IDE 27 Installing Third-Party Software for Eclipse . . . . . . . . . . Tested Software Versions . . . . . . . . . . . . . . . . . . . . . . . . . . . Installing Sun Java Runtime Environment (JRE) . . . . . . . Installing Eclipse IDE for C/C++ Developers . . . . . . . . . . . Verifying the GNU Tool Chain on Linux Host . . . . . . . . . . Installing the GNU Tool Chain on Windows . . . . . . . . . . . . 27-2 27-2 27-3 27-5 27-6 27-7 Configuring Your MathWorks Software to Work with Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27-10 Troubleshooting with Eclipse IDE . . . . . . . . . . . . . . . . . . . SIGSEGV Segmentation Fault for GDB . . . . . . . . . . . . . . . GDB Stops on Each Semaphore Post . . . . . . . . . . . . . . . . . . Build Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Profiling Not Available for Intel x86/Pentium and AMD K5/K6/Athlon Processors Running Windows or Linux Operating Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eclipse Message: “Can’t find a source file” . . . . . . . . . . . . . Eclipse Message: “Cannot access memory at address” . . . . Some Versions of Eclipse CDT Do Not Catch GCC Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27-14 27-14 27-14 27-15 27-15 27-15 27-16 27-16 Working with Linux Target 28 Disambiguation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28-2 Preparing Models to Run on Linux Target . . . . . . . . . . . 28-3 Scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28-4 xxvii Base Rate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Running Target Applications on Multicore Processors . . . . Running Multirate, Multitasking Executables on the Linux Desktop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Avoiding Lock-Up in Free-Running, Multirate, Multitasking Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28-4 28-4 28-11 28-12 Working with Microsoft Windows Target 29 Preparing Models to Run on Windows . . . . . . . . . . . . . . . 29-2 Scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-3 Selecting the Operating System and Scheduling Mode . . . 29-3 Base Rate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-4 Running Target Applications on Multicore Processors . . . . 29-4 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-10 Examples A xxviii Contents Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-2 Timing Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-3 Model Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-4 Data Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-5 Custom Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-6 S-Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-7 Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-8 External Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-9 Verification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-10 Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-11 Advanced Code Generation . . . . . . . . . . . . . . . . . . . . . . . . . A-12 Code Generation Using Makefiles . . . . . . . . . . . . . . . . . . . A-13 Index xxix xxx Contents Model Architecture and Design • Chapter 1, “Modeling” • Chapter 2, “Subsystems” • Chapter 3, “Referenced Models” • Chapter 4, “Combined Models” • Chapter 5, “Configure Model Parameters” • Chapter 6, “Model Protection” 1 Modeling • “Configure a Model for Code Generation” on page 1-2 • “Scheduling” on page 1-4 • “Supported Products and Block Usage” on page 1-92 • “Modeling Semantic Considerations” on page 1-117 1 Modeling Configure a Model for Code Generation Model configuration parameters determine the method for generating the code and the resulting format. 1 Open rtwdemo_throttlecntrl and save a copy as throttlecntrl in a writable location on your MATLAB path. Note This model uses Stateflow® software. 2 Open the Configuration Parameters dialog box Solver pane. To generate code for a model, you must configure the model to use a fixed-step solver. For this example, set the parameters as noted in the following table. 1-2 Parameter Setting Effect on Generated Code Type Fixed-step Maintains a constant (fixed) step size, which is required for code generation Solver discrete (no continuous states) Applies a fixed-step integration technique for computing the state derivative of the model Fixed-step size .001 Sets the base rate; must be the lowest common multiple of all rates in the system Configure a Model for Code Generation 3 Open the Code Generation pane and make sure that System target file is set to grt.tlc. Note The GRT (Generic Real-Time Target) configuration requires a fixed-step solver. However, the rsim.tlc system target file supports variable step code generation. The system target file (STF) defines a target, which is an environment for generating and building code for execution on a certain hardware or operating system platform. For example, one property of a target is code format. The grt configuration requires a fixed step solver and the rsim.tlc supports variable step code generation. 4 Open the Code Generation > Custom Code pane, and under Include list of additional, select Include directories. In the Include directories text field, enter: "$matlabroot$\toolbox\rtw\rtwdemos\EmbeddedCoderOverview\" This directory includes files that are required to build an executable for the model. 5 Apply your changes and close the dialog box. 1-3 1 Modeling Scheduling The following sections explain and illustrate how the Simulink® and Simulink Coder™ products handle multirate (mixed-rate) models, depending on whether code is being generated for single-tasking or multitasking environments. In this section... “About Scheduling” on page 1-4 “Single-Tasking and Multitasking Execution Modes” on page 1-5 “Handle Rate Transitions” on page 1-13 “Single-Tasking and Multitasking Model Execution” on page 1-27 “Handle Asynchronous Events” on page 1-34 “Timers” on page 1-79 “Configure Scheduling” on page 1-90 About Scheduling Simulink models run at one or more sample times. The Simulink product provides considerable flexibility in building multirate systems, that is, systems with more than one sample time. However, this same flexibility also allows you to construct models for which the code generator cannot generate real-time code for execution in a multitasking environment. To make multirate models operate as expected in real time (that is, to give the right answers), you sometimes must modify your model or instruct the Simulink engine to modify the model for you. In general, the modifications involve placing Rate Transition blocks between blocks that have unequal sample times. The following sections discuss issues you must address to use a multirate model in a multitasking environment. For a comprehensive discussion of sample times, including rate transitions, see “What Is Sample Time?”, “Sample Times in Subsystems”, “Sample Times in Systems”, “Resolve Rate Transitions”, and associated topics. 1-4 Scheduling Single-Tasking and Multitasking Execution Modes • “About Tasking Modes” on page 1-5 • “Execute Multitasking Models” on page 1-6 • “Multitasking and Pseudomultitasking Modes” on page 1-8 • “Build a Program for Multitasking Execution” on page 1-10 • “Single-Tasking Mode” on page 1-10 • “Build a Program for Single-Tasking Execution” on page 1-11 • “Model Execution and Rate Transitions” on page 1-11 • “Simulate Models with the Simulink Product” on page 1-12 • “Execute Models in Real Time” on page 1-12 • “Single-Tasking Versus Multitasking Operation” on page 1-13 About Tasking Modes There are two execution modes for a fixed-step Simulink model: single-tasking and multitasking. These modes are available only for fixed-step solvers. To select an execution mode, use the Tasking mode for periodic sample times menu on the Solver pane of the Configuration Parameters dialog box. Auto mode (the default) applies multitasking execution for a multirate model, and otherwise selects single-tasking execution. You can also select SingleTasking or MultiTasking execution explicitly. Execution of models in a real-time system can be done with the aid of a real-time operating system, or it can be done on a bare-board target, where the model runs in the context of an interrupt service routine (ISR). The fact that a system (such as The Open Group UNIX® or Microsoft® Windows® systems) is multitasking does not imply that your program can execute in real time. This is because the program might not preempt other processes when required. In operating systems (such as PC-DOS) where only one process can exist at any given time, an interrupt service routine (ISR) must perform the steps of saving the processor context, executing the model code, collecting data, and restoring the processor context. 1-5 1 Modeling Other operating systems, such as POSIX-compliant ones, provide automatic context switching and task scheduling. This simplifies the operations performed by the ISR. In this case, the ISR simply enables the model execution task, which is normally blocked. The next figure illustrates this difference. Real-Time Clock Hardware Interrupt Interrupt Service Routine Save Context Execute Model Program execution using an interrupt service routine (bareboard, with no real-time operating system). See the grt target for an example. Collect Data Restore Context Real-Time Clock Hardware Interrupt Interrupt Service Routine semGive Context Switch Model Execution Task semTake Execute Model Program execution using a real-time operating system primitive. See the Tornado raget for an example. Collect Data Execute Multitasking Models In cases where the continuous part of a model executes at a rate that is different from the discrete part, or a model has blocks with different sample 1-6 Scheduling rates, the Simulink engine assigns each block a task identifier (tid) to associate the block with the task that executes at the block’s sample rate. You set sample rates and their constraints on the Solver pane of the Configuration Parameters dialog box. To generate code with the Simulink Coder software, you must select Fixed-step for the solver type. Certain restrictions apply to the sample rates that you can use: • The sample rate of any block must be an integer multiple of the base (that is, the fastest) sample period. • When Periodic sample time constraint is unconstrained, the base sample period is determined by the Fixed step size specified on the Solvers pane of the Configuration parameters dialog box. • When Periodic sample time constraint is Specified, the base rate fixed-step size is the first element of the sample time matrix that you specify in the companion option Sample time properties. The Solver pane from the example model rtwdemo_mrmtbb shows an example. 1-7 1 Modeling • Continuous blocks always execute by using an integration algorithm that runs at the base sample rate. The base sample period is the greatest common denominator of all rates in the model only when Periodic sample time constraint is set to Unconstrained and Fixed step size is Auto. • The continuous and discrete parts of the model can execute at different rates only if the discrete part is executed at the same or a slower rate than the continuous part and is an integer multiple of the base sample rate. Multitasking and Pseudomultitasking Modes When periodic tasks execute in a multitasking mode, by default the blocks with the fastest sample rates are executed by the task with the highest priority, the next fastest blocks are executed by a task with the next higher priority, and so on. Time available in between the processing of high-priority tasks is used for processing lower priority tasks. This results in efficient program execution. Where tasks are asynchronous rather than periodic, there may not necessarily be a relationship between sample rates and task priorities; the task with the highest priority need not have the fastest sample rate. You specify asynchronous task priorities using Async Interrupt and Task Sync blocks. You can switch the sense of what priority numbers mean by selecting or deselecting the Solver option Higher priority value indicates higher task priority. In multitasking environments (that is, under a real-time operating system), you can define separate tasks and assign them priorities. In a bare-board target (that is, no real-time operating system present), you cannot create separate tasks. However, Simulink Coder application modules implement what is effectively a multitasking execution scheme using overlapped interrupts, accompanied by programmatic context switching. This means an interrupt can occur while another interrupt is currently in progress. When this happens, the current interrupt is preempted, the floating-point unit (FPU) context is saved, and the higher priority interrupt executes its higher priority (that is, faster sample rate) code. Once complete, control is returned to the preempted ISR. 1-8 Scheduling The next figures illustrate how timing of tasks in multirate systems are handled by the Simulink Coder software in multitasking, pseudomultitasking, and single-tasking environments. t0 t1 t2 t3 t4 rate 1 Highest Priority rate 2 rate 3 Lowest Priority Vertical arrows indicate sample time hits. Dotted lines with downward pointing arrows indicate the release of control to a lower priority task. Dotted lines with upward pointing arrows indicate preemption by a higher priority task. Dark gray areas indicate task execution. Hashed areas indicate task preemption by a higher priority task. Light gray areas indicate task execution is pending. The next figure shows how overlapped interrupts are used to implement pseudomultitasking. In this case, Interrupt 0 does not return until after Interrupts 1, 2, and 3. 1-9 1 Modeling Interrupt 0 Begins t0 Interrupt 1 t1 Interrupt 2 Begins Interrupt 1 Ends t2 Interrupt 3 t3 Interrupt 3 Ends t4 Highest Priority Interrupt 2 Ends Interrupt 0 Ends Lowest Priority Build a Program for Multitasking Execution To use multitasking execution, select Auto (the default) or MultiTasking from the Tasking mode for periodic sample times menu on the Solver pane of the Configuration Parameters dialog box. This menu is active only if you select Fixed-step as the solver type. Auto mode results in a multitasking environment if your model has two or more different sample times. A model with a continuous and a discrete sample time runs in single-tasking mode if the fixed-step size is equal to the discrete sample time. Single-Tasking Mode You can execute model code in a strictly single-tasking manner. While this mode is less efficient with regard to execution speed, in certain situations, it can simplify your model. In single-tasking mode, the base sample rate must define a time interval that is long enough to allow the execution of all blocks within that interval. 1-10 Scheduling The next figure illustrates the inefficiency inherent in single-tasking execution. t0 t1 t2 t3 t4 Single-tasking system execution requires a base sample rate that is long enough to execute one step through the entire model. Build a Program for Single-Tasking Execution To use single-tasking execution, select SingleTasking from the Tasking mode for periodic sample times menu on the Solver pane of the Configuration Parameters dialog box. If you select Auto, single-tasking is used in the following cases: • If your model contains one sample time • If your model contains a continuous and a discrete sample time and the fixed step size is equal to the discrete sample time Model Execution and Rate Transitions To generate code that executes as expected in real time, you (or the Simulink engine) might need to identify and handle sample rate transitions within the model. In multitasking mode, by default the Simulink engine flags errors during simulation if the model contains invalid rate transitions, although you can use the Multitask rate transition diagnostic to alter this behavior. A similar diagnostic, called Single task rate transition, exists for single-tasking mode. To avoid raising rate transition errors, insert Rate Transition blocks between tasks. You can request that the Simulink engine handle rate transitions automatically by inserting hidden Rate Transition blocks. See “Automatic Rate Transition” on page 1-20 for an explanation of this option. To understand such problems, first consider how Simulink simulations differ from real-time programs. 1-11 1 Modeling Simulate Models with the Simulink Product Before the Simulink engine simulates a model, it orders the blocks based upon their topological dependencies. This includes expanding virtual subsystems into the individual blocks they contain and flattening the entire model into a single list. Once this step is complete, each block is executed in order. The key to this process is the ordering of blocks. Any block whose output is directly dependent on its input (that is, any block with direct feedthrough) cannot execute until the block driving its input executes. Some blocks set their outputs based on values acquired in a previous time step or from initial conditions specified as a block parameter. The output of such a block is determined by a value stored in memory, which can be updated independently of its input. During simulation, computations are performed prior to advancing the variable corresponding to time. In essence, this results in computations occurring instantaneously (that is, no computational delay). Execute Models in Real Time A real-time program differs from a Simulink simulation in that the program must execute the model code synchronously with real time. Every calculation results in some computational delay. This means the sample intervals cannot be shortened or lengthened (as they can be in a Simulink simulation), which leads to less efficient execution. Consider the following timing figure. t0 t1 t2 Time Note the processing inefficiency in the sample interval t1. That interval cannot be compressed to increase execution speed because, by definition, sample times are clocked in real time. 1-12 Scheduling You can circumvent this potential inefficiency by using the multitasking mode. The multitasking mode defines tasks with different priorities to execute parts of the model code that have different sample rates. See “Multitasking and Pseudomultitasking Modes” on page 1-8 for a description of how this works. It is important to understand that section before proceeding here. Single-Tasking Versus Multitasking Operation Single-tasking programs require longer sample intervals, because all computations must be executed within each clock period. This can result in inefficient use of available CPU time, as shown in the previous figure. Multitasking mode can improve the efficiency of your program if the model is large and has many blocks executing at each rate. However, if your model is dominated by a single rate, and only a few blocks execute at a slower rate, multitasking can actually degrade performance. In such a model, the overhead incurred in task switching can be greater than the time required to execute the slower blocks. In this case, it is more efficient to execute all blocks at the dominant rate. If you have a model that can benefit from multitasking execution, you might need to modify your model by adding Rate Transition blocks (or instruct the Simulink engine to do so) to generate expected results. The next section, “Handle Rate Transitions” on page 1-13, discusses issues related to rate transition blocks. Handle Rate Transitions • “About Rate Transitions” on page 1-14 • “Data Transfer Problems” on page 1-15 • “Data Transfer Assumptions” on page 1-16 • “Rate Transition Block Options” on page 1-17 • “Faster to Slower Transitions in a Simulink Model” on page 1-22 • “Faster to Slower Transitions in Real Time” on page 1-23 1-13 1 Modeling • “Slower to Faster Transitions in a Simulink Model” on page 1-24 • “Slower to Faster Transitions in Real Time” on page 1-25 About Rate Transitions Two periodic sample rate transitions can exist within a model: • A faster block driving a slower block • A slower block driving a faster block The following sections concern models with periodic sample times with zero offset only. Other considerations apply to multirate models that involve asynchronous tasks. For details on how to generate code for asynchronous multitasking, see “Handle Asynchronous Events” on page 1-34. In single-tasking systems, there are no issues involving multiple sample rates. In multitasking and pseudomultitasking systems, however, differing sample rates can cause problems by causing blocks to be executed in the wrong order. To prevent possible errors in calculated data, you must control model execution at these transitions. When connecting faster and slower blocks, you or the Simulink engine must add Rate Transition blocks between them. Fast-to-slow transitions are illustrated in the next figure. T = 1s Faster Block T = 2s Slower Block becomes T = 1s Faster Block 1-14 Port-based: Tin = 1s; Tout = 2s Rate Transition T = 2s Slower Block Scheduling Slow-to-fast transitions are illustrated in the next figure. T = 2s T = 1s Slower Block Faster Block becomes T = 2s Slower Block Port-based: Tin = 2s; Tout = 1s Rate Transition T = 1s Faster Block Note Although the Rate Transition block offers a superset of the capabilities of the Unit Delay block (for slow-to-fast transitions) and the Zero-Order Hold block (for fast-to-slow transitions), you should use the Rate Transition block instead of these blocks. Data Transfer Problems Rate Transition blocks deal with issues of data integrity and determinism associated with data transfer between blocks running at different rates. • Data integrity: A problem of data integrity exists when the input to a block changes during the execution of that block. Data integrity problems can be caused by preemption. Consider the following scenario: - A faster block supplies the input to a slower block. The slower block reads an input value V1 from the faster block and begins computations using that value. 1-15 1 Modeling - The computations are preempted by another execution of the faster block, which computes a new output value V2. - A data integrity problem now arises: when the slower block resumes execution, it continues its computations, now using the “new” input value V2. Such a data transfer is called unprotected. “Faster to Slower Transitions in Real Time” on page 1-23 shows an unprotected data transfer. In a protected data transfer, the output V1 of the faster block is held until the slower block finishes executing. • Deterministic versus nondeterministic data transfer: In a deterministic data transfer, the timing of the data transfer is completely predictable, as determined by the sample rates of the blocks. The timing of a nondeterministic data transfer depends on the availability of data, the sample rates of the blocks, and the time at which the receiving block begins to execute relative to the driving block. You can use the Rate Transition block to protect data transfers in your application and make them deterministic. These characteristics are considered desirable in most applications. However, the Rate Transition block supports flexible options that allow you to compromise data integrity and determinism in favor of lower latency. The next section summarizes these options. Data Transfer Assumptions When processing data transfers between tasks, the Simulink Coder software assumes the following: • Data transitions occur between a single reading task and a single writing task. • A read or write of a byte-sized variable is atomic. • When two tasks interact through a data transition, only one of them can preempt the other. • For periodic tasks, the faster rate task has higher priority than the slower rate task; the faster rate task always preempts the slower rate task. 1-16 Scheduling • All tasks run on a single processor. Time slicing is not allowed. • Processes do not crash or restart (especially while data is transferred between tasks). Rate Transition Block Options Several parameters of the Rate Transition block are relevant to its use in code generation for real-time execution, as discussed below. For a complete block description, see Rate Transition in the Simulink documentation. The Rate Transition block handles periodic (fast to slow and slow to fast) and asynchronous transitions. When inserted between two blocks of differing sample rates, the Rate Transition block automatically configures its input and output sample rates for the type of transition; you do not need to specify whether a transition is slow-to-fast or fast-to-slow (low-to-high or high-to-low priorities for asynchronous tasks). The critical decision you must make in configuring a Rate Transition block is the choice of data transfer mechanism to be used between the two rates. Your choice is dictated by considerations of safety, memory usage, and performance. As the Rate Transition block parameter dialog box in the next figure shows, the data transfer mechanism is controlled by two options. 1-17 1 Modeling • Ensure data integrity during data transfer: When this option is on, data transferred between rates maintains its integrity (the data transfer is protected). When this option is off, the data might not maintain its integrity (the data transfer is unprotected). By default, Ensure data integrity during data transfer is on. • Ensure deterministic data transfer (maximum delay): This option is supported for periodic tasks with an offset of zero and fast and slow rates that are multiples of each other. Enable this option for protected data transfers (when Ensure data integrity during data transfer is on). When this option is on, the Rate Transition block behaves like a Zero-Order Hold block (for fast to slow transitions) or a Unit Delay block (for slow to fast transitions). The Rate Transition block controls the timing of data transfer in a completely predictable way. When this option is off, the data transfer is nondeterministic. By default, Ensure deterministic data 1-18 Scheduling transfer (maximum delay) is on for transitions between periodic rates with an offset of zero; for asynchronous transitions, it cannot be selected. Thus the Rate Transition block offers three modes of operation with respect to data transfer. In order of level of safety: • Protected/Deterministic (default): This is the safest mode. The drawback of this mode is that it introduces deterministic latency into the system for the case of slow-to-fast periodic rate transitions. For that case, the latency introduced by the Rate Transition block is one sample period of the slower task. For the case of fast-to-slow periodic rate transitions, the Rate Transition block introduces no additional latency. • Protected/NonDeterministic: In this mode, for slow-to-fast periodic rate transitions, data integrity is protected by double-buffering data transferred between rates. For fast-to-slow periodic rate transitions, a semaphore flag is used. The blocks downstream from the Rate Transition block always use the latest available data from the block that drives the Rate Transition block. Maximum latency is less than or equal to one sample period of the faster task. The drawbacks of this mode are its nondeterministic timing. The advantage of this mode is its low latency. • Unprotected/NonDeterministic: This mode is not recommended for mission-critical applications. The latency of this mode is the same as for Protected/NonDeterministic mode, but memory requirements are reduced since neither double-buffering nor semaphores are required. That is, the Rate Transition block does nothing in this mode other than to pass signals through; it simply exists to notify you that a rate transition exists (and can cause generated code to compute incorrect answers). Selecting this mode, however, generates the least amount of code. Note In unprotected mode (Ensure data integrity during data transfer option off), the Rate Transition block does nothing other than allow the rate transition to exist in the model. 1-19 1 Modeling Automatic Rate Transition. The Simulink engine can detect mismatched rate transitions in a multitasking model and automatically insert Rate Transition blocks to handle them. To instruct the engine to do this, select Automatically handle rate transition for data transfer on the Solver pane of the Configuration Parameters dialog box. The Automatically handle rate transition for data transfer option is off by default. When you select it, • The Simulink engine handles transitions between periodic sample times and asynchronous tasks. • The Simulink engine inserts “hidden” Rate Transition blocks that are not visible on the block diagram. • The Simulink Coder software generates code for the automatically inserted Rate Transition blocks that is identical to that generated for manually inserted Rate Transition blocks. • Automatically inserted Rate Transition blocks operate in protected mode for periodic tasks and asynchronous tasks, which you cannot alter. For periodic tasks, automatically inserted Rate Transition blocks operate with the level of determinism specified by the Solver pane parameter Deterministic data transfer. (The default setting is Whenever possible, which enables determinism for data transfers between periodic sample-times that are related by an integer multiple; for more information, see “Deterministic data transfer” in the Simulink reference documentation.) To use other modes, you must insert Rate Transition blocks and set their modes manually. For example, in the following model SineWave2 has a Sample time of 2, and SineWave3 has a Sample time of 3. 1-20 Scheduling If Automatically handle rate transition for data transfer is on, the Simulink engine inserts an invisible Rate Transition block between each Sine Wave block and the Product block. The inserted blocks have the parameter values required to reconcile the Sine Wave block sample times. Inserted Rate Transition Block HTML Report When the Simulink engine has automatically inserted Rate Transition blocks into a model, after code generation the optional HTML code generation report includes a List of inserted blocks that describes the blocks. For example, the following report describes the two Rate Transition blocks that the engine automatically inserts into the previous model. Only automatically inserted Rate Transition blocks appear in a List of inserted blocks. If no such blocks exist in a model, the HTML code generation report does not include a List of inserted blocks. 1-21 1 Modeling Rate Transition Blocks and Continuous Time. The sample time at the output port of a Rate Transition block can only be discrete or fixed in minor time step. This means that when a Rate Transition block inherits continuous sample time from its destination block, it treats the inherited sample time as Fixed in Minor Time Step. Therefore, the output function of the Rate Transition block runs only at major time steps. If the destination block sample time is continuous, Rate Transition block output sample time is the base rate sample time (if solver is fixed-step), or zero-order-hold-continuous sample time (if solver is variable-step). The next four sections describe cases in which Rate Transition blocks are required for periodic sample rate transitions. The discussion and timing diagrams in these sections are based on the assumption that the Rate Transition block is used in its default (protected/deterministic) mode; that is, the Ensure data integrity during data transfer and Ensure deterministic data transfer (maximum delay) options are both on. These are the settings used for automatically inserted Rate Transition blocks. Faster to Slower Transitions in a Simulink Model In a model where a faster block drives a slower block having direct feedthrough, the outputs of the faster block are always computed first. In simulation intervals where the slower block does not execute, the simulation progresses more rapidly because there are fewer blocks to execute. The next figure illustrates this situation. t1 t0 T = 1s Faster Block T = 2s Slower Block T = 1s T = 2s t2 T = 1s T = 1s t3 T = 2s T = 1s Time A Simulink simulation does not execute in real time, which means that it is not bound by real-time constraints. The simulation waits for, or moves ahead to, whatever tasks are required to complete simulation flow. The actual time interval between sample time steps can vary. 1-22 Scheduling Faster to Slower Transitions in Real Time In models where a faster block drives a slower block, you must compensate for the fact that execution of the slower block might span more than one execution period of the faster block. This means that the outputs of the faster block can change before the slower block has finished computing its outputs. The next figure shows a situation in which this problem arises (T = sample time). Note that lower priority tasks are preempted by higher priority tasks before completion. T = 1s Faster Block T = 2s Slower Block 2 Sec Task 1 Sec Task 1 T=1s T=2s 2 1 T=1s 3 T=1s T=2s 2 T=1s 3 Time 1 The faster task (T=1s) completes. 2 Higher priority preemption occurs. 3 The slower task (T=2s) resumes and its inputs have changed. This leads to unpredictable results. In the above figure, the faster block executes a second time before the slower block has completed execution. This can cause unpredictable results because the input data to the slow task is changing. Data might not maintain its integrity in this situation. To avoid this situation, the Simulink engine must hold the outputs of the 1 second (faster) block until the 2 second (slower) block finishes executing. The way to accomplish this is by inserting a Rate Transition block between the 1 second and 2 second blocks. The input to the slower block does not change during its execution, maintaining data integrity. 1-23 1 Modeling T=1s Faster Block Tin = 1Tout = 2 T=2s Rate Transition Slower Block It is assumed that the Rate Transition block is used in its default (protected/deterministic) mode. The Rate Transition block executes at the sample rate of the slower block, but with the priority of the faster block. t0 t2 2 Sec Task T=2s t0 1 Sec Task T=2s t1 T=1s RT t2 T=1s t3 T=1s RT T=1s Time When you add a Rate Transition block, the block executes before the 2 second block (its priority is higher) and its output value is held constant while the 2 second block executes (it executes at the slower sample rate). Slower to Faster Transitions in a Simulink Model In a model where a slower block drives a faster block, the Simulink engine again computes the output of the driving block first. During sample intervals where only the faster block executes, the simulation progresses more rapidly. The next figure shows the execution sequence. 1-24 Scheduling t1 t0 T = 2s T = 1s Slower Block T = 2s Faster Block t2 T = 1s T = 1s t3 T = 2s T = 1s T = 1s Time As you can see from the preceding figures, the Simulink engine can simulate models with multiple sample rates in an efficient manner. However, a Simulink simulation does not operate in real time. Slower to Faster Transitions in Real Time In models where a slower block drives a faster block, the generated code assigns the faster block a higher priority than the slower block. This means the faster block is executed before the slower block, which requires special care to avoid incorrect results. t0 2 Sec Task T = 2s Block T = 1s Faster Block T=2s T=2s 1 t0 1 Sec Task t2 T=1s 2 t1 T=1s 1 t2 T=1s t3 2 T=1s t4 T=1s Time 1 The faster block executes a second time prior to the completion of the slower block. 2 The faster block executes before the slower block. This timing diagram illustrates two problems: • Execution of the slower block is split over more than one faster block interval. In this case the faster task executes a second time before the 1-25 1 Modeling slower task has completed execution. This means the inputs to the faster task can have incorrect values some of the time. • The faster block executes before the slower block (which is backward from the way a Simulink simulation operates). In this case, the 1 second block executes first; but the inputs to the faster task have not been computed. This can cause unpredictable results. To eliminate these problems, you must insert a Rate Transition block between the slower and faster blocks. T = 2s T = 1s Tin = 2 Tout = 1 Slower Block Faster Block Rate Transition It is assumed that the Rate Transition block is used in its default (protected/deterministic) mode. The next figure shows the timing sequence that results with the added Rate Transition block. 2 2 Sec Task RT update T=2s t1 t0 1 Sec Task RT output T=1s T=1s Time 1-26 t3 t2 1 1 1 3 RT update T=2s RT output T=1s 1 T=1s Scheduling Three key points about transitions in this diagram (refer to circled numbers): 1 The Rate Transition block output runs in the 1 second task, but at a slower rate (2 seconds). The output of the Rate Transition block feeds the 1 second task blocks. 2 The Rate Transition update uses the output of the 2 second task to update its internal state. 3 The Rate Transition output in the 1 second task uses the state of the Rate Transition that was updated in the 2 second task. The first problem is alleviated because the Rate Transition block is updating at a slower rate and at the priority of the slower block. The input to the Rate Transition block (which is the output of the slower block) is read after the slower block completes executing. The second problem is alleviated because the Rate Transition block executes at a slower rate and its output does not change during the computation of the faster block it is driving. The output portion of a Rate Transition block is executed at the sample rate of the slower block, but with the priority of the faster block. Since the Rate Transition block drives the faster block and has effectively the same priority, it is executed before the faster block. Note This use of the Rate Transition block changes the model. The output of the slower block is now delayed by one time step compared to the output without a Rate Transition block. Single-Tasking and Multitasking Model Execution • “Introduction” on page 1-28 • “Single-Tasking Execution” on page 1-28 • “Multitasking Execution” on page 1-31 1-27 1 Modeling Introduction This section examines how a simple multirate model executes in both real time and simulation, using a fixed-step solver. It considers the operation of both SingleTasking and MultiTasking Solver pane tasking modes. The example model is shown in the next figure. The discussion refers to the six blocks of the model as A through F, as labeled in the block diagram. The execution order of the blocks (indicated in the upper right of each block) has been forced into the order shown by assigning higher priorities to blocks F, E, and D. The ordering shown is one possible valid execution ordering for this model. (See “Simulating Dynamic Systems” in the Simulink documentation.) The execution order is determined by data dependencies between blocks. In a real-time system, the execution order determines the order in which blocks execute within a given time interval or task. This discussion treats the model’s execution order as a given, because it is concerned with the allocation of block computations to tasks, and the scheduling of task execution. Note The discussion and timing diagrams in this section are based on the assumption that the Rate Transition blocks are used in the default (protected/deterministic) mode, with the Ensure data integrity during data transfer and Ensure deterministic data transfer (maximum delay) options on. Single-Tasking Execution This section considers the execution of the above model when the solver Tasking mode is SingleTasking. 1-28 Scheduling In a single-tasking system, if the Block reduction option on the Optimization pane is on, fast-to-slow Rate Transition blocks are optimized out of the model. The default case is shown (Block reduction on), so block B does not appear in the timing diagrams in this section. For more information, see “Block reduction”. The following table shows, for each block in the model, the execution order, sample time, and whether the block has an output or update computation. Block A does not have discrete states, and accordingly does not have an update computation. Execution Order and Sample Times (Single-Tasking) Blocks (in Execution Order) Sample Time (in Seconds) Output Update F 0.1 Y Y E 0.1 Y Y D 1 Y Y A 0.1 Y N C 1 Y Y Real-Time Single-Tasking Execution. The next figure shows the scheduling of computations when the generated code is deployed in a real-time system. The generated program is shown running in real time, under control of interrupts from a 10 Hz timer. 1-29 1 Modeling Output: FEDAC FEA (wait) FEDC Update: FEDAC FEA (wait) FE FE ... FEDC ... Time: 0.0 0.1 0.2 ... 1.0 At time 0.0, 1.0, and every second thereafter, both the slow and fast blocks execute their output computations; this is followed by update computations for blocks that have states. Within a given time interval, output and update computations are sequenced in block execution order. The fast blocks execute on every tick, at intervals of 0.1 second. Output computations are followed by update computations. The system spends some portion of each time interval (labeled “wait”) idling. During the intervals when only the fast blocks execute, a larger portion of the interval is spent idling. This illustrates an inherent inefficiency of single-tasking mode. Simulated Single-Tasking Execution. The next figure shows the execution of the model during the Simulink simulation loop. Output: Update: Time: 0.0 1-30 FEA FEDAC FEDC 0.1 FEA FE 0.2 FEDAC FE .. ... F E D C ... ... ... 1.0 Scheduling Because time is simulated, the placement of ticks represents the iterations of the simulation loop. Blocks execute in exactly the same order as in the previous figure, but without the constraint of a real-time clock. Therefore there is no idle time between simulated sample periods. Multitasking Execution This section considers the execution of the above model when the solver Tasking mode is MultiTasking. Block computations are executed under two tasks, prioritized by rate: • The slower task, which gets the lower priority, is scheduled to run every second. This is called the 1 second task. • The faster task, which gets higher priority, is scheduled to run 10 times per second. This is called the 0.1 second task. The 0.1 second task can preempt the 1 second task. The following table shows, for each block in the model, the execution order, the task under which the block runs, and whether the block has an output or update computation. Blocks A and B do not have discrete states, and accordingly do not have an update computation. Task Allocation of Blocks in Multitasking Execution Blocks (in Execution Order) Task Output Update F 0.1 second task Y Y E 0.1 second task Y Y 1-31 1 Modeling Task Allocation of Blocks in Multitasking Execution (Continued) Blocks (in Execution Order) Task Output Update D The Rate Transition block uses port-based sample times. Output runs at the output port sample time under 0.1 second task. Update runs at input port sample time under 1 second task. For more information on port-based sample times, see “Inherit Sample Times” in the Simulink documentation. Y Y A 0.1 second task Y N B The Rate Transition block uses port-based sample times. Output runs at the output port sample time under 0.1 second task. For more information on port-based sample times, see “Inherit Sample Times” in the Simulink documentation. Y N C 1 second task Y Y Real-Time Multitasking Execution. The next figure shows the scheduling of computations in MultiTasking solver mode when the generated code is deployed in a real-time system. The generated program is shown running in real time, as two tasks under control of interrupts from a 10 Hz timer. 1-32 Scheduling 1 SECOND Output: C C preemption preemption Update: C ... DC ... Time: 0.0 1.0 0.1 SECOND Output: FEDAB Update: FEA FE FEA FE (wait) FEA FEDAB FE ... FE ... Time: 0.0 0.1 0.2 1.0 1.1 Simulated Multitasking Execution. The next figure shows the Simulink execution of the same model, in MultiTasking solver mode. In this case, the Simulink engine runs the blocks in one thread of execution, simulating multitasking. No preemption occurs. 1-33 1 Modeling 1 SECOND BLOCKS Output: C C Update: DC DC ... Time: 0.0 1.0 0.1 SECOND BLOCKS Output: F E D A B Update: FE FE F E DA FEA FEA F ... FEA FE ... Time: 0.0 0.1 0.2 1.0 Handle Asynchronous Events • “About Asynchronous Events” on page 1-35 • “Handling Interrupts” on page 1-37 • “Rate Transitions and Asynchronous Blocks” on page 1-53 • “Use Timers in Asynchronous Tasks” on page 1-58 • “Create a Customized Asynchronous Library” on page 1-60 • “Import Asynchronous Event Data for Simulation” on page 1-69 • “Asynchronous Support Limitations” on page 1-74 1-34 1.1 Scheduling About Asynchronous Events • “Asynchronous Support” on page 1-35 • “Block Library for Wind River Systems VxWorks Real-Time Operating System” on page 1-35 • “Access the VxWorks Block Library” on page 1-36 • “Generate Code with the VxWorks Library Blocks” on page 1-37 • “Examples and Additional Information” on page 1-37 Asynchronous Support. Simulink Coder models are normally timed from a periodic interrupt source (for example, a hardware timer). Blocks in a periodically clocked single-rate model run at a timer interrupt rate (the base rate of the model). Blocks in a periodically clocked multirate model run at the base rate or at submultiples of that rate. Many systems must also support execution of blocks in response to events that are asynchronous with respect to the periodic timing source of the system. For example, a peripheral device might signal completion of an input operation by generating an interrupt. The system must service such interrupts, for example, by acquiring data from the interrupting device. This chapter explains how to use blocks to model and generate code for asynchronous event handling, including servicing of hardware-generated interrupts, maintenance of timers, asynchronous read and write operations, and spawning of asynchronous tasks under a real-time operating system (RTOS). Although the blocks target the Wind River® Systems VxWorks® Tornado® RTOS, this chapter provides source code analysis and other information you can use to develop blocks that support asynchronous event handling for an alternative target RTOS. Block Library for Wind River Systems VxWorks Real-Time Operating System. The next figure shows the blocks in the VxWorks block library (vxlib1). 1-35 1 Modeling The key blocks in the library are the Async Interrupt and Task Sync blocks. These blocks are targeted for the VxWorks Tornado operating system. You can use them, without modification, to support VxWorks applications. If you want to implement asynchronous support for an RTOS other than VxWorks RTOS, guidelines and example code are provided that will help you to adapt the VxWorks library blocks to target your RTOS. This topic is discussed in “Create a Customized Asynchronous Library” on page 1-60. The VxWorks library includes blocks you can use to • Generate interrupt-level code — Async Interrupt block • Spawn a VxWorks task that calls a function call subsystem — Task Sync block • Enable data integrity when transferring data between blocks running as different tasks — Protected RT block • Use an unprotected/nondeterministic mode when transferring data between blocks running as different tasks — Unprotected RT block The use of protected and unprotected Rate Transition blocks in asynchronous contexts is discussed in “Rate Transitions and Asynchronous Blocks” on page 1-53. For general information on rate transitions, see “Scheduling” on page 1-4. Access the VxWorks Block Library. To access the VxWorks library, enter the MATLAB® command vxlib1. 1-36 Scheduling Generate Code with the VxWorks Library Blocks. To generate a VxWorks compatible application from a model containing VxWorks library blocks, select one of the following targets from the System Target File Browser associated with the model: • ert.tlc Embedded Coder. This target is provided with the Embedded Coder™ product. When using the ERT target with VxWorks library blocks, you must select the Generate an example main program option, and select VxWorksExample from the Target operating system menu. • tornado.tlc Tornado (VxWorks) Real-Time Target. Examples and Additional Information. Additional information relevant to the topics in this chapter can be found in • The rtwdemo_async model. To open this example, type rtwdemo_async at the MATLAB command prompt. • The rtwdemo_async_mdlreftop model. To open this example, type rtwdemo_async_mdlreftop at the MATLAB command prompt. • “Scheduling” on page 1-4, discusses general multitasking and rate transition issues for periodic models. • The Embedded Coder documentation discusses the Embedded Real-Time (ERT) target, including task execution and scheduling. • See your VxWorks system documentation for detailed information about the VxWorks system calls mentioned in this chapter. Handling Interrupts • “Generate Interrupt Service Routines” on page 1-37 • “Spawn a Wind River Systems VxWorks Task” on page 1-46 Generate Interrupt Service Routines. To generate an interrupt service routine (ISR) associated with a specific Wind River Systems VxWorks VME interrupt level, use the Async Interrupt block. The Async Interrupt block enables the specified interrupt level and installs an ISR that calls a connected function call subsystem. 1-37 1 Modeling You can also use the Async Interrupt block in a simulation. It provides an input port that can be enabled and connected to a simulated interrupt source. Connecting the Async Interrupt Block To generate an ISR, connect an output of the Async Interrupt block to the control input of • A function call subsystem • The input of a Task Sync block • The input to a Stateflow chart configured for a function call input event The next figure shows an Async Interrupt block configured to service two interrupt sources. The outputs (signal width 2) are connected to two function call subsystems. Requirements and Restrictions Note the following requirements and restrictions: • The Async Interrupt block supports VME interrupts 1 through 7. 1-38 Scheduling • The Async Interrupt block requires a VxWorks Board Support Package (BSP) that supports the following VxWorks system calls: - sysIntEnable sysIntDisable intConnect intLock intUnlock tickGet Performance Considerations Execution of large subsystems at interrupt level can have a significant impact on interrupt response time for interrupts of equal and lower priority in the system. As a general rule, it is best to keep ISRs as short as possible. Connect only function call subsystems that contain a small number of blocks to an Async Interrupt block. A better solution for large subsystems is to use the Task Sync block to synchronize the execution of the function call subsystem to a VxWorks task. The Task Sync block is placed between the Async Interrupt block and the function call subsystem. The Async Interrupt block then installs the Task Sync block as the ISR. The ISR releases a synchronization semaphore (performs a semGive) to the task, and returns immediately from interrupt level. The task is then scheduled and run by the VxWorks RTOS. See “Spawn a Wind River Systems VxWorks Task” on page 1-46 for more information. Using the Async Interrupt Block in Simulation and Code Generation This section describes a dual-model approach to the development and implementation of real-time systems that include ISRs. In this approach, you develop one model that includes a plant and a controller for simulation, and another model that only includes the controller for code generation. Using a Simulink library, you can implement changes to both models simultaneously. The next figure shows how changes made to the plant or controller, both of which are in a library, are propagated to the models. 1-39 1 Modeling Plant Controller Library: Changes made here affect both models. Plant Interrupt Block (Simulation input enabled) Interrupt Block Simulink Coder library Interrupt Block Model (for simulation) Controller Model (for code generation) Controller Dual-Model Use of Async Interrupt Block for Simulation and Code Generation A single-model approach is also possible. In this approach, the Plant component of the model is active only in simulation. During code generation, the Plant components are effectively switched out of the system and code is generated only for the interrupt block and controller parts of the model. For an example of this approach, see the rtwdemo_async model. Dual-Model Approach: Simulation The following block diagram shows a simple model that illustrates the dual-model approach to modeling. During simulation, the Pulse Generator blocks provide simulated interrupt signals. 1-40 Scheduling The simulated interrupt signals are routed through the Async Interrupt block’s input port. Upon receiving a simulated interrupt, the block calls the connected subsystem. During simulation, subsystems connected to Async Interrupt block outputs are executed in order of their VxWorks priority. In the event that two or more interrupt signals occur simultaneously, the Async Interrupt block executes the downstream systems in the order specified by their interrupt levels (level 7 gets the highest priority). The first input element maps to the first output element. You can also use the Async Interrupt block in a simulation without enabling the simulation input. In such a case, the Async Interrupt block inherits the base rate of the model and calls the connected subsystems in order of their VxWorks priorities. (In effect, in this case the Async Interrupt block behaves as if all inputs received a 1 simultaneously.) Dual-Model Approach: Code Generation In the generated code for the sample model, • Ground blocks provide input signals to the Environment Controller block • The Async Interrupt block does not use its simulation input 1-41 1 Modeling The Ground blocks drive control input of the Environment Controller block so no code is generated for that signal path. The Simulink Coder code generator does not generate code for blocks that drive the simulation control input to the Environment Controller block because that path is not selected during code generation. However, the sample times of driving blocks for the simulation input to the Environment Controller block contribute to the sample times supported in the generated code. To avoid including unnecessary sample times in the generated code, use the sample times of the blocks driving the simulation input in the model where generated code is intended. Standalone functions are installed as ISRs and the interrupt vector table is as follows: Offset 192 &isr_num1_vec192() 193 &isr_num2_vec193() Consider the code generated from this model, assuming that the Async Interrupt block parameters are configured as shown in the next figure. 1-42 Scheduling Initialization Code In the generated code, the Async Interrupt block installs the code in the Subsystem blocks as interrupt service routines. The interrupt vectors for IRQ1 and IRQ2 are stored at locations 192 and 193 relative to the base of the interrupt vector table, as specified by the VME interrupt vector offset(s) parameter. Installing an ISR requires two VxWorks calls, int_connect and sysInt_Enable. The Async Interrupt block inserts these calls in the model_initialize function, as shown in the following code excerpt. /* VxWorks Interrupt Block: '/Async Interrupt' */ /* Connect and enable ISR function: isr_num1_vec192 */ if( intConnect(INUM_TO_IVEC(192), isr_num1_vec192, 0) != OK) { printf("intConnect failed for ISR 1.\n"); } sysIntEnable(1); 1-43 1 Modeling /* VxWorks Interrupt Block: ' /Async Interrupt' */ /* Connect and enable ISR function: isr_num2_vec193 */ if( intConnect(INUM_TO_IVEC(193), isr_num2_vec193, 0) != OK) { printf("intConnect failed for ISR 2.\n"); } sysIntEnable(2); The hardware that generates the interrupt is not configured by the Async Interrupt block. Typically, the interrupt source is a VME I/O board, which generates interrupts for specific events (for example, end of A/D conversion). The VME interrupt level and vector are set up in registers or by using jumpers on the board. You can use the mdlStart routine of a user-written device driver (S-function) to set up the registers and enable interrupt generation on the board. You must match the interrupt level and vector specified in the Async Interrupt block dialog to the level and vector set up on the I/O board. Generated ISR Code The actual ISR generated for IRQ1 is listed below. /* VxWorks Interrupt Block: ' /Async Interrupt' */ void isr_num1_vec192(void) { int_T lock; FP_CONTEXT context; /* Use tickGet() as a portable tick counter example. A much higher resolution can be achieved with a hardware counter */ Async_Code_M->Timing.clockTick2 = tickGet(); /* disable interrupts (system is configured as non-ive) */ lock = intLock(); /* save floating point context */ fppSave(&context); 1-44 Scheduling /* Call the system: /Subsystem A */ Count(0, 0); /* restore floating point context */ fppRestore(&context); /* re-enable interrupts */ intUnlock(lock); } There are several features of the ISR that should be noted: • Because of the setting of the Preemption Flag(s) parameter, this ISR is locked; that is, it cannot be preempted by a higher priority interrupt. The ISR is locked and unlocked by the VxWorks int_lock and int_unlock functions. • The connected subsystem, Count, is called from within the ISR. • The Count function executes algorithmic (model) code. Therefore, the floating-point context is saved and restored across the call to Count. • The ISR maintains its own absolute time counter, which is distinct from other periodic base rate or subrate counters in the system. Timing data is maintained for the use of any blocks executed within the ISR that require absolute or elapsed time. See “Use Timers in Asynchronous Tasks” on page 1-58 for details. Model Termination Code The model’s termination function disables the interrupts: /* Model terminate function */ void Async_Code_terminate(void) { /* VxWorks Interrupt Block: ' /Async Interrupt' */ /* Disable interrupt for ISR system: isr_num1_vec192 */ sysIntDisable(1); 1-45 1 Modeling /* VxWorks Interrupt Block: ' /Async Interrupt' */ /* Disable interrupt for ISR system: isr_num2_vec193 */ sysIntDisable(2); } Spawn a Wind River Systems VxWorks Task. To spawn an independent VxWorks task, use the Task Sync block. The Task Sync block is a function call subsystem that spawns an independent VxWorks task. The task calls the function call subsystem connected to the output of the Task Sync block. Typically, the Task Sync block is placed between an Async Interrupt block and a function call subsystem block or a Stateflow chart. Another example would be to place the Task Sync block at the output of a Stateflow chart that has an event, Output to Simulink, configured as a function call. The Task Sync block performs the following functions: • An independent task is spawned, using the VxWorks system call taskSpawn. When the task is activated, it calls the downstream function call subsystem code. The task is deleted using taskDelete during model termination. • A semaphore is created to synchronize the connected subsystem to the execution of the Task Sync block. • The spawned task is wrapped in an infinite for loop. In the loop, the spawned task listens for the semaphore, using semTake. When semTake is first called, NO_WAIT is specified. This allows the task to determine whether a second semGive has occurred prior to the completion of the function call subsystem. This would indicate that the interrupt rate is too fast or the task priority is too low. • The Task Sync block generates synchronization code (for example, semGive()). This code allows the spawned task to run; the task in turn calls the connected function call subsystem code. The synchronization code can run at interrupt level. This is accomplished by connecting the Task Sync block to the output of an Async Interrupt block, which triggers execution of the Task Sync block within an ISR. • If blocks in the downstream algorithmic code require absolute time, it can be supplied either by the timer maintained by the Async Interrupt block, 1-46 Scheduling or by an independent timer maintained by the task associated with the Task Sync block. For an example of how to use the Task Sync block, see the rtwdemo_async example. The block diagram for the model appears in the next figure. Before reading the following discussion, open the example model and double-click the Generate Code button. You can then examine the generated code in the HTML code generation report produced by the example. In this model, the Async Interrupt block is configured for VME interrupts 1 and 2, using interrupt vector offsets 192 and 193. Interrupt 2 is connected to the Task Sync block, which in turn drives the Algorithm subsystem. Consider the code generated from this model, assuming that the Task Sync block parameters are configured as shown in the next figure. 1-47 1 Modeling Initialization Code The Task Sync block generates initialization code for initialization by MdlStart, which itself creates and initializes the synchronization semaphore. It also spawns an independent task (task0). /* VxWorks Task Block: /S-Function (vxtask1) */ /* Spawn task: Task0 with priority 50 */ if ((*(SEM_ID *)rtwdemo_async_DWork.SFunction_PWORK.SemID = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY)) == NULL) { printf("semBCreate call failed for block Task0.\n"); } if ((rtwdemo_async_DWork.SFunction_IWORK.TaskID = taskSpawn("Task0", 50.0, VX_FP_TASK, 8192.0, (FUNCPTR)Task0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR) { printf("taskSpawn call failed for block Task0.\n"); } After spawning Task0, MdlStart connects and enables the ISR (isr_num2_vec193) for interrupt 2: /* VxWorks Interrupt Block: ' /Async Interrupt' */ /* Connect and enable ISR function: isr_num1_vec192 */ 1-48 Scheduling if( intConnect(INUM_TO_IVEC(192), isr_num1_vec192, 0) != OK) { printf("intConnect failed for ISR 1.\n"); } sysIntEnable(1); The ordering of these operations is significant. The task must be spawned before the interrupt that activates it can be enabled. Task and Task Synchronization Code The function Task0, generated by the Task Sync block, runs as a VxWorks task. The task waits for a synchronization semaphore in an infinite for loop. If it obtains the semaphore, it updates its task timer and calls the Algorithm subsystem. For this example, the Synchronize the data transfer of this task with the caller task option of the Task Sync block is selected. Therefore, the timer associated with the Task Sync block (rtM->Timing.clockTick2) is updated with the value of the timer that is maintained by the Async Interrupt block (rtM->Timing.clockTick3). Therefore, blocks within the Algorithm subsystem use timer values based on the time of the most recent interrupt (not the most recent activation of Task0). /* VxWorks Task Block: /S-Function (vxtask1) */ /* Spawned with priority: 50 */ void Task0(void) { /* Wait for semaphore to be released by system: rtwdemo_async/Task Sync */ for(;;) { if (semTake(*(SEM_ID *)rtwdemo_async_DWork.SFunction_PWORK.SemID,NO_WAIT) != ERROR) { logMsg("Rate for Task Task0() too fast.\n",0,0,0,0,0,0); #if STOPONOVERRUN logMsg("Aborting real-time simulation.\n",0,0,0,0,0,0); semGive(stopSem); return(ERROR); #endif 1-49 1 Modeling } else { semTake(*(SEM_ID *)rtwdemo_async_DWork.SFunction_PWORK.SemID, WAIT_FOREVER); } /* Use the upstream clock tick counter for this Task. */ rtwdemo_async_M->Timing.clockTick2 = rtwdemo_async_M->Timing.clockTick3; /* Call the system: /Algorithm */ { /* Output and update for function-call system: ' /Algorithm' */ { uint32_T rt_currentTime = ((uint32_T)rtwdemo_async_M->Timing.clockTick2); uint32_T rt_elapseTime = rt_currentTime rtwdemo_async_DWork.Algorithm_PREV_T; rtwdemo_async_DWork.Algorithm_PREV_T = rt_currentTime; { int32_T i; /* DiscreteIntegrator: ' /Integrator' */ rtwdemo_async_B.Integrator = rtwdemo_async_DWork.Integrator_DSTATE; for(i = 0; i < 60; i++) { /* Sum: ' /Sum' */ rtwdemo_async_B.Sum[i] = rtwdemo_async_B.ProtectedRT1[i] + 1.25; } } /* Sum: ' /Sum1' */ rtwdemo_async_B.Sum1 = rtwdemo_async_B.Sum[0]; { int_T i1; const real_T *u0 = &rtwdemo_async_B.Sum[1]; 1-50 Scheduling for (i1=0; i1 < 59; i1++) { rtwdemo_async_B.Sum1 += u0[i1]; } } { int32_T i; if(rtwdemo_async_DWork.ProtectedRT2_ActiveBufIdx) { for(i = 0; i < 60; i++) { rtwdemo_async_DWork.ProtectedRT2_Buffer0[i] = rtwdemo_async_B.Sum[i]; } rtwdemo_async_DWork.ProtectedRT2_ActiveBufIdx = (boolean_T)0U; } else { for(i = 0; i < 60; i++) { rtwdemo_async_DWork.ProtectedRT2_Buffer1[i] = rtwdemo_async_B.Sum[i]; } rtwdemo_async_DWork.ProtectedRT2_ActiveBufIdx = (boolean_T)1U; } } /* Update for DiscreteIntegrator: ' /Integrator' */ rtwdemo_async_DWork.Integrator_DSTATE = (real_T)rt_elapseTime * 1.6666666666666666E-002 * rtwdemo_async_B.Sum1 + rtwdemo_async_DWork.Integrator_DSTATE; } The semaphore is granted by the function isr_num2_vec193, which is called from interrupt level: /* VxWorks Interrupt Block: ' /Async Interrupt' */ void isr_num2_vec193(void) { /* Use tickGet() as a portable tick counter example. A much higher resolution can be achieved with a hardware counter */ rtwdemo_async_M->Timing.clockTick3 = tickGet(); /* Call the system: /Subsystem */ 1-51 1 Modeling /* Output and update for function-call system: ' /Subsystem' */ { { int32_T i; for(i = 0; i < 60; i++) { if(rtwdemo_async_DWork.ProtectedRT1_ActiveBufIdx) { rtwdemo_async_B.ProtectedRT1[i] = rtwdemo_async_DWork.ProtectedRT1_Buffer1[i]; } else { rtwdemo_async_B.ProtectedRT1[i] = rtwdemo_async_DWork.ProtectedRT1_Buffer0[i]; } } } /* VxWorks Task Block: /S-Function (vxtask1) */ /* Release semaphore for system task: Task0 */ semGive(*(SEM_ID *)rtwdemo_async_DWork.SFunction_PWORK.SemID); } } The ISR maintains a timer that stores the tick count at the time of interrupt. This timer is updated before releasing the semaphore that activates Task0. As this example shows, the Task Sync block generates only a small amount of interrupt-level code. Task Termination Code The Task Sync block also generates the following termination code. /* Model terminate function */ void rtwdemo_async_terminate(void) { 1-52 Scheduling /* VxWorks Interrupt Block: ' /Async Interrupt' */ /* Disable interrupt for ISR system: isr_num1_vec192 */ sysIntDisable(1); /* VxWorks Interrupt Block: ' /Async Interrupt' */ /* Disable interrupt for ISR system: isr_num2_vec193 */ sysIntDisable(2); /* Terminate for function-call system: ' /Subsystem' */ /* VxWorks Task Block: /S-Function (vxtask1) */ /* Destroy task: Task0 */ taskDelete(rtwdemo_async_DWork.SFunction_IWORK.TaskID); } Rate Transitions and Asynchronous Blocks • “About Rate Transitions and Asynchronous Blocks” on page 1-53 • “Handle Rate Transitions for Asynchronous Tasks” on page 1-55 • “Handle Multiple Asynchronous Interrupts” on page 1-56 About Rate Transitions and Asynchronous Blocks. Because an asynchronous function call subsystem can preempt or be preempted by other model code, an inconsistency arises when more than one signal element is connected to an asynchronous block. The issue is that signals passed to and from the function call subsystem can be in the process of being written to or read from when the preemption occurs. Thus, some old and some new data is used. This situation can also occur with scalar signals in some cases. For example, if a signal is a double (8 bytes), the read or write operation might require two machine instructions. The Simulink Rate Transition block is designed to deal with preemption problems that occur in data transfer between blocks running at different rates. These issues are discussed in “Scheduling” on page 1-4. You can handle rate transition issues automatically by selecting the Automatically handle data transfers between tasks option on the Solver pane of the Configuration Parameters dialog box. This saves you from having to manually insert Rate Transition blocks to avoid invalid rate transitions, 1-53 1 Modeling including invalid asynchronous-to-periodic and asynchronous-to-asynchronous rate transitions, in multirate models. For asynchronous tasks, the Simulink engine configures inserted blocks for data integrity but not determinism during data transfers. For asynchronous rate transitions, the Rate Transition block provides data integrity, but cannot provide determinism. Therefore, when you insert Rate Transition blocks explicitly, you must clear the Ensure data determinism check box in the Block Parameters dialog box. When you insert a Rate Transition block between two blocks to maintain data integrity and priorities are assigned to the tasks associated with the blocks, the Simulink Coder software assumes that the higher priority task can preempt the lower priority task and the lower priority task cannot preempt the higher priority task. If the priority associated with task for either block is not assigned or the priorities of the tasks for both blocks are the same, the Simulink Coder software assumes that either task can preempt the other task. Priorities of periodic tasks are assigned by the Simulink engine, in accordance with the options specified in the Solver options section of the Solver pane of the Configuration Parameters dialog box. When the Periodic sample time constraint option field of Solver options is set to Unconstrained, the model base rate priority is set to 40. Priorities for subrates then increment or decrement by 1 from the base rate priority, depending on the setting of the Higher priority value indicates higher task priority option. You can assign priorities manually by using the Periodic sample time properties field. The Simulink engine does not assign a priority to asynchronous blocks. For example, the priority of a function call subsystem that connects back to an Async Interrupt block is assigned by the Async Interrupt block. The Simulink task priority field of the Async Interrupt block specifies a priority level (required) for every interrupt number entered in the VME interrupt number(s) field. The priority array sets the priorities of the subsystems connected to each interrupt. For the Task Sync block, if the Wind River Systems VxWorks RTOS is the target, the Higher priority value indicates higher task priority option should be deselected. The Simulink task priority field specifies the block 1-54 Scheduling priority relative to connected blocks (in addition to assigning a VxWorks priority to the generated task code). The VxWorks library provides two types of rate transition blocks as a convenience. These are simply preconfigured instances of the built-in Simulink Rate Transition block: • Protected Rate Transition block: Rate Transition block that is configured with the Ensure data integrity during data transfers on and Ensure deterministic data transfer off. • Unprotected Rate Transition block: Rate Transition block that is configured with the Ensure data integrity during data transfers option off. Handle Rate Transitions for Asynchronous Tasks. For rate transitions that involve asynchronous tasks, you can maintain data integrity. However, you cannot achieve determinism. You have the option of using the Rate Transition block or target-specific rate transition blocks. Consider the following model, which includes a Rate Transition block. You can use the Rate Transition block in either of the following modes: • Maintain data integrity, no determinism • Unprotected Alternatively, you can use target-specific rate transition blocks. The following blocks are available for the VxWorks RTOS: 1-55 1 Modeling • Protected Rate Transition block (reader) • Protected Rate Transition block (writer) • Unprotected Rate Transition block Handle Multiple Asynchronous Interrupts. Consider the following model, in which two functions trigger the same subsystem. The two tasks must have equal priorities. When priorities are the same, the outcome depends on whether they are firing periodically or asynchronously, and also on a diagnostic setting. The following table and notes describe these outcomes: Supported Sample Time and Priority for Function Call Subsystem with Multiple Triggers Async Priority = 1 Async Priority = 1 Async Priority = 2 Async Priority Unspecified 1-56 Async Priority = 2 Async Priority Unspecified Supported (1) Supported (1) Supported (2) Periodic Priority = 1 Periodic Priority = 2 Scheduling Supported Sample Time and Priority for Function Call Subsystem with Multiple Triggers (Continued) Async Priority = 1 Periodic Priority = 1 Periodic Priority = 2 Async Priority = 2 Async Priority Unspecified Periodic Priority = 1 Periodic Priority = 2 Supported Supported 1 Control these outcomes using the Tasks with equal priority option in the Diagnostics pane of the Configuration Parameters dialog box; set this diagnostic to none if tasks of equal priority cannot preempt each other in the target system. 2 For this case, the following warning message is issued unconditionally: The function call subsystem has multiple asynchronous triggers that do not specify priority. Data integrity will not be maintained if these triggers can preempt one another. Empty cells in the above table represent multiple triggers with differing priorities, which are unsupported. The Simulink Coder product provides absolute time management for a function call subsystem connected to multiple interrupts in the case where timer settings for TriggerA and TriggerB (time source, resolution) are the same. Assume that all of the following conditions are true for the model shown above: • A function call subsystem is triggered by two asynchronous triggers (TriggerA and TriggerB) having identical priority settings. • Each trigger sets the source of time and timer attributes by calling the functions ssSetTimeSource and ssSetAsyncTimerAttributes. 1-57 1 Modeling • The triggered subsystem contains a block that needs elapsed or absolute time (for example, a Discrete Time Integrator). The asynchronous function call subsystem has one global variable, clockTick# (where # is the task ID associated with the subsystem). This variable stores absolute time for the asynchronous task. There are two ways timing can be handled: • If the time source is set to SS_TIMESOURCE_BASERATE, the Simulink Coder code generator generates timer code in the function call subsystem, updating the clock tick variable from the base rate clock tick. Data integrity is maintained if the same priority is assigned to TriggerA and TriggerB. • If the time source is SS_TIMESOURCE_SELF, generated code for both TriggerA and TriggerB updates the same clock tick variable from the hardware clock. The word size of the clock tick variable can be set directly or be established according to the Application lifespan (days) setting and the timer resolution set by the TriggerA and TriggerB S-functions (which must be the same). See “Use Timers in Asynchronous Tasks” on page 1-58 and “Control Memory Allocation for Time Counters” on page 16-9 for more information. Use Timers in Asynchronous Tasks An ISR can set a source for absolute time. This is done with the function ssSetTimeSource, which has the following three options: • SS_TIMESOURCE_SELF: Each generated ISR maintains its own absolute time counter, which is distinct from any periodic base rate or subrate counters in the system. The counter value and the timer resolution value (specified in the Timer resolution (seconds) parameter of the Async Interrupt block) are used by downstream blocks to determine absolute time values required by block computations. • SS_TIMESOURCE_CALLER: The ISR reads time from a counter maintained by its caller. Time resolution is thus the same as its caller’s resolution. • SS_TIMESOURCE_BASERATE: The ISR can read absolute time from the model’s periodic base rate. Time resolution is thus the same as its base rate resolution. 1-58 Scheduling Note The function ssSetTimeSource cannot be called before ssSetOutputPortWidth is called. If this occurs, the program will come to a halt and generate an error message. By default, the counter is implemented as a 32-bit unsigned integer member of the Timing substructure of the real-time model structure. For any target that supports the rtModel data structure, when the time data type is not set by using ssSetAsyncTimeDataType, the counter word size is determined by the Application lifespan (days) model parameter. As an example (from ERT target code), /* Real-time Model Data Structure */ struct _RT_MODEL_elapseTime_exp_Tag { const char *errorStatus; /* * Timing: * The following substructure contains information regarding * the timing information for the model. */ struct { uint32_T clockTick1; uint32_T clockTick2; } Timing; }; The example omits unused fields in the Timing data structure (a feature of ERT target code not found in GRT). For any target that supports the rtModel data structure, the counter word size is determined by the Application lifespan (days) model parameter. By default, the library blocks for the Wind River Systems VxWorks RTOS set the timer source to SS_TIMESOURCE_SELF and update their counters by using the system call tickGet. tickGet returns a timer value maintained by the VxWorks kernel. The maximum word size for the timer is UINT32. The following VxWorks example for the shows a generated call to tickGet. /* VxWorks Interrupt Block: ' /Async Interrupt' */ void isr_num2_vec193(void) 1-59 1 Modeling { /* Use tickGet() as a portable tick counter example. A much higher resolution can be achieved with a hardware counter */ rtM->Timing.clockTick2 = tickGet(); . . . The tickGet call is supplied only as an example. It can (and in many instances should) be replaced by a timing source that has better resolution. If you are targeting the VxWorks RTOS, you can obtain better timer resolution by replacing the tickGet call and accessing a hardware timer by using your BSP instead. If you are implementing a custom asynchronous block for an RTOS other than the VxWorks RTOS, you should either generate an equivalent call to the target RTOS, or generate code to read a timer register on the target hardware. The default Timer resolution (seconds) parameter of your Async Interrupt block implementation should be changed to match the resolution of your target’s timing source. The counter is updated at interrupt level. Its value represents the tick value of the timing source at the most recent execution of the ISR. The rate of this timing source is unrelated to sample rates in the model. In fact, typically it is faster than the model’s base rate. Select the timer source and set its rate and resolution based on the expected rate of interrupts to be serviced by the Async Interrupt block. For an example of timer code generation, see “Async Interrupt Block Implementation” on page 1-61. Create a Customized Asynchronous Library • “About Implementing Asynchronous Blocks” on page 1-61 • “Async Interrupt Block Implementation” on page 1-61 • “Task Sync Block Implementation” on page 1-66 • “asynclib.tlc Support Library” on page 1-68 1-60 Scheduling About Implementing Asynchronous Blocks. This section describes how to implement asynchronous blocks for use with your target RTOS, using the Async Interrupt and Task Sync blocks as a starting point. (Rate Transition blocks are target-independent, so you do not need to develop customized rate transition blocks.) You can customize the asynchronous library blocks by modifying the block implementation. These files are • The block’s underlying S-function MEX-file • The TLC files that control code generation of the block In addition, you need to modify the block masks to remove references specific to the Wind River Systems VxWorks RTOS and to incorporate parameters required by your target RTOS. Custom block implementation is an advanced topic, requiring familiarity with the Simulink MEX S-function format and API, and with the Target Language Compiler (TLC). These topics are covered in the following documents: • Simulink topics “What Is an S-Function?”, “Use S-Functions in Models”, “How S-Functions Work”, and “Implementing S-Functions” describe MEX S-functions and the S-function API in general. • The “Inlining S-Functions”, “Inlining C MEX S-Functions”, and “Insert S-Function Code” on page 14-46 describe how to create a TLC block implementation for use in code generation. The following sections discuss the C/C++ and TLC implementations of the asynchronous library blocks, including required SimStruct macros and functions in the TLC asynchronous support library (asynclib.tlc). Async Interrupt Block Implementation. The source files for the Async Interrupt block are located in matlabroot/rtw/c/tornado/devices: • vxinterrupt1.c: C MEX-file source code, for use in configuration and simulation • vxinterrupt1.tlc: TLC implementation, for use in code generation 1-61 1 Modeling • asynclib.tlc: library of TLC support functions, called by the TLC implementation of the block. The library calls are summarized in “asynclib.tlc Support Library” on page 1-68. C MEX Block Implementation Most of the code in vxinterrupt1.c performs ordinary functions that are not related to asynchronous support (for example, obtaining and validating parameters from the block mask, marking parameters nontunable, and passing parameter data to the model.rtw file). The mdlInitializeSizes function uses special SimStruct macros and SS_OPTIONS settings that are required for asynchronous blocks, as described below. Note that the following macros cannot be called before ssSetOutputPortWidth is called: • ssSetTimeSource • ssSetAsyncTimerAttributes • ssSetAsyncTimerResolutionEl • ssSetAsyncTimerDataType • ssSetAsyncTimerDataTypeEl • ssSetAsyncTaskPriorities • ssSetAsyncTaskPrioritiesEl If any one of the above macros is called before ssSetOutputPortWidth, the following error message will appear: SL_SfcnMustSpecifyPortWidthBfCallSomeMacro { S-function '%s' in '% ' must set output port %d width using ssSetOutputPortWidth before calling macro %s } 1-62 Scheduling ssSetAsyncTimerAttributes ssSetAsyncTimerAttributes declares that the block requires a timer, and sets the resolution of the timer as specified in the Timer resolution (seconds) parameter. The function prototype is ssSetAsyncTimerAttributes(SimStruct *S, double res) where • S is a Simstruct pointer. • res is the Timer resolution (seconds) parameter value. The following code excerpt shows the call to ssSetAsyncTimerAttributes. /* Setup Async Timer attributes */ ssSetAsyncTimerAttributes(S,mxGetPr(TICK_RES)[0]); ssSetAsyncTaskPriorities ssSetAsyncTaskPriorities sets the Simulink task priority for blocks executing at each interrupt level, as specified in the block’s Simulink task priority field. The function prototype is ssSetAsyncTaskPriorities(SimStruct *S, int numISRs, int *priorityArray) where • S is a SimStruct pointer. • numISRs is the number of interrupts specified in the VME interrupt number(s) parameter. • priorityarray is an integer array containing the interrupt numbers specified in the VME interrupt number(s) parameter. The following code excerpt shows the call to ssSetAsyncTaskPriorities: 1-63 1 Modeling /* Setup Async Task Priorities */ priorityArray = malloc(numISRs*sizeof(int_T)); for (i=0; i Input must be a comma-separated list of tables, as described in “Enable Data Import”. • The table corresponding to the input port outputting asynchronous events must be a column vector containing time values for the asynchronous events. - The time vector of the asynchronous events must be of double data type and monotonically increasing. - All time data must be integer multiples of the model step size. To specify multiple function calls at a given time step, you must repeat the time value accordingly. In other words, if you wish to specify three asynchronous events at t = 1 and two events at t = 9, then you must list 1 three times and 9 twice in your time vector. ( t = [1 1 1 9 9]) • The table corresponding to normal data input port can be of any other supported format as described in “Enable Data Import”. Example. In this model, a function-call subsystem is used to track the total number of asynchronous events and to multiply a set of inputs by 2. 1-70 Scheduling 1-71 1 Modeling 1 To input data via the Configuration Parameters dialog box, a Select Simulation > Configuration Parameters > Data Import/Export. b Select the Input parameter. c For this example, enter the following command in the MATLAB window: >> t = [1 1 5 9 9 9]', u = [[0:10]' [0:10]'] Alternatively, you can enter the data as t, tu in the Data Import/Export pane: 1-72 Scheduling Here, t is a column vector containing the times of asynchronous events for Inport block In1 while tu is a table of input values versus time for Inport block In2. 2 By default, the Time and Output options are selected and the output variables are named tout and yout. 3 Simulate the model. 4 Display the output by entering [tout yout] at the MATLAB command line and obtain: ans = 0 1 2 3 4 5 6 7 8 9 10 0 2 2 2 2 3 3 3 3 6 6 -1 2 2 2 2 10 10 10 10 18 18 Here the first column contains the simulation times. 1-73 1 Modeling The second column represents the output of Out1 — the total number of asynchronous events. Since the function-call subsystem is triggered twice at t = 1, the output is 2. It is not called again until t = 5, and so does not increase to 3 until then. Finally, it is called three times at 9, so it increases to 6. The third column contains the output of Out2 obtained by multiplying the input value at each asynchronous event time by 2. At any other time, the output is held at its previous value Asynchronous Support Limitations • “Asynchronous Task Priority” on page 1-74 • “Convert an Asynchronous Subsystem into a Model Reference” on page 1-74 Asynchronous Task Priority. The Simulink product does not simulate asynchronous task behavior. Although you can specify a task priority for an asynchronous task represented in a model with the Task Sync block, the priority setting is for code generation purposes only and is not honored during simulation. Convert an Asynchronous Subsystem into a Model Reference. You can use the Asynchronous Task Specification block to specify an asynchronous function-call input to a model reference. However, you must convert the Async Interrupt and Function-Call blocks into a subsystem and then convert the subsystem into a model reference. Following is an example with step-by-step instructions for conversion. 1-74 Scheduling 1 Convert the Async Interrupt and Count blocks into a subsystem. Select both blocks and right-click Count. From the menu, select Subsystem & Model Reference > Create Subsystem from Selection. 2 To prepare for converting the new subsystem to a Model block, set the following configuration parameters in the top model. Open the Configuration Parameters dialog box. • If you are simulating in Normal mode, then you must make the following change. From the Optimization node, navigate to the Signals and Parameters pane. Under Simulation and code generation, select the Inline parameters option. • From the Diagnostics node, navigate to the Sample Time pane. Then set Multitask rate transition to error and Multitask conditionally executed subsystem to error. • Under Diagnostics, navigate to the Data Validity pane and set the Multitask data store option to error and set the Underspecified initialization detection to Simplified. If your model is large or complex, in the Model Advisor, run the Check consistency of initialization parameters for Outport and Merge blocks check and make suggested changes. • Under Diagnostics, navigate to the Connectivity pane. Set Mux blocks used to create bus signals, Bus signal treated as 1-75 1 Modeling vector, and Invalid function-call connection to error. Also set Context-dependent inputs to Enable All. 3 Convert the subsystem to an atomic subsystem. Select Edit > Subsystem Parameters > Treat as atomic unit. 4 Convert the subsystem to a Model block. Right-click the subsystem and select Subsystem & Model Reference > Convert Subsystem to > Referenced Model. A window opens with a model reference block inside of it. 5 Replace the subsystem in the top model with the new model reference block. 6 Move the Async Interrupt block from the model reference to the top model, before the model reference block. 1-76 Scheduling 7 Insert an Asynchronous Task Specification block in the model reference. Set the priority of the Asynchronous Task Specification block. (For more information on setting the priority, see Asynchronous Task Specification.) 8 In the model reference, double-click the input port to open its Source Block Parameters dialog box. Click theSignal Attributes tab and select the Output function call option. Click OK. 1-77 1 Modeling 9 Save your model and then perform Simulation > Update Diagram to verify your settings. 1-78 Scheduling Timers • “Absolute and Elapsed Time Computation” on page 1-79 • “APIs for Accessing Timers” on page 1-81 • “Elapsed Timer Code Generation Example” on page 1-85 • “Limitations on the Use of Absolute Time” on page 1-88 Absolute and Elapsed Time Computation • “About Timers” on page 1-79 • “Timers for Periodic and Asynchronous Tasks” on page 1-80 • “Allocation of Timers” on page 1-80 • “Integer Timers in Generated Code” on page 1-81 • “Elapsed Time Counters in Triggered Subsystems” on page 1-81 About Timers. Certain blocks require the value of either absolute time (that is, the time from the start of program execution to the present time) or elapsed time (for example, the time elapsed between two trigger events). Targets that support the real-time model (rtModel) data structure provide efficient time computation services to blocks that request absolute or elapsed time. Absolute and elapsed timer features include • Timers are implemented as unsigned integers in generated code. • In multirate models, at most one timer is allocated per rate. If no blocks executing at a given rate require a timer, no timer is allocated to that rate. This minimizes memory allocated for timers and significantly reduces overhead involved in maintaining timers. 1-79 1 Modeling • Allocation of elapsed time counters for use of blocks within triggered subsystems is minimized, further reducing memory usage and overhead. • The Simulink Coder product provides S-function and TLC APIs that let your S-functions access timers, in both simulation and code generation. • The word size of the timers is determined by a user-specified maximum counter value, Application lifespan (days). If you specify this value, timers will not overflow. For more information, see “Control Memory Allocation for Time Counters” on page 16-9. See “Limitations on the Use of Absolute Time” on page 1-88 and “Blocks that Depend on Absolute Time” on page 1-89 for more information about absolute time and the restrictions that it imposes. Timers for Periodic and Asynchronous Tasks. This chapter discusses timing services provided for blocks executing within periodic tasks (that is, tasks running at the model’s base rate or subrates). The Simulink Coder product also provides timer support for blocks whose execution is asynchronous with respect to the periodic timing source of the model. See the following sections of the Asynchronous Support chapter: • “Use Timers in Asynchronous Tasks” on page 1-58 • “Create a Customized Asynchronous Library” on page 1-60 Allocation of Timers. If you create or maintain an S-Function block that requires absolute or elapsed time data, it must register the requirement (see “APIs for Accessing Timers” on page 1-81). In multirate models, timers are allocated on a per-rate basis. For example, consider a model structured as follows: • There are three rates, A, B, and C, in the model. • No blocks running at rate B require absolute or elapsed time. • Two blocks running at rate C register a requirement for absolute time. • One block running at rate A registers a requirement for absolute time. In this case, two timers are generated, running at rates A and C respectively. The timing engine updates the timers as the tasks associated with rates A 1-80 Scheduling and C execute. Blocks executing at rates A and C obtain time data from the timers associated with rates A and C. Integer Timers in Generated Code. In the generated code, timers for absolute and elapsed time are implemented as unsigned integers. The default size is 64 bits. This is the amount of memory allocated for a timer if you specify a value of inf for the Application lifespan (days) parameter. For an application with a sample rate of 1000 MHz, a 64-bit counter will not overflow for more than 500 years. See “Use Timers in Asynchronous Tasks” on page 1-58 and “Control Memory Allocation for Time Counters” on page 16-9 for more information. Elapsed Time Counters in Triggered Subsystems. Some blocks, such as the Discrete-Time Integrator block, perform computations requiring the elapsed time (delta T) since the previous block execution. Blocks requiring elapsed time data must register the requirement (see “APIs for Accessing Timers” on page 1-81). A triggered subsystem then allocates and maintains a single elapsed time counter if required. This timer functions at the subsystem level, not at the individual block level. The timer is generated if the triggered subsystem (or any unconditionally executed subsystem within the triggered subsystem) contains one or more blocks requiring elapsed time data. Note If you are using simplified initialization mode, elapsed time is always reset on first execution after becoming enabled, whether or not the subsystem is configured to reset on enable. For more information, see “Underspecified initialization detection” in the Simulink documentation. APIs for Accessing Timers • “About Timer APIs” on page 1-82 • “C API for S-Functions” on page 1-82 • “TLC API for Code Generation” on page 1-84 1-81 1 Modeling About Timer APIs. This section describes APIs that let your S-functions take advantage of the efficiencies offered by the absolute and elapsed timers. SimStruct macros are provided for use in simulation, and TLC functions are provided for inlined code generation. Note that • To generate and use the new timers as described above, your S-functions must register the need to use an absolute or elapsed timer by calling ssSetNeedAbsoluteTime or ssSetNeedElapseTime in mdlInitializeSampleTime. • Existing S-functions that read absolute time but do not register by using these macros will continue to operate as expected, but will generate old-style, less efficient code. C API for S-Functions. The SimStruct macros described in this section provide access to absolute and elapsed timers for S-functions during simulation. In the functions below, the SimStruct *S argument is a pointer to the simstruct of the calling S-function. • void ssSetNeedAbsoluteTime(SimStruct *S, boolean b): if b is TRUE, registers that the calling S-function requires absolute time data, and allocates an absolute time counter for the rate at which the S-function executes (if such a counter has not already been allocated). • int ssGetNeedAbsoluteTime(SimStruct *S): returns 1 if the S-function has registered that it requires absolute time. • double ssGetTaskTime(SimStruct *S, tid): read absolute time for a given task with task identifier tid. ssGetTaskTime operates transparently, regardless of whether or not you use the new timer features. ssGetTaskTime is documented in the SimStruct Functions chapter of the Simulink documentation. • void ssSetNeedElapseTime(SimStruct *S, boolean b): if b is TRUE, registers that the calling S-function requires elapsed time data, and allocates an elapsed time counter for the triggered subsystem in which the S-function executes (if such a counter has not already been allocated). See also “Elapsed Time Counters in Triggered Subsystems” on page 1-81. 1-82 Scheduling • int ssGetNeedElapseTime(SimStruct *S): returns 1 if the S-function has registered that it requires elapsed time. • void ssGetElapseTime(SimStruct *S, (double *)elapseTime): returns, to the location pointed to by elapseTime, the value (as a double) of the elapsed time counter associated with the S-function. • void ssGetElapseTimeCounterDtype(SimStruct *S, (int *)dtype): returns the data type of the elapsed time counter associated with the S-function to the location pointed to by dtype. This function is intended for use with the ssGetElapseTimeCounter function (see below). • void ssGetElapseResolution(SimStruct *S, (double *)resolution): returns the resolution (that is, the sample time) of the elapsed time counter associated with the S-function to the location pointed to by resolution. This function is intended for use with the ssGetElapseTimeCounter function (see below). • void ssGetElapseTimeCounter(SimStruct *S, (void *)elapseTime): This function is provided for the use of blocks that require the elapsed time values for fixed-point computations. ssGetElapseTimeCounter returns, to the location pointed to by elapseTime, the integer value of the elapsed time counter associated with the S-function. If the counter size is 64 bits, the value is returned as an array of two 32-bit words, with the low-order word stored at the lower address. To determine how to access the returned counter value, obtain the data type of the counter by calling ssGetElapseTimeCounterDtype, as in the following code: int *y_dtype; ssGetElapseTimeCounterDtype(S, y_dtype); switch(*y_dtype) { case SS_DOUBLE_UINT32: { uint32_T dataPtr[2]; ssGetElapseTimeCounter(S, dataPtr); } break; case SS_UINT32: { uint32_T dataPtr[1]; 1-83 1 Modeling ssGetElapseTimeCounter(S, dataPtr); } break; case SS_UINT16: { uint16_T dataPtr[1]; ssGetElapseTimeCounter(S, dataPtr); } break; case SS_UINT8: { uint8_T dataPtr[1]; ssGetElapseTimeCounter(S, dataPtr); } break; case SS_DOUBLE: { real_T dataPtr[1]; ssGetElapseTimeCounter(S, dataPtr); } break; default: ssSetErrorStatus(S, "Invalid data type for elaspe time counter"); break; } If you want to use the actual elapsed time, issue a call to the ssGetElapseTime function to access the elapsed time directly. You do not need to get the counter value and then calculate the elapsed time. double *y_elapseTime; . . . ssGetElapseTime(S, elapseTime) TLC API for Code Generation. The following TLC functions support elapsed time counters in generated code when you inline S-functions by writing TLC scripts for them. 1-84 Scheduling • LibGetTaskTimeFromTID(block): Generates code to read the absolute time for the task in which block executes. LibGetTaskTimeFromTID is documented with other sample time functions in the TLC Function Library Reference pages of the Target Language Compiler documentation. Note Do not use LibGetT for this purpose. LibGetT always reads the base rate (tid 0) timer. If LibGetT is called for a block executing at a subrate, the wrong timer is read, causing serious errors. • LibGetElapseTime(system): Generates code to read the elapsed time counter for system. (system is the parent system of the calling block.) See “Elapsed Timer Code Generation Example” on page 1-85 for an example of code generated by this function. • LibGetElapseTimeCounter(system): Generates code to read the integer value of the elapsed time counter for system. (system is the parent system of the calling block.) This function should be used in conjunction with LibGetElapseTimeCounterDtypeId and LibGetElapseTimeResolution. (See the discussion of ssGetElapseTimeCounter above.) • LibGetElapseTimeCounterDtypeId(system): Generates code that returns the data type of the elapsed time counter for system. (system is the parent system of the calling block.) • LibGetElapseTimeResolution(system): Generates code that returns the resolution of the elapsed time counter for system. (system is the parent system of the calling block.) Elapsed Timer Code Generation Example This section shows a simple model illustrating how an elapsed time counter is generated and used by a Discrete-Time Integrator block within a triggered subsystem. The following block diagrams show the model elapseTime_exp, which contains subsystem Amplifier, which includes a Discrete-Time Integrator block. 1-85 1 Modeling elapseTime_exp Model Amplifier Subsystem A 32-bit timer for the base rate (the only rate in this model) is defined within the rtModel structure, as follows, in model.h. -/* * Timing: * The following substructure contains information regarding * the timing information for the model. */ struct { time_T stepSize; uint32_T clockTick0; uint32_T clockTickH0; time_T stepSize0; time_T tStart; time_T tFinal; time_T timeOfLastOutput; void *timingData; real_T *varNextHitTimesList; 1-86 Scheduling SimTimeStep simTimeStep; boolean_T stopRequestedFlag; time_T *sampleTimes; time_T *offsetTimes; int_T *sampleTimeTaskIDPtr; int_T *sampleHits; int_T *perTaskSampleHits; time_T *t; time_T sampleTimesArray[1]; time_T offsetTimesArray[1]; int_T sampleTimeTaskIDArray[1]; int_T sampleHitArray[1]; int_T perTaskSampleHitsArray[1]; time_T tArray[1]; } Timing; Had the target been ERT instead of GRT, the Timing structure would have been pruned to contain only the data required by the model, as follows: /* Real-time Model Data Structure */ (for ERT!) struct _RT_MODEL_elapseTime_exp_Tag { /* * Timing: * The following substructure contains information regarding * the timing information for the model. */ struct { uint32_T clockTick0; } Timing; }; Storage for the previous-time value of the Amplifier subsystem (Amplifier_PREV_T) is allocated in the D_Work(states) structure in model.h. typedef struct D_Work_elapseTime_exp_tag { real_T DiscreteTimeIntegrator_DSTATE; /* ' /Discrete-Time Integrator' */ int32_T clockTickCounter; /* ' /Pulse Generator' */ uint32_T Amplifier_PREV_T; /* ' /Amplifier' */ } D_Work_elapseTime_exp; 1-87 1 Modeling These structures are declared in model.c: /* Block states (auto storage) */ D_Work_elapseTime_exp elapseTime_exp_DWork; . . . /* Real-time model */ rtModel_elapseTime_exp elapseTime_exp_M_; rtModel_elapseTime_exp *elapseTime_exp_M = &elapseTime_exp_M_; The elapsed time computation is performed as follows within the model_step function: /* Output and update for trigger system: ' /Amplifier' */ uint32_T rt_currentTime = ((uint32_T)elapseTime_exp_M->Timing.clockTick0); uint32_T rt_elapseTime = rt_currentTime elapseTime_exp_DWork.Amplifier_PREV_T; elapseTime_exp_DWork.Amplifier_PREV_T = rt_currentTime; As shown above, the elapsed time is maintained as a state of the triggered subsystem. The Discrete-Time Integrator block finally performs its output and update computations using the elapsed time. /* DiscreteIntegrator: ' /Discrete-Time Integrator' */ OUTPUT = elapseTime_exp_DWork.DiscreteTimeIntegrator_DSTATE; /* Update for DiscreteIntegrator: ' /Discrete-Time Integrator'*/ elapseTime_exp_DWork.DiscreteTimeIntegrator_DSTATE += 0.3 * (real_T)rt_elapseTime * 1.5 ; Because the triggered subsystem maintains the elapsed time, the TLC implementation of the Discrete-Time Integrator block needs only a single call to LibGetElapseTime to access the elapsed time value. Limitations on the Use of Absolute Time • “About Absolute Time Limitations” on page 1-89 • “Logging Absolute Time” on page 1-89 1-88 Scheduling • “Absolute Time in Stateflow Charts” on page 1-89 • “Blocks that Depend on Absolute Time” on page 1-89 About Absolute Time Limitations. Absolute time is the time that has elapsed from the beginning of program execution to the present time, as distinct from elapsed time, the interval between two events. See “Absolute and Elapsed Time Computation” on page 1-79 for more information. When you design an application that is intended to run indefinitely, you must take care when logging time values, or using charts or blocks that depend on absolute time. If the value of time reaches the largest value that can be represented by the data type used by the timer to store time, the timer overflows and the logged time or block output is incorrect. If your target uses rtModel, you can avoid timer overflow by specifying a value for the Application life span parameter. See “Integer Timers in Generated Code” on page 1-81 for more information. Logging Absolute Time. If you log time values by opening the Configuration Parameters dialog box and enabling Data Import/Export > Save to workspace > Time, your model uses absolute time. Absolute Time in Stateflow Charts. Every Stateflow chart that uses time is dependent on absolute time. The only way to eliminate the dependency is to change the Stateflow chart to not use time. Blocks that Depend on Absolute Time. The following Simulink blocks depend on absolute time: • Backlash • Chirp Signal • Clock • Derivative • Digital Clock • Discrete-Time Integrator (only when used in triggered subsystems) • From File 1-89 1 Modeling • From Workspace • Pulse Generator • Ramp • Rate Limiter • Repeating Sequence • Signal Generator • Sine Wave (only when the Sine type parameter is set to Time-based) • Step • To File • To Workspace (only when logging to StructureWithTime format) • Transport Delay • Variable Time Delay • Variable Transport Delay In addition to the Simulink blocks above, blocks in other blocksets may depend on absolute time. See the documentation for the blocksets that you use. Configure Scheduling • “Configure Start and Stop Times” on page 1-90 • “Configure the Solver Type” on page 1-91 • “Configure the Tasking Mode” on page 1-91 For details about solver options, see “Solver Pane” in the Simulink reference documentation. Configure Start and Stop Times The Stop time must be greater than or equal to the Start time. If the stop time is zero, or if the total simulation time (Stop minus Start) is less than zero, the generated program runs for one step. If the stop time is set to inf, the generated program runs indefinitely. 1-90 Scheduling When using the GRT or Wind River Systems Tornado targets, you can override the stop time when running a generated program from the Microsoft Windows command prompt or UNIX1 command line. To override the stop time that was set during code generation, use the -tf switch. model -tf n The program runs for n seconds. If n = inf, the program runs indefinitely. Certain blocks have a dependency on absolute time. If you are designing a program that is intended to run indefinitely (Stop time = inf), and your generated code does not use the rtModel data structure (that is, it uses simstructs instead), you must not use these blocks. See “Limitations on the Use of Absolute Time” on page 1-88 for a list of blocks that can potentially overflow timers. If you know how long an application that depends on absolute time needs to run, you can prevent the timers from overflowing and force the use of optimal word sizes by specifying the Application lifespan (days) parameter on the Optimization pane. See “Control Memory Allocation for Time Counters” on page 16-9 for details. Configure the Solver Type For code generation, you must configure a model to use a fixed-step solver for all targets except the S-function and RSim targets. You can configure the S-function and RSim targets with a fixed-step or variable-step solver. Configure the Tasking Mode The Simulink Coder product supports both single-tasking and multitasking modes for periodic sample times. See “Scheduling” on page 1-4 for details. 1. UNIX® is a registered trademark of The Open Group in the United States and other countries. 1-91 1 Modeling Supported Products and Block Usage In this section... “Related Products” on page 1-92 “Simulink Built-In Blocks That Support Code Generation” on page 1-94 “Block Set Support for Code Generation” on page 1-116 “Fixed-Point Tool Data Type Override” on page 1-116 “Data Type Overrides Unavailable for Most Blocks in Embedded Targets and Desktop Targets” on page 1-116 Related Products The following table summarizes MathWorks® products that extend and complement Simulink Coder software. For information about these and other MathWorks products, see www.mathworks.com. 1-92 Product Extends Code Generation Capabilities for ... Aerospace Blockset™ Aircraft, spacecraft, rocket, propulsion systems, and unmanned airborne vehicles Communications System Toolbox™ Physical layer of communication systems Computer Vision System Toolbox™ Video processing, image processing, and computer vision systems Control System Toolbox™ Linear control systems DSP System Toolbox™ Signal processing systems Embedded Coder Embedded systems, on-target rapid prototyping boards, microprocessors in mass production, and real-time simulators Fuzzy Logic Toolbox™ System designs based on fuzzy logic Gauges Blockset™ Linking generated code executing on a target system with graphical instrumentation in a Simulink model Supported Products and Block Usage Product Extends Code Generation Capabilities for ... Model-Based Calibration Toolbox™ Developing processes for systematically identifying optimal balance of engine performance, emissions, and fuel economy, and reusing statistical models for control design, hardware-in-the-loop testing, or powertrain simulation Model Predictive Control Toolbox™ Controllers that optimize performance of multi-input and multi-output systems that are subject to input and output constraints Real-Time Windows Target™ Rapid prototyping or hardware-in-the-loop simulation of control system and signal processing algorithms SimDriveline™ Driveline (drivetrain) systems SimElectronics® Electronic and electromechanical systems SimHydraulics® Hydraulic power and control systems SimMechanics™ Three-dimensional mechanical systems SimPowerSystems™ Systems that generate, transmit, distribute, and consume electrical power Simscape™ Systems spanning mechanical, electrical, hydraulic, and other physical domains as physical networks Simulink Fixed Point™ Control and signal processing systems implemented with fixed-point arithmetic Simulink 3D Animation™ Systems with 3D visualizations Simulink Design Optimization™ Systems requiring maximum overall system performance Simulink Report Generator™ Automatically generating project documentation in a standard format 1-93 1 Modeling Product Extends Code Generation Capabilities for ... Simulink Verification and Validation™ Applications requiring automated requirements tracing, model standards compliance checking, and test harness generation System Identification Toolbox™ Systems constructed from measured input-output data Support exceptions: • Nonlinear IDNLGREY Model, IDDATA Source, IDDATA Sink, and estimator blocks • Nonlinear ARX models that contain custom regressors • neuralnet nonlinearities • customnet nonlinearities Vehicle Network Toolbox™ Support exception: CAN Configuration, CAN Receive, and CAN Transmit blocks in the CAN Communication library xPC Target™ Rapid control prototyping, hardware-in-the-loop (HIL) simulation, and other real-time testing applications xPC Target Embedded Option™ Deploying real-time embedded systems on a PC for production, data acquisition, calibration, and testing applications Simulink Built-In Blocks That Support Code Generation The following tables summarize Simulink Coder and Embedded Coder support for Simulink blocks. There is a table for each block library. For each block, the second column indicates any support notes, which give information about the block for code generation. For more detail, including 1-94 Supported Products and Block Usage data types each block supports, in the MATLAB Command Window, type showblockdatatypetable, or consult the block reference pages. • Additional Math and Discrete: Additional Discrete on page 1-96 • Additional Math and Discrete: Increment/Decrement on page 1-97 • Continuous on page 1-97 • Discontinuities on page 1-98 • Discrete on page 1-99 • Logic and Bit Operations on page 1-101 • Lookup Tables on page 1-102 • Math Operations on page 1-103 • Model Verification on page 1-106 • Model-Wide Utilities on page 1-107 • Ports & Subsystems on page 1-107 • Signal Attributes on page 1-108 • Signal Routing on page 1-109 • Sinks on page 1-110 • Sources on page 1-112 • User-Defined on page 1-115 1-95 1 Modeling Additional Math and Discrete: Additional Discrete Block Support Notes Fixed-Point State-Space The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Transfer Fcn Direct Form II • The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Transfer Fcn Direct Form II Time Varying Unit Delay Enabled Unit Delay Enabled External IC Unit Delay Enabled Resettable Unit Delay Enabled Resettable External IC Unit Delay External IC Unit Delay Resettable Unit Delay Resettable External IC Unit Delay With Preview Enabled Unit Delay With Preview Enabled Resettable Unit Delay With Preview Enabled Resettable External RV Unit Delay With Preview Resettable Unit Delay With Preview Resettable External RV 1-96 • Generated code might rely on memcpy or memset (string.h). Supported Products and Block Usage Additional Math and Discrete: Increment/Decrement Block Support Notes Decrement Real World The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Decrement Stored Integer Decrement Time To Zero Supports code generation. Decrement To Zero The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Increment Real World Increment Stored Integer Continuous Block Support Notes Derivative Not recommended for production-quality code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. The code generated can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Integrator Integrator Limited PID Controller PID Controller (2DOF) Second-Order Integrator Second-Order Integrator Limited State-Space Transfer Fcn Transport Delay Variable Time Delay In general, consider using the Simulink Model Discretizer to map continuous blocks into discrete equivalents that support production code generation. To start the Model Discretizer, select Analysis > Control Design > Model Discretizer. One exception is the Second-Order Integrator block because, for this block, the Model Discretizer produces an approximate discretization. 1-97 1 Modeling Continuous (Continued) Block Support Notes Variable Transport Delay Zero-Pole Discontinuities 1-98 Block Support Notes Backlash Supports code generation. Coulomb and Viscous Friction The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Dead Zone Supports code generation. Dead Zone Dynamic The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Hit Crossing Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Quantizer Supports code generation. Rate Limiter Cannot use inside a triggered subsystem hierarchy. Supported Products and Block Usage Discontinuities (Continued) Block Support Notes Rate Limiter Dynamic The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Relay Support code generation. Saturation Saturation Dynamic Wrap To Zero The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Discrete Block Support Notes Delay Supports code generation. Difference • The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. • Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. 1-99 1 Modeling Discrete (Continued) Block Support Notes Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Discrete Derivative • Generated code might rely on memcpy or memset (string.h). • Depends on absolute time when used inside a triggered subsystem hierarchy. Discrete Filter Support code generation. Discrete FIR Filter PID Controller • Generated code might rely on memcpy or memset (string.h). PID Controller (2DOF) • Depends on absolute time when used inside a triggered subsystem hierarchy. Discrete State-Space Generated code might rely on memcpy or memset (string.h). Discrete Transfer Fcn Discrete Zero-Pole Discrete-Time Integrator Depends on absolute time when used inside a triggered subsystem hierarchy. First-Order Hold Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Memory Support code generation. Tapped Delay 1-100 Supported Products and Block Usage Discrete (Continued) Block Support Notes Transfer Fcn First Order Transfer Fcn Real Zero The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Unit Delay Generated code might rely on memcpy or memset (string.h). Zero-Order Hold Supports code generation. Transfer Fcn Lead or Lag Logic and Bit Operations Block Support Notes Bit Clear Support code generation. Bit Set Bitwise Operator Combinatorial Logic Compare to Constant Compare to Zero Detect Change Generated code might rely on memcpy or memset (string.h). Detect Decrease Detect Fall Negative Detect Fall Nonpositive Detect Increase Detect Rise Nonnegative Detect Rise Positive 1-101 1 Modeling Logic and Bit Operations (Continued) Block Support Notes Extract Bits Support code generation. Interval Test Interval Test Dynamic Logical Operator Relational Operator Shift Arithmetic Lookup Tables Block Support Notes Cosine The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit check box. Direct Lookup Table (n-D) Support code generation. Interpolation Using Prelookup 1-D Lookup Table 2-D Lookup Table n-D Lookup Table Lookup Table Dynamic Prelookup Sine 1-102 The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by Supported Products and Block Usage Lookup Tables (Continued) Block Support Notes configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Math Operations Block Support Notes Abs Support code generation. Add Algebraic Constraint Ignored during code generation. Assignment Support code generation. Bias Complex to Magnitude-Angle Complex to Real-Imag Divide Dot Product Find Nonzero Elements Gain Magnitude-Angle to Complex Math Function (10^u) Math Function (conj) Math Function (exp) Math Function (hermitian) Math Function (hypot) Math Function (log) Math Function (log10) 1-103 1 Modeling Math Operations (Continued) Block Math Function (magnitude^2) Math Function (mod) Math Function (pow) Math Function (reciprocal) Math Function (rem) Math Function (square) Math Function (transpose) Matrix Concatenate MinMax MinMax Running Resettable Permute Dimensions Polynomial Product Product of Elements Real-Imag to Complex Reciprocal Sqrt Reshape Rounding Function Sign Signed Sqrt 1-104 Support Notes Supported Products and Block Usage Math Operations (Continued) Block Support Notes Sine Wave Function • Does not refer to absolute time when configured for sample-based operation. Depends on absolute time when in time-based operation. • Depends on absolute time when used inside a triggered subsystem hierarchy. Slider Gain Support code generation. Sqrt Squeeze Subtract Sum Sum of Elements Trigonometric Function Functions asinh, acosh, and atanh are not supported by all compilers. If you use a compiler that does not support those functions, the software issues a warning for the block and the generated code fails to link. Unary Minus Support code generation. Vector Concatenate Weighted Sample Time Math 1-105 1 Modeling Model Verification Block Support Notes Assertion Supports code generation. Check Discrete Gradient Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Check Dynamic Gap Support code generation. Check Dynamic Lower Bound Check Dynamic Range Check Dynamic Upper Bound Check Input Resolution Check Static Gap Check Static Lower Bound Check Static Range Check Static Upper Bound 1-106 Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Supported Products and Block Usage Model-Wide Utilities Block Support Notes Block Support Table Ignored during code generation. DocBlock Uses the template symbol you specify for the Embedded Coder Flag block parameter to add comments to generated code. Requires an Embedded Coder license. For more information, see “Use a Simulink DocBlock to Add a Comment”. Model Info Ignored during code generation. Timed-Based Linearization Trigger-Based Linearization Ports & Subsystems Block Support Notes Atomic Subsystem Support code generation. CodeReuse Subsystem Configurable Subsystem Enable Enabled Subsystem Enabled and Triggered Subsystem For Each For Each Subsystem For Iterator Subsystem Function-Call Generator Function-Call Split Function-Call Subsystem If 1-107 1 Modeling Ports & Subsystems (Continued) Block Support Notes If Action Subsystem Model Subsystem Switch Case Switch Case Action Subsystem Triggered Subsystem While Iterator Subsystem Signal Attributes Block Support Notes Bus to Vector Support code generation. Data Type Conversion Data Type Conversion Inherited Data Type Duplicate Data Type Propagation Data Type Scaling Strip 1-108 IC Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Probe Supports code generation. Supported Products and Block Usage Signal Attributes (Continued) Block Support Notes Rate Transition • Generated code might rely on memcpy or memset (string.h). • Cannot use inside a triggered subsystem hierarchy. Signal Conversion Support code generation. Signal Specification Weighted Sample Time Width Signal Routing Block Support Notes Bus Assignment Support code generation. Bus Creator Bus Selector Data Store Memory Data Store Read Data Store Write Demux Environment Controller Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. 1-109 1 Modeling Signal Routing (Continued) Block Support Notes From Support code generation. Goto Goto Tag Visibility Index Vector Manual Switch Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Merge When multiple signals connected to a Merge block have a non-Auto storage class, all non-Auto signals connected to that block must be identically labeled and have the same storage class. When Merge blocks connect directly to one another, these rules apply to all signals connected to Merge blocks in the group. Multiport Switch Support code generation. Mux Selector Switch Generated code might rely on memcpy or memset (string.h). Sinks Block Support Notes Display Ignored for code generation. Floating Scope Outport (Out1) 1-110 Supports code generation. Supported Products and Block Usage Sinks (Continued) Block Support Notes Scope Ignored for code generation. Stop Simulation • Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. • Generated code stops executing when the stop condition is true. Terminator Supports code generation. To File Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. To Workspace Ignored for code generation. XY Graph 1-111 1 Modeling Sources Block Support Notes Band-Limited White Noise Cannot use inside a triggered subsystem hierarchy. Chirp Signal Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Clock Constant Supports code generation. Counter Free-Running Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Counter Limited • The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. • Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. 1-112 Supported Products and Block Usage Sources (Continued) Block Support Notes Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Digital Clock Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Enumerated Constant Supports code generation. From File Ignored for code generation. From Workspace Ground Support code generation. Inport (In1) Pulse Generator Cannot use inside a triggered subsystem hierarchy. Does not refer to absolute time when configured for sample-based operation. Depends on absolute time when in time-based operation. Ramp Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Random Number Supports code generation. 1-113 1 Modeling Sources (Continued) Block Support Notes Repeating Sequence • Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. • Consider using the Repeating Sequence Stair or Repeating Sequence Interpolated block instead. Repeating Sequence Interpolated • The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. • Cannot use inside a triggered subsystem hierarchy. Repeating Sequence Stair The Simulink Coder software does not explicitly group primitive blocks that constitute a nonatomic masked subsystem block in the generated code. This flexibility allows for more efficient code generation. In certain cases, you can achieve grouping by configuring the masked subsystem block to execute as an atomic unit by selecting the Treat as atomic unit option. Signal Builder Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Signal Generator 1-114 Supported Products and Block Usage Sources (Continued) Block Support Notes Sine Wave • Depends on absolute time when used inside a triggered subsystem hierarchy. • Does not refer to absolute time when configured for sample-based operation. Depends on absolute time when in time-based operation. Step Not recommended for production code. Relates to resource limits and restrictions on speed and memory often found in embedded systems. Generated code can contain dynamic allocation and freeing of memory, recursion, additional memory overhead, and widely-varying execution times. While the code is functionally valid and generally acceptable in resource-rich environments, smaller embedded targets often cannot support such code. Usually, blocks evolve toward being suitable for production code. Thus, blocks suitable for production code remain suitable. Uniform Random Number Supports code generation. User-Defined Block Support Notes Fcn Supports code generation. Interpreted MATLAB Function Consider using the MATLAB Function block instead. Level-2 MATLAB S-Function Ignored during code generation. MATLAB Function Supports code generation. S-Function S-functions that call into MATLAB are not supported for code generation. S-Function Builder 1-115 1 Modeling Block Set Support for Code Generation Several products that include blocks are available for you to consider for code generation. However, before using the blocks for one of these products, consult the documentation for that product to confirm whether any, all, or a subset of blocks support code generation. Fixed-Point Tool Data Type Override SIL/PIL does not support signals with data types overridden by the Fixed-Point Tool Data type override parameter at the SIL/PIL component boundary. You may see an exception message like the following: Simulink.DataType object 'real_T' is not in scope from 'mpil_mtrig_no_ic_preread/TmpSFcnForModelReference_unitInTopMdl'. This error message is related to a hidden S-Function block. There is no resolution for this issue. Data Type Overrides Unavailable for Most Blocks in Embedded Targets and Desktop Targets When you attempt to perform a datatype override on a block, you may get an error message similar to the following example: Error reported by S-function 'sfun_can_frame_splitter' in 'c2000_host_CAN_monitor/CAN Message Unpacking/CAN Message Unpacking': Incompatible DataType or Size specified. Data type overrides using the Fixed point tool are not available for blocks in Simulink Coder > Desktop Targets and Embedded Coder > Embedded Targets libraries that support fixed-point. There is no resolution for this issue. 1-116 Modeling Semantic Considerations Modeling Semantic Considerations In this section... “Data Propagation” on page 1-117 “Sample Time Propagation” on page 1-119 “Latches for Subsystem Blocks” on page 1-120 “Block Execution Order” on page 1-120 “Algebraic Loops” on page 1-122 Data Propagation The first stage of code generation is compilation of the block diagram. This stage is analogous to that of a C or C++ program. The compiler carries out type checking and preprocessing. Similarly, the Simulink engine verifies that input/output data types of block ports are consistent, line widths between blocks are of expected thickness, and the sample times of connecting blocks are consistent. The Simulink engine propagates data from one block to the next along signal lines. The data propagated consists of • Data type • Line widths • Sample times You can verify what data types any given Simulink block supports by typing showblockdatatypetable at the MATLAB prompt, or (from the Help browser) clicking the command above. The Simulink engine typically derives signal attributes from a source block. For example, the Inport block’s parameters dialog box specifies the signal attributes for the block. 1-117 1 Modeling In this example, the Inport block has a port width of 3, a sample time of .01 seconds, the data type is double, and the signal is complex. This figure shows the propagation of the signal attributes associated with the Inport block through a simple block diagram. In this example, the Gain and Outport blocks inherit the attributes specified for the Inport block. 1-118 Modeling Semantic Considerations Sample Time Propagation Inherited sample times in source blocks (for example, a root inport) can sometimes lead to unexpected and unintended sample time assignments. Since a block may specify an inherited sample time, information available at the outset is often insufficient to compile a block diagram completely. In such cases, the Simulink engine propagates the known or assigned sample times to those blocks that have inherited sample times but that have not yet been assigned a sample time. Thus, the engine continues to fill in the blanks (the unknown sample times) until sample times have been assigned to as many blocks as possible. Blocks that still do not have a sample time are assigned a default sample time. For a completely deterministic model (one where no sample times are set using the above rules), you should explicitly specify the sample times of all your source blocks. Source blocks include root inport blocks and any blocks without input ports. You do not have to set subsystem input port sample times. You might want to do so, however, when creating modular systems. An unconnected input implicitly connects to ground. For ground blocks and ground connections, the sample time is always constant (inf). All blocks have an inherited sample time (Ts = -1). They are assigned a sample time of (Tf - Ti)/50. Constant Block Sample Times You can specify a sample time for Constant blocks. This has certain implications for code generation. When a sample time of inf is selected for a Constant block, • If Inline parameters is on, the block takes on a constant sample time, and propagates a constant sample time downstream. • If Inline parameters is off, the Constant block inherits its sample time – which is nonconstant – and propagates that sample time downstream. Generated code for any block differs when it has a constant sample time; its outputs are represented in the constant block outputs structure instead of in 1-119 1 Modeling the general block outputs structure. The generated code thus reflects that the Constant block propagates a constant sample time downstream if a sample time of inf is specified and Inline parameters is on. Latches for Subsystem Blocks When an Inport block is the signal source for a triggered or function-call subsystem, you can use latch options to preserve input values while the subsystem executes. The Inport block latch options include: For... You Can Use... Triggered subsystems Latch input by delaying outside signal Function-call subsystems Latch input for feedback signals of function-call subsystem outputs When you use Latch input for feedback signals of function-call subsystem outputs for a function-call subsystem, the Simulink Coder code generator • Preserves latches in generated code regardless of any optimizations that might be set • Places the code for latches at the start of a subsystem’s output/update function For more information on these options, see the description of the Inport block in the Simulink documentation. Block Execution Order Once the Simulink engine compiles the block diagram, it creates a model.rtw file (analogous to an object file generated from a C or C++ file). The model.rtw file contains the connection information of the model, as well as the signal attributes. Thus, the timing engine in can determine when blocks with different rates should be executed. You cannot override this execution order by directly calling a block (in handwritten code) in a model. For example, in the next figure the 1-120 Modeling Semantic Considerations disconnected_trigger model on the left has its trigger port connected to ground, which can lead to all blocks inheriting a constant sample time. Calling the trigger function, f(), directly from user code does not work and should never be done. Instead, you should use a function-call generator to specify the rate at which f() should be executed, as shown in the connected_trigger model on the right. f0 1 In1 In1 f0 Out1 Triggered Subsystem Connected Trigger Function-call Generator Disconnected Trigger 1 Out1 1 In1 In1 f0 Out1 1 Out1 Triggered Subsystem Instead of the function-call generator, you could use any other block that can drive the trigger port. Then, you should call the model’s main entry point to execute the trigger function. For multirate models, a common use of the Simulink Coder product is to build individual models separately and then manually code the I/O between the models. This approach places the burden of data consistency between models on the developer of the models. Another approach is to let the Simulink and Simulink Coder products maintain data consistency between rates and generate multirate code for use in a multitasking environment. The Simulink Rate Transition block is able to interface both periodic and asynchronous signals. For a description of the Simulink Coder libraries, see “Handle Asynchronous Events” on page 1-34. For more information on multirate code generation, see “Scheduling” on page 1-4. 1-121 1 Modeling Algebraic Loops Algebraic loops are circular dependencies between variables. This prevents the straightforward direct computation of their values. For example, in the case of a system of equations • x = y + 2 • y = -x the values of x and y cannot be directly computed. To solve this, either repeatedly try potential solutions for x and y (in an intelligent manner, for example, using gradient based search) or “solve” the system of equations. In the previous example, solving the system into an explicit form leads to • 2x = 2 • y = -x • x = 1 • y = -1 An algebraic loop exists whenever the output of a block having direct feedthrough (such as Gain, Sum, Product, and Transfer Fcn) is fed back as an input to the same block. The Simulink engine is often able to solve models that contain algebraic loops, such as the next diagram. 1-122 Modeling Semantic Considerations The Simulink Coder software does not produce code that solves algebraic loops. This restriction includes models that use Algebraic Constraint blocks in feedback paths. However, the Simulink engine can often eliminate all or some algebraic loops that arise, by grouping equations in certain ways in models that contain them. It does this by separating the update and output functions to avoid circular dependencies. See “Algebraic Loops” in the Simulink documentation for details. Algebraic Loops in Triggered Subsystems While the Simulink engine can minimize algebraic loops involving atomic and enabled subsystems, a special consideration applies to some triggered subsystems. An example for which code can be generated is shown in the following model and triggered subsystem. The default Simulink behavior is to combine output and update methods for the subsystem, which creates an apparent algebraic loop, even though the Unit Delay block in the subsystem has no direct feedthrough. You can allow the Simulink engine to solve the problem by splitting the output and update methods of triggered and enabled-triggered subsystems when feasible. If you want the Simulink Coder code generator to take advantage of this feature, select the Minimize algebraic loop occurrences check box in the Subsystem Parameters dialog box. Select this option to avoid algebraic loop warnings in triggered subsystems involved in loops. 1-123 1 Modeling Note If you always check this box, the generated code for the subsystem might contain split output and update methods, even if the subsystem is not actually involved in a loop. Also, if a direct feedthrough block (such as a Gain block) is connected to the inport in the above triggered subsystem, the Simulink engine cannot solve the problem, and the Simulink Coder software is unable to generate code. A similar Minimize algebraic loop occurrences option appears on the Model Referencing pane of the Configuration Parameters dialog box. Selecting it enables the Simulink Coder software to generate code for models containing Model blocks that are involved in algebraic loops. 1-124 2 Subsystems • “Code Generation of Subsystems” on page 2-2 • “Generate Code and Executables for Individual Subsystem” on page 2-4 • “Inline Subsystem Code” on page 2-7 • “Generate Subsystem Code as Separate Function and Files” on page 2-10 • “Generate Reusable Function for Identical Subsystems Within a Model” on page 2-11 • “Optimize Code for Identical Nested Subsystems” on page 2-14 • “Generate Reusable Code for Subsystems Containing S-Function Blocks” on page 2-15 • “Generate Reusable Code from Stateflow Charts” on page 2-16 • “Code Reuse Limitations for Subsystems” on page 2-17 • “Code Reuse For Subsystems Shared Across Referenced Models” on page 2-19 • “Reusable Library Subsystem” on page 2-20 • “Code Generation of Constant Parameters” on page 2-22 • “Shared Constant Parameters for Code Reuse” on page 2-23 • “Generate Reusable Code for Subsystems Shared Across Models” on page 2-25 • “Determine Why Subsystem Code Is Not Reused” on page 2-32 2 Subsystems Code Generation of Subsystems For you to control how code is generated for any nonvirtual subsystem, the Simulink Coder software provides subsystem parameters that you can use. The categories of nonvirtual subsystems are: • Conditionally executed subsystems. Execution depends upon a control signal or control block. These subsystems include: - Triggered Enabled Action Iterator Function-call For more information, see “About Conditional Subsystems”. • Atomic subsystems: Any virtual subsystem can be declared atomic (and therefore nonvirtual) by using the “Treat as atomic unit” parameter in the Subsystem Parameters dialog box. For more information on nonvirtual subsystems and atomic subsystems, see “Systems and Subsystems” and run the sl_subsys_semantics model. You can design and configure your model to control the code generated from nonvirtual subsystems. 2-2 To... See... Generate inlined code from a selected nonvirtual subsystem. “Inline Subsystem Code” on page 2-7 Generate code for only a subsystem. “Generate Code and Executables for Individual Subsystem” on page 2-4 Generate separate functions with no arguments, and optionally place the subsystem code in a separate file. “Generate Subsystem Code as Separate Function and Files” on page 2-10 Code Generation of Subsystems To... See... Generate a single reentrant function for a subsystem that is included in multiple places within a model. “Generate Reusable Function for Identical Subsystems Within a Model” on page 2-11 Generate a single reentrant function for a subsystem that is included in multiple places in a model reference hierarchy. “Generate Reusable Code for Subsystems Shared Across Models” on page 2-25 and “Code Reuse For Subsystems Shared Across Referenced Models” on page 2-19 Note If you generate code for a virtual subsystem, code generator treats the subsystem as atomic and generates the code accordingly. The resulting code can change the execution behavior of your model, for example, by applying algebraic loops, and therefore introduce inconsistencies with the simulation behavior. Declare virtual subsystems as atomic subsystems, which makes simulation and execution behavior consistent for your model consistent. Subsystem Code Dependence Code generated from nonvirtual subsystems may or may not be completely independent of the generating model. When generating code for a subsystem, the code may reference global data structures of the model, even if the subsystem code is in a separate file. Each subsystem code file contains include directives and comments describing the dependencies. The Simulink Coder software checks for cyclic file dependencies and warns about them at build time. For descriptions of how generated code is packaged, see “Generated Source Files and File Dependencies” on page 10-4. To generate subsystem code that is independent of the generating model, place the subsystem in a library and configure it as a reusable subsystem. For more information, see “Code Reuse For Subsystems Shared Across Referenced Models” on page 2-19. 2-3 2 Subsystems Generate Code and Executables for Individual Subsystem You can generate code and build an executable for a subsystem within a model. The code generation and build process uses the code generation and build parameters of the root model. 1 In the Configuration Parameters dialog box, set up the code generation and build parameters, similar to setting up the code generation for a model. 2 Right-click the Subsystem block. From the context menu, select C/C++ Code > Build This Subsystem from the context menu. Alternatively, in the current model, click a subsystem and then from the Code menu, select C/C++ Code > Build Selected Subsystem. Note When you select Build This Subsystem, if the model is operating in external mode, the Simulink Coder build process automatically turns off external mode for the duration of the build. Simulink Coder then restores external mode upon completion of the build process. 2-4 Generate Code and Executables for Individual Subsystem 3 The Build code for Subsystem window displays a list of the subsystem parameters. The upper pane displays the name, class, and storage class of each variable (or data object) that is referenced as a block parameter in the subsystem. When you select a parameter in the upper pane, the lower pane shows all the blocks that reference the parameter and the parent system of each block. The Storage Class column contains a menu for each row. The menu options set the storage class or inline the parameter. To declare a parameter to be tunable, set the Storage Class to any value other than Inlined. For more information on tunable and inlined parameters and storage classes, see “Parameters” on page 7-10. 4 After selecting tunable parameters, Build to initiate the code generation and build process. 2-5 2 Subsystems 5 The build process displays status messages in the MATLAB Command Window. When the build is complete, the generated executable is in your working folder. The name of the generated executable is subsystem.exe (on PC platforms) or subsystem (on The Open Group UNIX platforms). subsystem is the name of the source subsystem block. The generated code is in a build subfolder, named subsystem_target_rtw. subsystem is the name of the source subsystem block and target is the name of the target configuration. When you generate code for a subsystem, you can generate an S-function by selecting Code > C/C++ Code> Generate S-Function, or you can use the right-click subsystem build. For more information on S-functions, see “Automate S-Function Generation” on page 14-23 and in Embedded Coder, “Generate S-Function Wrappers”. Subsystem Build Limitations The following limitations apply to building subsystems: • When you right-click build a subsystem that includes an Outport block for which the Data type parameter specifies a bus object, you must address errors that result from setting signal labels. To configure the software to display these errors, in the Configuration Parameters dialog box for the parent model, on the Diagnostics > Connectivity pane, set the Signal label mismatch parameter to error. • When a subsystem is in a triggered or function-call subsystem, the right-click build process might fail if the subsystem code is not sample-time independent. To find out whether a subsystem is sample-time independent: 1 Copy all blocks in the subsystem to an empty model. 2 In the Configuration Parameters dialog box, on the Solver pane, set: a. Type to Fixed-step. b. Periodic sample time constraint to Ensure sample time independent. c. Click Apply. 3 Update the model. If the model is sample-time dependent, Simulink generates an error in the process of updating the diagram. 2-6 Inline Subsystem Code Inline Subsystem Code You can configure a nonvirtual subsystem to inline the subsystem code with the model code. In the Subsystem Parameters dialog box, setting the Function packaging parameter to Auto or Inline inlines the generated code of the subsystem. The Auto option is the default. When there is only one instance of a subsystem in the model, the Auto option inlines the subsystem code. When multiple instances of a subsystem exist, the Auto option results in a single copy of the function (as a reusable function). For function-call subsystems with multiple callers, the subsystem code is generated as if you specified Function. To always inline subsystem code, select Inline. The Inline option explicitly directs the code generator to inline the subsystem unconditionally. Configure Subsystem to Inline Code To configure your subsystem for inlining: 1 Right-click the Subsystem block. From the context menu, select Block Parameters (Subsystem). 2 In the Subsystem Parameters dialog box, if the subsystem is virtual, select Treat as atomic unit. This option makes the subsystem nonvirtual. On the Code Generation tab, the Function packaging option is now available. If the system is already nonvirtual, the Function packaging option is already selected. 3 Click the Code Generation tab and select Auto or Inline from the Function packaging parameter. 2-7 2 Subsystems 4 Click Apply and close the dialog box. The border of the subsystem thickens, indicating that it is nonvirtual. When you generate code from your model, the code generator inlines subsystem code within model.c or model.cpp (or in its parent system’s source file). You can identify this code by system/block identification tags, such as: /* Atomic SubSystem Block: /AtomicSubsys1 */ Exceptions to Inlining There are certain cases in which the code generator does not inline a nonvirtual subsystem, even though the Inline option is selected. • If the subsystem is a function-call subsystem that is called by a noninlined S-function, the Inline option is ignored. Noninlined S-functions make calls 2-8 Inline Subsystem Code by using function pointers. Therefore, the function-call subsystem must generate a function with all arguments present. • In a feedback loop involving function-call subsystems, the code generator forces one of the subsystems to be generated as a function instead of inlining it. Based on the order in which the subsystems are sorted internally, the software selects the subsystem to be generated as a function. • If a subsystem is called from an S-function block that sets the option SS_OPTION_FORCE_NONINLINED_FCNCALL to TRUE, it is not inlined. When user-defined Async Interrupt blocks or Task Sync blocks are present, this result might occur. Such blocks must be generated as functions. These blocks are located in the VxWorks block library (vxlib1) shipped with the Simulink Coder product and use the SS_OPTION_FORCE_NONINLINED_FCNCALL option.2 2. VxWorks® is a registered trademark of Wind River® Systems, Inc. 2-9 2 Subsystems Generate Subsystem Code as Separate Function and Files To generate both a separate subsystem function and a separate file for a subsystem in a model: 1 Right-click a Subsystem block. From the context menu, select Block Parameters (Subsystem). 2 In the Subsystem Parameters dialog box, if the subsystem is virtual, select Treat as atomic unit. On the Code Generation tab, the Function packaging parameter is now available. 3 Click the Code Generation tab and select Function from the Function packaging parameter. The Function option enables two parameters: • The “Function name options” parameter controls the naming of the generated function. • The “File name options” parameter controls the naming of the generated file. 4 Set the Function name options parameter. 5 Set the File name options parameter to a value other than Auto. If you are generating a reusable function for your subsystem, see “Generate Reusable Function for Identical Subsystems Within a Model” on page 2-11 or “Generate Reusable Code for Subsystems Shared Across Models” on page 2-25. 6 Click Apply and close the dialog box. 2-10 Generate Reusable Function for Identical Subsystems Within a Model Generate Reusable Function for Identical Subsystems Within a Model In the Subsystem Parameters dialog box, the Function packaging parameter option Function generates functions that use global data. The Reusable function option generates reusable functions that have data passed as arguments (enabling them to be reentrant). Selecting Reusable function generates a function with arguments that allows the subsystem code to be shared by other instances of it in the model. This action supports less code instead of replicating the code for each instance of a subsystem or each time it is called. To determine reusability of the subsystem code, the code generator performs a checksum to determine if subsystems are identical. The generated function has arguments, for example, for block inputs and outputs (rtB_*), continuous states (rtDW_*), parameters (rtP_*). Note In the generated code, the call interface is subject to change from release to release. Therefore, do not directly call reusable functions from external code. To generate one reusable function for identical subsystems within a model: 1 Right-click the Subsystem block. From the context menu, select Block Parameters (Subsystem). 2 In the Subsystem Parameters dialog box, if the subsystem is virtual, select Treat as atomic unit. On the Code Generation tab, the Function packaging menu is now available. If the subsystem is already nonvirtual, the Function packaging menu is already selected. 3 Click the Code Generation tab and select Reusable function for the Function packaging parameter. 2-11 2 Subsystems For more information about this setting, see “Considerations for Function Packaging Options Auto and Reusable function” on page 2-13. 4 Set the function name using the “Function name options” parameter. Note If you do not choose Auto, for all other Subsystem blocks that you want to share this code, specify the same function name for those Subsystem blocks. 5 Set the file name using the “File name options” parameter to a value other than Auto. If your generated code is under source control, a value other than Auto prevents the generated file name from changing due to unrelated model modifications. 2-12 Generate Reusable Function for Identical Subsystems Within a Model Note For all other Subsystem blocks that you want to share this code, specify the same file name for those Subsystem blocks. 6 Click Apply and close the dialog box. For a summary of code reuse limitations, see “Code Reuse Limitations for Subsystems” on page 2-17. Considerations for Function Packaging Options Auto and Reusable function When you want multiple instances of a subsystem to be represented as one reusable function, you can designate each one of them as Auto or as Reusable function. Use one or the other, because using both creates two reusable functions, one for each specification. The outcomes of these choices differ only when reuse is not possible. Selecting Auto does not allow control of the function or file name for the subsystem code. The Reusable function and Auto options both try to determine if multiple instances of a subsystem exist and if the code can be reused. When reuse is not possible, there are differences in the options behavior: • Auto yields inlined code. If circumstances prohibit inline, then the generated code is separate functions without arguments for each subsystem instance. • Reusable function yields a separate function with arguments for each subsystem instance in the model. 2-13 2 Subsystems Optimize Code for Identical Nested Subsystems The Function packaging parameter Auto option can optimize code in situations in which identical subsystems contain other identical subsystems, by both reusing and inlining generated code. Suppose a model, such as the one shown in Reuse of Identical Nested Subsystems on page 2-14, contains identical subsystems A1 and A2. A1 contains subsystem B1, and A2 contains subsystem B2, which are identical. In such cases, the Auto option causes one function to be generated which is called for both A1 and A2. This function contains one piece of inlined code to execute B1 and B2. This optimization generates less code which improves execution speed. Reuse of Identical Nested Subsystems 2-14 Generate Reusable Code for Subsystems Containing S-Function Blocks Generate Reusable Code for Subsystems Containing S-Function Blocks There are several requirements that need to be met in order for subsystems containing S-function blocks to be reused. For the list of requirements, see “S-Functions That Support Code Reuse” on page 14-113. When you select the Reusable function option, two additional options are enabled, Function name options and File name options. If you use these fields to enter a function name and/or a file name, you must specify exactly the same function name and file name for each instance of identical subsystems for the code generator to reuse the subsystem code. For an example, follow the procedure in “Generate Reusable Function for Identical Subsystems Within a Model” on page 2-11. 2-15 2 Subsystems Generate Reusable Code from Stateflow Charts You can generate reusable code from a Stateflow chart, or from a subsystem containing a chart, except in the following cases: • The Stateflow chart contains exported graphical functions. • The Stateflow model contains machine parented events. 2-16 Code Reuse Limitations for Subsystems Code Reuse Limitations for Subsystems The code generator uses a checksum to determine whether subsystems are identical and reusable. Subsystem code is not reused, if: • Multiple ports of a subsystem share the same source. • A port used by multiple instances of a subsystem has different sample times, data types, complexity, frame status, or dimensions across the instances. • The output of a subsystem is marked as a global signal. • Subsystems contain identical blocks with different names or parameter settings. • The output of a subsystem is connected to a Merge block, and the output of the Merge block is a custom storage class that is implemented in the C code as memory that is nonaddressable (for example, BitField). • The input of a subsystem is nonscalar and has a custom storage class that is implemented in the C code as memory that is nonaddressable. • A masked subsystem has a parameter that is nonscalar and has a custom storage class that is implemented in the C code as memory that is nonaddressable. If you select Reusable function, and the code generator determines that code for a subsystem cannot be reused, it generates a separate function that is not reused. The code generation report might show that the separate function is reusable, even if it is used by only one subsystem. If you prefer that subsystem code be inlined in such circumstances rather than deployed as functions, then choose Auto for the Function packaging option. Blocks That Prevent Code Reuse Use of the following blocks in a subsystem can also prevent the subsystem code from being reused: • Scope blocks (with data logging enabled) • S-Function blocks that fail to meet certain criteria (see “S-Functions That Support Code Reuse” on page 14-113) 2-17 2 Subsystems • To File blocks (with data logging enabled) • To Workspace blocks (with data logging enabled) Code Reuse Limitations for Subsystems Shared Across Referenced Models The code generator uses a checksum to determine whether reusable library subsystems are identical. The reusable library subsystem code is placed in the shared utilities folder and is independent of the generated code of the top model or the referenced model. For example, the reusable library subsystem code does not include model.h or model_types.h. Reusable code that is generated to the shared utilities folder and is dependent on the model code does not compile. If the code generator determines that the reusable library subsystem code is dependent on the model code, the reusable subsystem code is not generated to the shared utilities folder. The following cases might generate code that is dependent on the model code, when the reusable library subsystem: • Contains a block that uses time-related functionality, such as a Step block, or continuous time or multirate blocks. • Contains one or more Model blocks. • Contains subsystems that are not inlined or a reusable library subsystem. • Contains a For Each subsystem and the model configuration parameter, Inline parameters, is cleared. In this case, types are defined in model_types.h. • Contains a signal that is not an Auto storage class. Variables of non-Auto storage classes are generated to model.h. • Contains a parameter that is not an Auto storage class. • Contains a user-defined type where Data Scope is not set to Exported. The code generator might place the type definition in model_types.h. • Is a variant subsystem that generates preprocessor conditionals. Preprocessor directives defining the variant objects are included in model_types.h. 2-18 Code Reuse For Subsystems Shared Across Referenced Models Code Reuse For Subsystems Shared Across Referenced Models To reuse common functionality, you can include multiple instances of a subsystem within a model and across referenced models. To generate a reusable function for a subsystem which is included in multiple referenced models: • If the subsystem is in a model reference hierarchy, set the configuration parameter, Shared code placement to Auto. Otherwise, for each model that uses the subsystem, set Shared code placement to Shared location. The Shared code placement parameter is in the Configuration Parameters dialog box, on the Code Generation > Interface pane. • The subsystem must be defined in a library and configured for reuse. This subsystem is referred to as a reusable library subsystem. For more information, see “Reusable Library Subsystem” on page 2-20. For an example, see “Generate Reusable Code for Subsystems Shared Across Models” on page 2-25. The code generator performs a checksum to determine reusability. There are cases when the code generator cannot reuse subsystem code. For more information, see “Code Reuse Limitations for Subsystems” on page 2-17. 2-19 2 Subsystems Reusable Library Subsystem A reusable library subsystem is a subsystem included in a library that is configured for reuse. The Subsystem parameters must be set as follows: • Treat as an atomic unit is selected. • On the Code Generation tab: - Function packaging is set to Reusable function. Function name options and File name options are set to Auto or Use subsystem name. For more information on creating a library, see “Libraries”. For an example of creating a reusable library subsystem, see “Generate Reusable Code for Subsystems Shared Across Models” on page 2-25. Code Generation of a Reusable Library Subsystem For incremental code generation, if the reusable library subsystem changes, a rebuild of itself and its parents occurs. During the build, if a matching function is not found, a new instance of the reusable function is generated into the shared utilities folder. If a different matching function is found from previous builds, that function is used, and a new reusable function is not emitted. For subsequent builds, unused files are not replaced or deleted from your folder. During development of a model, when many obsolete shared functions exist in the shared utilities folder, you can delete the folder and regenerate the code. If all instances of a reusable library subsystem are removed from a model reference hierarchy and you regenerate the code, the obsolete shared functions remain in the shared utilities folder until you delete them. If a model changes such that the change might cause different generated code for the subsystem, a new reusable function is generated. For example, model configuration parameters that modify code comments might cause different generated code for the subsystem even if the reusable library subsystem did not change. 2-20 Reusable Library Subsystem Reusable Library Subsystem Code Placement and Naming The code generator uses checksums to determine reusability. The generated code of a reusable library subsystem is independent of the generated code of the model. Code for the reusable library subsystem is generated to the shared utility folder, slprj/target/_sharedutils, instead of the model reference hierarchy folders. The generated code for the supporting types, which are generated to the .h file, are also in the shared utilities folder. In the Subsystem Parameters dialog box, the Function name options and File name options must be set to Auto or Use subsystem name. For unique naming, reusable function names have a checksum string appended to the reusable library subsystem name. For example, the code and files for a subsystem, SS1, which links to a reusable library subsystem, RLS, might be: • Function name: RLS_mgdjlngd • File name: RLS_mgdjlnd.c and RLS_mgdjlnd.h Reusable Library Subsystem in the Top Model In a model reference hierarchy, if an instance of the reusable library subsystem is in the top model, then on the Model Referencing pane of the Configuration Parameters dialog box, you must select the Pass fixed-size scalar root input by value for code generation parameter. If you do not select the parameter, a separate shared function is generated for the reusable library subsystem instance in the top model, and a reusable function is generated for instances in the referenced models. Reusable Library Subsystem Connected to Root Outport If a reusable library subsystem is connected to the root outport, reuse does not happen with identical subsystems that are not connected to the root outport. However, you can set Pass reusable system outputs as to Individual arguments on the Optimizations > Signals and Parameters pane to make sure that reuse occurs between these subsystems. This parameter requires an Embedded Coder license. 2-21 2 Subsystems Code Generation of Constant Parameters The code generator attempts to generate constant parameters to the shared utilities folder first. If constant parameters are not generated to the shared utilities folder, they are defined in the top model in a global constant parameter structure. The declaration of the structure, ConstParam_model, is in model.h: /* Constant parameters (auto storage) */ typedef struct { /* Expression: [1 2 3 4 5 6 7] * Referenced by: ' /Constant' */ real_T Constant_Value[7]; /* Expression: [7 6 5 4 3 2 1] * Referenced by: ' /Gain' */ real_T Gain_Gain[7]; } ConstParam_model; The definition of the constant parameters, model_constP, is in: /* Constant parameters (auto storage) */ const ConstParam_model model_ConstP = { /* Expression: [1 2 3 4 5 6 7] * Referenced by: ' /Constant' */ { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 }, /* Expression: [7 6 5 4 3 2 1] * Referenced by: ' /Gain' */ { 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 } }; The model_constP is passed as an argument to referenced models. For more information on how shared constants are generated, see “Shared Constant Parameters for Code Reuse” on page 2-23. 2-22 Shared Constant Parameters for Code Reuse Shared Constant Parameters for Code Reuse You can share the generated code for constant parameters across models if: • Constant parameters are shared in a model reference hierarchy, or • On the Code Generation > Interface pane, the model configuration parameter Shared code placement is set to Shared location. The shared constant parameters are generated individually to the const_params.c file, which is placed in the shared utilities folder slprj/target/_sharedutils. For example, if a constant has multiple uses within a model reference hierarchy where the top model is named topmod, the code for the shared constant is as follows: • In the shared utility folder, slprj/grt/_sharedutils, the constant parameters are defined in const_params.c and named rtCP_pooled_ appended to a unique checksum string: extern const real_T rtCP_pooled_lfcjjmohiecj[7]; const real_T rtCP_pooled_lfcjjmohiecj[7] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 }; extern const real_T rtCP_pooled_ppphohdbfcba[7]; const real_T rtCP_pooled_ppphohdbfcba[7] = { 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 }; • In top_model_private.h or in any referenced model, ref_model_private.h, for better readability, the constants are renamed as follows: extern const real_T rtCP_pooled_lfcjjmohiecj[7]; extern const real_T rtCP_pooled_ppphohdbfcba[7]; #define rtCP_Constant_Value rtCP_pooled_lfcjjmohiecj /* Expression: [1 2 3 4 5 6 7] #define rtCP_Gain_Gain rtCP_pooled_ppphohdbfcba /* Expression: [7 6 5 4 3 2 1] * Referenced by: ' /Constant'*/ * Referenced by: ' /Gain' */ • In topmod.c or refmod.c, the call site might be: 2-23 2 Subsystems for (i = 0; i < 7; i++) { topmod_Y.Out1[i] = (topmod_U.In1 + rtCP_Constant_Value[i]) * rtCP_Gain_Gain[i]; } The code generator attempts to generate all constants as individual constants to the const_params.c file in the shared utilities folder. Otherwise, constants are generated as described in “Code Generation of Constant Parameters” on page 2-22. Shared Constant Parameters Limitations No shared constants or shared functions are generated for a model when: • The model has a Code Replacement Library (CRL) that is specified for data alignment. • The model is specified to replace data type names in the generated code. • The Memory Section for constants is MemVolatile or MemConstVolatile. Individual constants are not shared, if: • A constant is referenced by a non-inlined S-function. • A constant has a user-defined type where Data Scope is not set to Exported. 2-24 Generate Reusable Code for Subsystems Shared Across Models Generate Reusable Code for Subsystems Shared Across Models This example shows you how to configure a reusable library subsystem and generate a reusable function for a subsystem shared across referenced models. The result is reusable code for the subsystem, which is generated to the shared utility folder (slprj/target/_sharedutils). For more information about a reusable library subsystem, see “Code Reuse For Subsystems Shared Across Referenced Models” on page 2-19. Create a reusable library subsystem. 1 In the Simulink Editor, select File > New > Library. Open rtwdemo_ssreuse to copy and paste subsystem SS1 into the Library Editor. This action loads the variables for SS1 into the base workspace. Rename the subsystem block to RLS. 2 Click the Subsystem block and press Ctrl+U to view the contents of subsystem RLS. 2-25 2 Subsystems 3 To configure the subsystem, in the Library editor, right-click RLS. In the context menu, select Block Parameters(Subsystem). In the Subsystem Parameters dialog box, choose the following options: • Select Treat as an atomic unit. • On the Code Generation tab: – Set Function packaging to Reusable function. – Set Function name options and File name options to Auto. 4 Click Apply and OK. 5 Save the reusable library subsystem as ssreuselib, which creates a file, ssreuselib.slx. Create the example model. 1 Create a model which includes one instance of RLS from ssreuselib. Name this subsystem SS1. Add another subsystem and name it SS2. Name the model ex_model1. 2-26 Generate Reusable Code for Subsystems Shared Across Models 2 Create another model which includes one instance of RLS from ssreuselib. Name this subsystem SS1. Add another subsystem and name it SS3. Name the model ex_model2. 2-27 2 Subsystems 3 Create a top model with two model blocks that reference ex_model1 and ex_model2. Save the top model as ex_mdlref_ssreuse. Set configuration parameters of the top model. 2-28 Generate Reusable Code for Subsystems Shared Across Models 1 With model ex_mdlref_ssreuse open in the Simulink Editor, select Simulation > Model Configuration Parameters to open the Configuration Parameters dialog box. 2 On the Optimization > Signals and Parameters pane, select Inline parameters. 3 On the Solver pane, specify the Type as Fixed-step. 4 On the Code Generation > Report pane, select Create code generation report and Open report automatically. 5 On the Code Generation > Interface pane, set the Shared code placement to Shared location. 6 On the Code Generation > Symbols pane, set the Maximum identifier length to 256. This step is optional. 7 Click Apply and OK. Create and propagate a configuration reference. 1 In the Simulink Editor, select View > Model Explorer to open the Model Explorer. In the left navigation column of the Model Explorer, expand the ex_mdlref_ssreuse node. 2 Right-click Configuration and select Convert to Configuration Reference. 3 In the Convert Active Configuration to Reference dialog box, click OK. This action converts the model configuration set to a configuration reference, Simulink.ConfigSetRef, and creates the configuration reference object, configSetObj, in the base workspace. 4 In the left navigation column, right-click Reference (Active) and select Propagate to Referenced Models. 5 In the Configuration Reference Propagation to Referenced Models dialog box, select the referenced models in the list. Click Propagate. Now, the top model and reference models all use the same configuration reference, Reference (Active), which points to a model configuration 2-29 2 Subsystems reference object, configSetObj, in the base workspace. When you save your model, you also need to export the configSetObj to a MAT-file. For more information, see “Save a Referenced Configuration Set”. Generate and view the code. 1 To generate code, in the Simulink Editor, press Ctrl-B. After the code is generated, the code generation report opens. 2 To view the code generation report for a referenced model, in the left navigation pane, in the Referenced Models section, select ex_model1. The code generation report displays the generated files for ex_model1. 3 In the left navigation pane, expand the Shared Utility files. The code generator uses the reusable library subsystem name and a unique string to name the reused function. The code for subsystem SS1 is in RLS_aaaippph.c and RLS_aaaippph.h. 2-30 Generate Reusable Code for Subsystems Shared Across Models 4 Click Back and navigate to the ex_model2 code generation report. ex_model2 uses the same source code, RLS_aaaippph.c and RLS_aaaippph.h, as the code for ex_model1. Your subsystem function and file names will be different. Related Examples • “Determine Why Subsystem Code Is Not Reused” on page 2-32 • “Share a Configuration Across Referenced Models” • “Generate Reusable Function for Identical Subsystems Within a Model” on page 2-11 Concepts • “Code Generation of Subsystems” on page 2-2 • “Code Reuse For Subsystems Shared Across Referenced Models” on page 2-19 • “Code Reuse Limitations for Subsystems” on page 2-17 • “Libraries” 2-31 2 Subsystems Determine Why Subsystem Code Is Not Reused Due to the limitations described in “Code Reuse Limitations for Subsystems” on page 2-17, the code generator might not reuse generated code as you expect. To determine why code generated for a subsystem is not reused, see “Review the Subsystems Section of the HTML Code Generation Report” on page 2-32. If you cannot determine why based on the report, see “Compare Subsystem Checksum Data” on page 2-32. Review the Subsystems Section of the HTML Code Generation Report If you determine that the code generator does not generate code for a subsystem as reusable code, and you specified the subsystem as reusable, examine the Subsystems section of the HTML code generation report (see “Generate a Code Generation Report” on page 11-5). The Subsystems section contains: • A table that summarizes how nonvirtual subsystems were converted to generated code. • Diagnostic information that describes why the contents of some subsystems were not generated as reusable code. The Subsystems section also indicates the mapping of each noninlined subsystem in the model to functions or reused functions in the generated code. For an example, open and build the rtwdemo_atomic model. Compare Subsystem Checksum Data You can determine why subsystem code is not reused by accessing and comparing subsystem checksum data. The code generator determines whether subsystems are identical by comparing subsystem checksums, as noted in “Code Reuse Limitations for Subsystems” on page 2-17. For subsystem reuse across referenced models, this procedure might not catch every difference. Consider the model, rtwdemo_ssreuse. SS1 and SS2 are instances of the same subsystem. In both instances the subsystem parameter Function packaging is set to Reusable function. 2-32 Determine Why Subsystem Code Is Not Reused Use the method, Simulink.SubSystem.getChecksum, to get the checksum for a subsystem. Compare the results to determine why code is not reused. 1 Open the model rtwdemo_ssreuse. Save a copy of the model in a folder where you have write access. 2 In the model window, select subsystem SS1. In the command window, enter SS1 = gcb; 3 In the model window, select subsystem SS2. In the command window, enter SS2 = gcb; 4 Use the method, Simulink.SubSystem.getChecksum, to get the checksum for each subsystem. This method returns two output values: the checksum value and details on the input used to compute the checksum. [chksum1, chksum1_details] = ... Simulink.SubSystem.getChecksum(SS1); [chksum2, chksum2_details] = ... Simulink.SubSystem.getChecksum(SS2); 5 Compare the two checksum values. They should be equal based on the subsystem configurations. isequal(chksum1, chksum2) ans = 1 6 To see how you can use Simulink.SubSystem.getChecksum to determine why the checksums of two subsystems differ, change the data type mode of the output port of SS1 so that it differs from that of SS2. a Look under the mask of SS1. Right-click the subsystem. In the context menu, select Mask > Look Under Mask. b In the block diagram of the subsystem, double-click the Lookup Table block to open the Subsystem Parameters dialog box. c Click Data Types. 2-33 2 Subsystems d Select Saturate on integer overflow and click OK. 7 Get the checksum for SS1. Compare the checksums for the two subsystems. This time, the checksums are not equal. [chksum1, chksum1_details] = ... Simulink.SubSystem.getChecksum(SS1); isequal(chksum1, chksum2) ans = 0 8 After you determine that the checksums are different, find out why. The Simulink engine uses information, such as signal data types, some block parameter values, and block connectivity information, to compute the checksums. To determine why checksums are different, you compare the data used to compute the checksum values. You can get this information from the second value returned by Simulink.SubSystem.getChecksum, which is a structure array with four fields. Look at the structure chksum1_details. chksum1_details chksum1_details = ContentsChecksum: InterfaceChecksum: ContentsChecksumItems: InterfaceChecksumItems: [1x1 struct] [1x1 struct] [287x1 struct] [53x1 struct] ContentsChecksum and InterfaceChecksum are component checksums of the subsystem checksum. The remaining two fields, ContentsChecksumItems and InterfaceChecksumItems, contain the checksum details. 9 Determine whether a difference exists in the subsystem contents, interface, or both. For example: isequal(chksum1_details.ContentsChecksum.Value,... chksum2_details.ContentsChecksum.Value) ans = 0 2-34 Determine Why Subsystem Code Is Not Reused isequal(chksum1_details.InterfaceChecksum.Value,... chksum2_details.InterfaceChecksum.Value) ans = 1 In this case, differences exist in the contents. 10 Write a script like the following to find the differences. idxForCDiffs=[]; for idx = 1:length(chksum1_details.ContentsChecksumItems) if (~strcmp(chksum1_details.ContentsChecksumItems(idx).Identifier, ... chksum2_details.ContentsChecksumItems(idx).Identifier)) disp(['Identifiers different for contents item ', num2str(idx)]); idxForCDiffs=[idxForCDiffs, idx]; end if (ischar(chksum1_details.ContentsChecksumItems(idx).Value)) if (~strcmp(chksum1_details.ContentsChecksumItems(idx).Value, ... chksum2_details.ContentsChecksumItems(idx).Value)) disp(['String values different for contents item ', num2str(idx)]); idxForCDiffs=[idxForCDiffs, idx]; end end if (isnumeric(chksum1_details.ContentsChecksumItems(idx).Value)) if (chksum1_details.ContentsChecksumItems(idx).Value ~= ... chksum2_details.ContentsChecksumItems(idx).Value) disp(['Numeric values different for contents item ', num2str(idx)]); idxForCDiffs=[idxForCDiffs, idx]; end end end 11 Run the script. The following example assumes that you named the script check_details. check_details String values different for contents item 202 The results indicate that differences exist for index item 202 in the subsystem contents. 2-35 2 Subsystems 12 Use the returned index values to get the handle, identifier, and value details for each difference found. chksum1_details.ContentsChecksumItems(202) ans = Handle: 'rtwdemo_ssreuse/SS1/Lookup Table' Identifier: 'SaturateOnIntegerOverflow' Value: 'on' The details identify the Lookup Table block parameter Saturate on integer overflow as the focus for debugging a subsystem reuse issue. 2-36 3 Referenced Models 3 Referenced Models Code Generation for Referenced Models This section describes model referencing considerations that apply specifically to code generation by the Simulink Coder. This section assumes that you understand referenced models and related terminology and requirements, as described in “Overview of Model Referencing” and associated topics. When generating code for a referenced model hierarchy, the code generator produces a stand-alone executable for the top model, and a library module called a model reference target for each referenced model. When the code executes, the top executable invokes the model reference targets to compute the referenced model outputs. Model reference targets are sometimes called Simulink Coder targets. Be careful not to confuse a model reference target (Simulink Coder target) with any of these other types of targets: • Hardware target — A platform for which the Simulink Coder software generates code • System target — A file that tells the Simulink Coder software how to generate code for particular purpose • Rapid Simulation target (RSim) — A system target file supplied with the Simulink Coder product • Simulation target — A MEX-file that implements a referenced model that executes with Simulink Accelerator™ software The code generator places the code for the top model of a hierarchy in the current working folder, and the code for submodels in a folder named slprj within the current working folder. Subfolders in slprj provide separate places for different types of files. See “Project Folder Structure for Model Reference Targets” on page 3-16 for details. By default, the product uses incremental code generation. When generating code, it compares structural checksums of referenced model files with the generated code files to determine whether to regenerate model reference targets. To control when rebuilds occur, use the configuration parameter Model Referencing > Rebuild. For details, see “Rebuild”. 3-2 Code Generation for Referenced Models In addition to incremental code generation, the Simulink Coder software uses incremental loading. The code for a referenced model is not loaded into memory until the code for its parent model executes and needs the outputs of the referenced model. The product then loads the referenced model target and executes. Once loaded, the target remains in memory until it is no longer used. Most code generation considerations are the same whether or not a model includes any referenced models: the code generator handles the details automatically insofar as possible. This chapter describes topics that you may need to consider when generating code for a model reference hierarchy. If you have a Embedded Coder license, custom targets must declare themselves to be model reference compliant if they need to support Model blocks. For more information, see “Support Model Referencing” on page 24-101. 3-3 3 Referenced Models Generate Code for Referenced Models In this section... “About Generating Code for Referenced Models” on page 3-4 “Create and Configure the Subsystem” on page 3-4 “Convert Model to Use Model Referencing” on page 3-7 “Generate Model Reference Code for a GRT Target” on page 3-11 “Work with Project Folders” on page 3-14 About Generating Code for Referenced Models To generated code for referenced models, you 1 Create a subsystem in an existing model. 2 Convert the subsystem to a referenced model (Model block). 3 Call the referenced model from the top model. 4 Generate code for the top model and referenced model. 5 Explore the generated code and the project folder. You can accomplish some of these tasks automatically with a function called Simulink.Subsystem.convertToModelReference. Create and Configure the Subsystem In the first part of this example, you define a subsystem for the vdp example model, set configuration parameters for the model, and use the Simulink.Subsystem.convertToModelReference function to convert it into two new models — the top model (vdptop) and a referenced model vdpmultRM containing a subsystem you created (vdpmult). 3-4 Generate Code for Referenced Models 1 In the MATLAB Command Window, create a new working folder wherever you want to work and cd into it: mkdir mrexample cd mrexample 2 Open the vdp example model by typing: vdp 3 Drag a box around the three blocks outlined in blue below: 4 ChooseCreate Subsystem from Selected from the model’s Diagram > Subsystem & Model Reference menu. A subsystem block replaces the selected blocks. 5 If the new subsystem block is not where you want it, move it to a preferred location. 6 Rename the block vdpmult. 3-5 3 Referenced Models 7 Right-click the vdpmult block and select Subsystem Parameters. The Function Block Parameters dialog box appears. 8 In the Function Block Parameters dialog box, select Treat as atomic unit, then click OK. The border of the vdpmult subsystem thickens to indicate that it is now atomic. An atomic subsystem executes as a unit relative to the parent model: subsystem block execution does not interleave with parent block execution. This property makes it possible to extract subsystems for use as stand-alone models and as functions in generated code. The block diagram should now appear as follows: You must set several properties before you can extract a subsystem for use as a referenced model. To set the properties, 1 Open Model Explorer by selecting Model Explorer from the model’s View menu. 3-6 Generate Code for Referenced Models 2 In the Model Hierarchy pane, click the symbol preceding the model name to reveal its components. 3 Click Configuration (Active) in the left pane. 4 In the center pane, select Solver. 5 In the right pane, under Solver Options change the Type to Fixed-step, then click Apply. You must use fixed-step solvers when generating code, although referenced models can use different solvers than top models. 6 In the center pane, select Optimization. In the right pane, select the Signals and Parameters tab, and under Simulation and code generation, select Inline parameters. Click Apply. 7 In the center pane, select Diagnostics. In the right pane: a Select the Data Validity tab. In the Signals area, set Signal resolution to Explicit only. b Select the Connectivity tab. In the Buses area, set Mux blocks used to create bus signals to error. 8 Click Apply. The model now has the properties that model referencing requires. 9 In the center pane, click Model Referencing. In the right pane, set Rebuild to If any changes in known dependencies detected. Click Apply. This setting prevents code regeneration when it is not required. 10 In the vdp model window, choose File > Save as. Save the model as vdptop in your working folder. Leave the model open. Convert Model to Use Model Referencing In this portion of the example, you use the conversion function Simulink.SubSystem.convertToModelReference to extract the subsystem vdpmult from vdptop and convert vdpmult into a referenced model named vdpmultRM. To see the complete syntax of the conversion function, type at the MATLAB prompt: help Simulink.SubSystem.convertToModelReference 3-7 3 Referenced Models For additional information, type: doc Simulink.SubSystem.convertToModelReference If you want to see an example of Simulink.SubSystem.convertToModelReference before using it yourself, type: sldemo_mdlref_conversion Simulink also provides a menu command, Subsystem & Model Reference > Convert Subsystem to > Referenced Model, that you can use to convert a subsystem to a referenced model. The command calls Simulink.SubSystem.convertToModelReference with default arguments. For more information, see “Convert a Subsystem to a Referenced Model”. Extract the Subsystem to a Referenced Model To use Simulink.SubSystem.convertToModelReference to extract vdpmult and convert it to a referenced model, type: Simulink.SubSystem.convertToModelReference... ('vdptop/vdpmult', 'vdpmultRM',... 'ReplaceSubsystem', true, 'BuildTarget', 'Sim') This command: 1 Extracts the subsystem vdpmult from vdptop. 2 Converts the extracted subsystem to a separate model named vdpmultRM and saves the model to the working folder. 3 In vdptop, replaces the extracted subsystem with a Model block that references vdpmultRM. 4 Creates a simulation target for vdptop and vdpmultRM. The converter prints progress messages and terminates with ans = 1 3-8 Generate Code for Referenced Models The parent model vdptop now looks like this: Note the changes in the appearance of the block vdpmult. These changes indicate that it is now a Model block rather than a subsystem. As a Model block, it has no contents of its own: the previous contents now exist in the referenced model vdpmultRM, whose name appears at the top of the Model block. Widen the Model block to expose the complete name of the referenced model. If the parent model vdptop had been closed at the time of conversion, the converter would have opened it. Extracting a subsystem to a referenced model does not automatically create or change a saved copy of the parent model. To preserve the changes to the parent model, save vdptop. Right-click the Model block vdpmultRM and choose Open Model ’vdpmultRM’ to open the referenced model. The model looks like this: 3-9 3 Referenced Models Files Created and Changed by the Converter The files in your working folder now consist of the following (not in this order). File Description vdptop model file Top model that contains a Model block where the vdpmult subsystem was vdpmultRM model file Referenced model created for the vdpmult subsystem vdpmultRM_msf.mexw32 Static library file (Microsoft Windows platforms only). The last three characters of the suffix are system-dependent and may differ. This file executes when the vdptop model calls the Model block vdpmult. When called, vdpmult in turn calls the referenced model vdpmultRM. /slprj Project folder for generated model reference code Code for model reference simulation targets is placed in the slprj/sim subfolder. Generated code for GRT, ERT, and other Simulink Coder targets is placed in slprj subfolders named for those targets. You will inspect some model reference code later in this example. For more information on project folders, see “Work with Project Folders” on page 3-14. 3-10 Generate Code for Referenced Models Run the Converted Model Open the Scope block in vdptop if it is not visible. In the vdptop window, click the Run tool or choose Run from the Simulation menu. The model calls the vdpmultRM_msf simulation target to simulate. The output looks like this: Generate Model Reference Code for a GRT Target The function Simulink.SubSystem.convertToModelReference created the model and the simulation target files for the referenced model vdpmultRM. In this part of the example, you generate code for that model and the vdptop model, and run the executable you create: 1 Verify that you are still working in the mrexample folder. 2 If the model vdptop is not open, open it. Make sure it is the active window. 3 Open Model Explorer by selecting Model Explorer from the model’s View menu. 4 In the Model Hierarchy pane, click the symbol preceding the vdptop model to reveal its components. 5 Click Configuration (Active) in the left pane. 6 In the center pane, select Data Import/Export. 3-11 3 Referenced Models 7 In the Save to workspace section of the right pane, check Time and Output and clear Data stores. Click Apply. The pane shows the following information: These settings instruct the model vdptop (and later its executable) to log time and output data to MAT-files for each time step. 8 Generate GRT code (the default) and an executable for the top model and the referenced model by selecting Code Generation in the center pane and then clicking the Build button. 3-12 Generate Code for Referenced Models The Simulink Coder build process generates and compiles code. The current folder now contains a new file and a new folder: File Description vdptop.exe The executable created by the build process vdptop_grt_rtw/ The build folder, containing generated code for the top model The build process also generated GRT code for the referenced model, and placed it in the slprj folder. To view a model’s generated code in Model Explorer, the model must be open. To use the Model Explorer to inspect the newly created build folder, vdptop_grt_rtw: 1 Open Model Explorer by selecting Model Explorer from the model’s View menu. 2 In the Model Hierarchy pane, click the symbol preceding the model name to reveal its components. 3 Click the symbol preceding Code for vdptop to reveal its components. 4 Directly under Code for vdptop, click This Model. A list of generated code files for vdptop appears in the Contents pane: rtmodel.h vdptop.c vdptop.h vdptop.mk vdptop_private.h vdptop_types.h 3-13 3 Referenced Models You can browse code in any of these files by selecting a file of interest in the Contents pane. To open a file in a text editor, click a filename, and then click the hyperlink that appears in the gray area at the top of the Document pane. The figure below illustrates viewing code for vdptop.c, in a text editor. Your code may differ. To view the generated code in the HTML code generation report, see “Generate a Code Generation Report” on page 11-5. Work with Project Folders When you view generated code in Model Explorer, the files listed in the Contents pane can exist either in a build folder or a project folder. Model reference project folders (always rooted under slprj), like build folders, are created in your current working folder, and this implies certain constraints on when and where model reference targets are built, and how they are accessed. The models referenced by Model blocks can be stored anywhere. A given top model can include models stored on different file systems or in different folders. The same is not true for the simulation targets derived from these models; under most circumstances, all models referenced by a given top model must be set up to simulate and generate model reference target code in a single project folder. The top and referenced models can exist anywhere on your path, but the project folder is assumed to exist in your current folder. This means that, if you reference the same model from several top models, each stored in a different folder, you must either 3-14 Generate Code for Referenced Models • Always work in the same folder and be sure that the models are on your path • Allow separate project folders, simulation targets, and Simulink Coder targets to be generated in each folder in which you work The files in such multiple project folders are generally quite redundant. Therefore, to minimize code regeneration for referenced models, choose a specific working folder and remain in it for all sessions. As model reference code generated for Simulink Coder targets as well as for simulation targets is placed in project folders, the same considerations as above apply even if you are generating target applications only. That is, code for all models referenced from a given model ends up being generated in the same project folder, even if it is generated for different targets and at different times. 3-15 3 Referenced Models Project Folder Structure for Model Reference Targets Code for models referenced by using Model blocks is generated in project folders within the current working folder. The top-level project folder is always named /slprj. The next level within slprj contains parallel build area subfolders. The following table lists principal project folders and files. In the paths listed, model is the name of the model being used as a referenced model, and target is the system target file acronym (for example, grt, ert, rsim, and so on). Folders and Files Description slprj/sim/model/ Simulation target files for referenced models slprj/sim/model/tmwinternal MAT-files used during code generation slprj/target/model/referenced_model_includes Header files from models referenced by this model slprj/target/model Model reference target files slprj/target/model/tmwinternal MAT-files used during code generation slprj/sl_proj.tmw Marker file slprj/target/_sharedutils Utility functions for model reference targets, shared across models slprj/sim/_sharedutils Utility functions for simulation targets, shared across models If you are building code for more than one referenced model within the same working folder, model reference files for all such models are added to the existing slprj folder. 3-16 Configure Referenced Models Configure Referenced Models Minimize occurrences of algebraic loops by selecting the Minimize algebraic loop occurrences parameter on the Model Reference pane. The setting of this option affects only generation of code from the model. See “Hardware Targets” on page 9-9 in the Simulink Coder documentation for information on how this option affects code generation. For more information, see “Model Blocks and Direct Feedthrough”. Use the Integer rounding mode parameter on your model’s blocks to simulate the rounding behavior of the C compiler that you intend to use to compile code generated from the model. This setting appears on the Signal Attributes pane of the parameter dialog boxes of blocks that can perform signed integer arithmetic, such as the Product and n-D Lookup Table blocks. For most blocks, the value of Integer rounding mode completely defines rounding behavior. For blocks that support fixed-point data and the Simplest rounding mode, the value of Signed integer division rounds to also affects rounding. For details, see “Rounding”. When models contain Model blocks, all models that they reference must be configured to use identical hardware settings. For information on the Model Referencing pane options, see “Model Referencing Pane” and “Configuration Parameter Requirements”. 3-17 3 Referenced Models Build Model Reference Targets By default, the Simulink engine rebuilds simulation targets before the Simulink Coder software generates model reference targets. You can change the rebuild criteria or specify that the engine always or never rebuilds targets. See “Rebuild” for details. The Simulink Coder software generates a model reference target directly from the Simulink model. The product automatically generates or regenerates model reference targets, for example, when they require an update. You can command the Simulink and Simulink Coder products to generate a simulation target for an Accelerator mode referenced model, and a model reference target for any referenced model, by executing the slbuild command with arguments in the MATLAB Command Window. The Simulink Coder software generates only one model reference target for all instances of a referenced model. See “Reusable Code and Referenced Models” on page 3-32 for details. Reduce Change Checking Time You can reduce the time that the Simulink and Simulink Coder products spend checking whether any or all simulation targets and model reference targets need to be rebuilt by setting configuration parameter values as follows: • In the top model, consider setting the model configuration parameter Model Referencing > Rebuild to If any changes in known dependencies detected. (See “Rebuild”.) • In all referenced models throughout the hierarchy, set the configuration parameter Diagnostics > Data Validity > Signal resolution to Explicit only. (See “Signal resolution”.) These parameter values exist in a referenced model’s configuration set, not in the individual Model block, so setting either value for any instance of a referenced model sets it for all instances of that model. 3-18 Simulink® Coder™ Model Referencing Requirements Simulink Coder Model Referencing Requirements A model reference hierarchy must satisfy various Simulink Coder requirements, as described in this section. In addition to these requirements, a model referencing hierarchy to be processed by the Simulink Coder software must satisfy: • The Simulink requirements listed in: - “Configuration Requirements for All Referenced Model Simulation” “Model Structure Requirements” • The Simulink limitations listed in “Limitations on All Model Referencing” • The Simulink Coder limitations listed in “Simulink® Coder™ Model Referencing Limitations” on page 3-36 Configuration Parameter Requirements A referenced model uses a configuration set in the same way that any other model does, as described in “Manage a Configuration Set”. By default, every model in a hierarchy has its own configuration set, which it uses in the same way that it would if the model executed independently. Because each model can have its own configuration set, configuration parameter values can be different in different models. Furthermore, some parameter values are intrinsically incompatible with model referencing. The response of the Simulink Coder software to an inconsistent or unusable configuration parameter depends on the parameter: • Where an inconsistency has no significance, or a trivial resolution exists that carries no risk, the product ignores or resolves the inconsistency without posting a warning. • Where a nontrivial and possibly acceptable solution exists, the product resolves the conflict silently; resolves it with a warning; or generates an error. See “Model configuration mismatch” for details. • Where no acceptable resolution is possible, the product generates an error. You must then change some or all parameter values to eliminate the problem. 3-19 3 Referenced Models When a model reference hierarchy contains many submodels that have incompatible parameter values, or a changed parameter value must propagate to many submodels, manually eliminating all configuration parameter incompatibilities can be tedious. You can control or eliminate such overhead by using configuration references to assign an externally-stored configuration set to multiple models. See “Manage a Configuration Reference” for details. The following tables list configuration parameters that can cause problems if set in certain ways, or if set differently in a referenced model than in a parent model. Where possible, the Simulink Coder software resolves violations of these requirements automatically, but most cases require changes to the parameters in some or all models. Configuration Requirements for Model Referencing with All System Targets Dialog Box Pane Option Requirement Solver Start time Some system targets require the start time of all models to be zero. Hardware Emulation hardware options Implementation 3-20 All values must be the same for top and referenced models. Simulink® Coder™ Model Referencing Requirements Configuration Requirements for Model Referencing with All System Targets (Continued) Dialog Box Pane Option Requirement Code Generation System target file Must be the same for top and referenced models. Language Must be the same for top and referenced models. Generate code only Must be the same for top and referenced models. Symbols Maximum identifier length Cannot be longer for a referenced model than for its parent model. Interface Code replacement library Must be the same for top and referenced models. Data C API exchange > Interface The C API check boxes for signals, parameters, and states must be the same for top and referenced models. ASAP2 Can be on or off in a top model, but must be off in a referenced 3-21 3 Referenced Models Configuration Requirements for Model Referencing with All System Targets (Continued) Dialog Box Pane Option Requirement model. If it is not, the Simulink Coder software temporarily sets it to off during code generation. Configuration Requirements for Model Referencing with ERT System Targets (Requires Embedded Coder License) Dialog Box Pane 3-22 Option Requirement Ignore custom storage Code Generation classes Must be the same for top and referenced models. Symbols Global variables Global types Subsystem methods Local temporary variables Constant macros $R token must appear. Signal naming Must be the same for top and referenced models. M-function If specified, must be the same for top and referenced models. Parameter naming Must be the same for top and referenced models. #define naming Must be the same for top and referenced models. Simulink® Coder™ Model Referencing Requirements Configuration Requirements for Model Referencing with ERT System Targets (Requires Embedded Coder License) (Continued) Dialog Box Pane Option Requirement Interface Support floating-point numbers Must be the same for both top and referenced models Support non-finite numbers If off for top model, must be off for referenced models. Support complex numbers If off for top model, must be off for referenced models. Suppress error status in real-time model If on for top model, must be on for referenced models. Templates Target operating system Must be the same for top and referenced models. Data Module Naming Placement Must be the same for top and referenced models. Module Name (if specified) If set, must be the same for top and referenced models. Signal display level Must be the same for top and referenced models. Parameter tune level Must be the same for top and referenced models. Naming Requirements Within a model that uses model referencing, there can be no collisions between the names of the constituent models. When you generate code from a model that uses model referencing, the Maximum identifier length parameter must be large enough to accommodate the root model name and the name mangling string. A code generation error occurs if Maximum identifier length is not large enough. When a name conflict occurs between a symbol within the scope of a higher-level model and a symbol within the scope of a referenced model, the 3-23 3 Referenced Models symbol from the referenced model is preserved. Name mangling is performed on the symbol from the higher-level model. Embedded Coder Naming Requirements The Embedded Coder product provides a Symbol format field that lets you control the formatting of generated symbols in much greater detail. When generating code with an ERT target from a model that uses model referencing: • The $R token must be included in the Identifier format control parameter specifications (in addition to the $M token). • The Maximum identifier length must be large enough to accommodate full expansions of the $R and $M tokens. See “Code Generation Pane: Symbols” for more information. Custom Target Requirements If you have an Embedded Coder license, a custom target must meet various requirements to support model referencing. For details, see “Support Model Referencing” on page 24-101. 3-24 Storage Classes for Signals Used with Model Blocks Storage Classes for Signals Used with Model Blocks Models containing Model blocks can use signals of storage class Auto without restriction. However, when you declare signals to be global, you must be aware of how the signal data will be handled. A global signal is a signal with a storage class other than Auto: • ExportedGlobal • ImportedExtern • ImportedExternPointer • Custom The above are distinct from SimulinkGlobal signals, which are treated as test points with Auto storage class. Global signals are declared, defined, and used as follows: • An extern declaration is generated by all models that use any given global signal. As a result, if a signal crosses a Model block boundary, the top model and the referenced model both generate extern declarations for the signal. • For any exported signal, the top mode is responsible for defining (allocating memory for) the signal, whether or not the top model itself uses the signal. • All global signals used by a referenced model are accessed directly (as global memory). They are not passed as arguments to the functions that are generated for the referenced models. Custom storage classes also follow the above rules. However, certain custom storage classes are not currently supported for use with model reference. See “Custom Storage Class Limitations” for details. 3-25 3 Referenced Models Storage Classes for Parameters Used with Model Blocks All storage classes are supported for both simulation and code generation, and all except Auto are tunable. The supported storage classes thus include • SimulinkGlobal • ExportedGlobal • ImportedExtern • ImportedExternPointer • Custom Note the following restrictions on parameters in referenced models: • Tunable parameters are not supported for noninlined S-functions. • Tunable parameters set using the Model Parameter Configuration dialog box are ignored. Note the following considerations concerning how global tunable parameters are declared, defined, and used in code generated for targets: • A global tunable parameter is a parameter in the base workspace with a storage class other than Auto. • An extern declaration is generated by all models that use any given parameter. • If a parameter is exported, the top model is responsible for defining (allocating memory for) the parameter (whether it uses the parameter or not). • All global parameters are accessed directly (as global memory). They are not passed as arguments to any of the functions that are generated for any of the referenced models. • Symbols for SimulinkGlobal parameters in referenced models are generated using unstructured variables (rtP_xxx) instead of being written into the model_P structure. This is so that each referenced model can be compiled independently. 3-26 Storage Classes for Signals Used with Model Blocks Certain custom storage classes for parameters are not currently supported for model reference. See “Custom Storage Class Limitations” for details. Parameters used as Model block arguments must be defined in the referenced model’s workspace. See “Parameterize Model References” in the Simulink documentation for specific details. Effects of Signal Name Mismatches Within a parent model, the name and storage class for a signal entering or leaving a Model block might not match those of the signal attached to the root inport or outport within that referenced model. Because referenced models are compiled independently without regard to any parent model, they cannot adapt to all possible variations in how parent models label and store signals. The Simulink Coder software accepts all cases where input and output signals in a referenced model have Auto storage class. When such signals are test pointed or are global, as described above, certain restrictions apply. The following table describes how mismatches in signal labels and storage classes between parent and referenced models are handled: Relationships of Signals and Storage Classes Between Parent and Referenced Models Signal Passing Method Signal Mismatch Checking Referenced Model Parent Model Auto Any Function argument None SimulinkGlobal or resolved to Signal Object Any Function argument Label Mismatch Diagnostic (none / warning / error) 3-27 3 Referenced Models Relationships of Signals and Storage Classes Between Parent and Referenced Models (Continued) Referenced Model Parent Model Signal Passing Method Signal Mismatch Checking Global Auto or SimulinkGlobal Global variable Label Mismatch Diagnostic (none / warning / error) Global Global Global variable Labels and storage classes must be identical (else error) To summarize, the following signal resolution rules apply to code generation: • If the storage class of a root input or output signal in a referenced model is Auto (or is SimulinkGlobal), the signal is passed as a function argument. - When such a signal is SimulinkGlobal or resolves to a Simulink.Signal object, the Signal Mismatch diagnostic is applied. • If a root input or output signal in a referenced model is global, it is communicated by using direct memory access (global variable). In addition, - If the corresponding signal in the parent model is also global, the names and storage classes must match exactly. - If the corresponding signal in the parent model is not global, the Signal Mismatch diagnostic is applied. You can set the Signal Mismatch diagnostic to error, warning, or none in the Diagnostics > Connectivity pane of the Configuration Parameters dialog box. 3-28 Inherited Sample Time for Referenced Models Inherited Sample Time for Referenced Models See “Inherit Sample Times” in the Simulink documentation for information about Model block sample time inheritance. In generated code, you can control inheriting sample time by using ssSetModelReferenceSampleTimeInheritanceRule in different ways: • An S-function that precludes inheritance: If the sample time is used in the S-function’s run-time algorithm, then the S-function precludes a model from inheriting a sample time. For example, consider the following mdlOutputs code: static void mdlOutputs(SimStruct *S, int_T tid) { const real_T *u = (const real_T*) ssGetInputPortSignal(S,0); real_T *y = ssGetOutputPortSignal(S,0); y[0] = ssGetSampleTime(S,tid) * u[0]; } This mdlOutputs code uses the sample time in its algorithm, and the S-function therefore should specify ssSetModelReferenceSampleTimeInheritanceRule (S, DISALLOW_SAMPLE_TIME_INHERITANCE); • An S-function that does not preclude Inheritance: If the sample time is only used for determining whether the S-function has a sample hit, then it does not preclude the model from inheriting a sample time. For example, consider the mdlOutputs code from the S-function example sfun_multirate.c: static void mdlOutputs(SimStruct *S, int_T tid) { InputRealPtrsType enablePtrs; int *enabled = ssGetIWork(S); if (ssGetInputPortSampleTime (S,ENABLE_IPORT)==CONTINUOUS_SAMPLE_TIME && ssGetInputPortOffsetTime(S,ENABLE_IPORT)==0.0) { 3-29 3 Referenced Models if (ssIsMajorTimeStep(S) && ssIsContinuousTask(S,tid)) { enablePtrs = ssGetInputPortRealSignalPtrs(S,ENABLE_IPORT); *enabled = (*enablePtrs[0] > 0.0); } } else { int enableTid = ssGetInputPortSampleTimeIndex(S,ENABLE_IPORT); if (ssIsSampleHit(S, enableTid, tid)) { enablePtrs = ssGetInputPortRealSignalPtrs(S,ENABLE_IPORT); *enabled = (*enablePtrs[0] > 0.0); } } if (*enabled) { InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,SIGNAL_IPORT); real_T signal = *uPtrs[0]; int i; for (i = 0; i < NOUTPUTS; i++) { if (ssIsSampleHit(S, ssGetOutputPortSampleTimeIndex(S,i), tid)) { real_T *y = ssGetOutputPortRealSignal(S,i); *y = signal; } } } } /* end mdlOutputs */ The above code uses the sample times of the block, but only for determining whether there is a hit. Therefore, this S-function should set ssSetModelReferenceSampleTimeInheritanceRule (S, USE_DEFAULT_FOR_DISCRETE_INHERITANCE); 3-30 Customize Library File Suffix and File Type Customize Library File Suffix and File Type You can control the library file suffix and file type extension that the Simulink Coder code generator uses to name generated model reference libraries. Use the model configuration parameter TargetLibSuffix to specify the string for the suffix and extension. The string must include a period (.). If you do not set this parameter, the Simulink Coder software names the libraries as follows: • On Windows systems, model_rtwlib.lib • On UNIX or Linux® systems, model_rtwlib.a 3-31 3 Referenced Models Reusable Code and Referenced Models Models that employ model referencing might require special treatment when generating and using reusable code. The following sections identify general restrictions and discuss how reusable functions with inputs or outputs connected to a referenced model’s root Inport or Outport blocks can affect code reuse. General Considerations You can generate code for subsystems that contain referenced models using the same procedures and options described in “Code Generation of Subsystems” on page 2-2. However, the following restrictions apply to such builds: • A top model that uses single-tasking mode and that has a submodel that uses multi-tasking mode executes for blocks with the different rates that are not connected. However, you get an error if the blocks with different rates are connected by Rate Transition block (inserted either manually or by Simulink). • ERT S-functions do not support subsystems that contain a continuous sample time. • The Simulink Coder S-function target is not supported. • The Tunable parameters table (set by using the Model Parameter Configuration dialog box) is ignored; to make parameters tunable, you must define them as Simulink parameter objects in the base workspace. • All other parameters are inlined into the generated code and S-function. Note You can generate subsystem code using any target configuration available in the System Target File Browser. However, if the S-function target is selected, Build This Subsystem and Build Selected Subsystem behaves identically to Generate S-Function. (See “Automate S-Function Generation” on page 14-23.) 3-32 Reusable Code and Referenced Models Code Reuse and Model Blocks with Root Inport or Outport Blocks Reusable functions with inputs or outputs connected to a referenced model’s root Inport or Outport block can affect code reuse. This means that code for certain atomic subsystems cannot be reused in a model reference context the same way it is reused in a standalone model. For example, suppose you create the following subsystem and make the following changes to the subsystem’s block parameters: • Select Treat as an atomic unit • Go to the Code Generation tab and set Function packaging to Reusable function Suppose you then create the following model, which includes three instances of the preceding subsystem. With the Inline parameters option enabled in this stand-alone model, the Simulink Coder code generator can optimize the code by generating a single copy of the function for the reused subsystem, as shown below. void reuse_subsys1_Subsystem1( real_T rtu_0, rtB_reuse_subsys1_Subsystem1 *localB) { 3-33 3 Referenced Models /* Gain: ' /Gain' */ localB->Gain_k = rtu_0 * 3.0; } When generated as code for a Model block (into an slprj project folder), the subsystems have three different function signatures: /* Output and update for atomic system: ' /Subsystem1' */ void reuse_subsys1_Subsystem1(const real_T *rtu_0, rtB_reuse_subsys1_Subsystem1 *localB) { /* Gain: ' /Gain' */ localB->Gain_w = (*rtu_0) * 3.0; } /* Output and update for atomic system: ' /Subsystem2' */ void reuse_subsys1_Subsystem2(real_T rtu_In1, rtB_reuse_subsys1_Subsystem2 *localB) { /* Gain: ' /Gain' */ localB->Gain_y = rtu_In1 * 3.0; } /* Output and update for atomic system: ' /Subsystem3' */ void reuse_subsys1_Subsystem3(real_T rtu_In1, real_T *rty_0) { /* Gain: ' /Gain' */ (*rty_0) = rtu_In1 * 3.0; } One way to make all the function signatures the same for code reuse, is to insert Signal Conversion blocks. Place one between the Inport and Subsystem1 and another between Subsystem3 and the Outport of the referenced model. 3-34 Reusable Code and Referenced Models The result is a single reusable function: void reuse_subsys2_Subsystem1(real_T rtu_In1, rtB_reuse_subsys2_Subsystem1 *localB) { /* Gain: ' /Gain' */ localB->Gain_g = rtu_In1 * 3.0; } You can achieve the same result (reusable code) with only one Signal Conversion block. You can omit the Signal Conversion block connected to the Inport block if you select the Pass fixed-size scalar root inputs by value check box at the bottom of the Model Referencing pane of the Configuration Parameters dialog box. When you do this, you still need to insert a Signal Conversion block before the Outport block. 3-35 3 Referenced Models Simulink Coder Model Referencing Limitations The following Simulink Coder limitations apply to model referencing. In addition to these limitations, a model reference hierarchy used for code generation must satisfy: • The Simulink requirements listed in: - “Configuration Requirements for All Referenced Model Simulation” “Model Structure Requirements” • The Simulink limitations listed in “Model Referencing Limitations”. • The Simulink Coder requirements applicable to the code generation target, as listed in “Configuration Parameter Requirements” on page 3-19. Customization Limitations • The code generator ignores custom code settings in the Configuration Parameter dialog box and custom code blocks when generating code for a referenced model. • Referenced models do not support custom storage classes if the parent model has inline parameters off. • This release does not include Stateflow target custom code in simulation targets generated for referenced models. • Data type replacement is not supported for simulation target code generation for referenced models. • Simulation targets do not include Stateflow target custom code. • If you have an Embedded Coder license, some restrictions exist on grouped custom storage classes in referenced models. For details, see “Custom Storage Class Limitations”. Data Logging Limitations • To Workspace blocks, Scope blocks, and all types of runtime display, such as the display of port values and signal values, are ignored when the Simulink Coder software generates code for a referenced model. The resulting code is the same as if the constructs did not exist. 3-36 Simulink® Coder™ Model Referencing Limitations • Code generated for referenced models cannot log data to MAT-files. If data logging is enabled for a referenced model, the Simulink Coder software disables the option before code generation and re-enables it afterwards. • If you log states for a model that contains referenced models, the ordering of the states in the output is determined by block sorted order, and might not match between simulation output and generated code MAT-file logging output. State Initialization Limitation When a top model uses the Load from workspace > Initial state option to specify initial conditions, the Simulink Coder software does not initialize the states of any referenced models. 3-37 3 Referenced Models Reusability Limitations If a referenced model used for code generation has any of the following properties, the model must specify the configuration parameter Model Referencing > Total number of instances allowed per top model as One, and no other instances of the model can exist in the hierarchy. If you do not set the parameter to One, or more than one instance of the model exists in the hierarchy, an error occurs. The properties are: • The model references another model which has been set to single instance • The model contains a state or signal with non-auto storage class • The model uses any of the following Stateflow constructs: - Machine-parented data Machine-parented events Stateflow graphical functions • The model contains a subsystem that is marked as function • The model contains an S-function that is: - Inlined but has not set the option SS_OPTION_WORKS_WITH_CODE_REUSE Not inlined • The model contains a function-call subsystem that: - 3-38 Has been forced by the Simulink engine to be a function Is called by a wide signal Simulink® Coder™ Model Referencing Limitations S-Function Limitations • If a referenced model contains an S-function that should be inlined using a Target Language Compiler file, the S-function must use the ssSetOptions macro to set the SS_OPTION_USE_TLC_WITH_ACCELERATOR option in its mdlInitializeSizes method. The simulation target will not inline the S-function unless this flag is set. • A referenced model cannot use noninlined S-functions generated by the Simulink Coder software. • The Simulink Coder S-function target does not support model referencing. For additional information, in the Simulink documentation, see “S-Functions with Model Referencing”. Simulink Tool Limitations • Simulink tools that require access to a model’s internal data or configuration (including the Model Coverage tool, the Simulink Report Generator product, the Simulink debugger, and the Simulink profiler) have no effect on code generated by the Simulink Coder software for a referenced model, or on the execution of that code. Specifications made and actions taken by such tools are ignored and effectively do not exist. Subsystem Limitations • If a subsystem contains Model blocks, you cannot build a subsystem module by right-clicking the subsystem (or by using Code > C/C++ Code > Build Selected Subsystem) unless the model is configured to use an ERT target. • If you generate code for an atomic subsystem as a reusable function, inputs or outputs that connect the subsystem to a referenced model can affect code reuse, as described in “Reusable Code and Referenced Models” on page 3-32. Target Limitations • Simulink Coder grt_malloc targets do not support model reference. • The Simulink Coder S-function target does not support model referencing. 3-39 3 Referenced Models Other Limitations • Errors or unexpected behavior can occur if a Model block is part of a cycle, the Model block is a direct feedthrough block, and an algebraic loop results. For details, see “Model Blocks and Direct Feedthrough”. • The External mode option is not supported. If it is enabled, it is ignored during code generation. 3-40 4 Combined Models 4 Combined Models Combined Models If you want to combine several models (or several instances of the same model) into a single executable, the Simulink Coder product offers several options. The most powerful solution is to use Model blocks. Each instance of a Model block represents another model, called a referenced model. For code generation, the referenced model effectively replaces the Model block that references it. For details, see “Overview of Model Referencing” and “Generate Code for Referenced Models” on page 3-4. When developing embedded systems using the Embedded Coder product, you can interface the code for several models to a common harness program by directly calling the entry points to each model. However, the Embedded Coder target has certain restrictions, relating to embedded processing, that might not be compatible with your application. The GRT malloc target is a another possible solution. Use it in situations where you want to: • Selectively control calls to more than one model • Use dynamic memory allocation • Include models that employ continuous states • Log data to multiple files • Run one of the models in external mode For more information, see “Use GRT Malloc to Combine Models” on page 4-4. To summarize by target, your options are as follows: 4-2 Target Support for Combining Multiple Models? Generic Real-Time Target (grt.tlc) Yes (using Model blocks) Generic Real-Time Target with dynamic memory allocation (grt_malloc.tlc) Yes Combined Models Target Support for Combining Multiple Models? Embedded Coder (ert.tlc) Yes S-function Target (rtwsfcn.tlc) No 4-3 4 Combined Models Use GRT Malloc to Combine Models This section discusses how to use the GRT malloc target to combine models into a single program. Building a multiple-model executable is fairly straightforward: 1 Generate and compile code from each of the models that are to be combined. 2 Combine the makefiles for each of the models into one makefile for creating the final multimodel executable. 3 Create a combined simulation engine by modifying grt_malloc_main.c to initialize and call the models. 4 Run the combination makefile to link the object files from the models and the main program into an executable. Share Data Across Models Use unidirectional signal connections between models. This affects the order in which models are called. For example, if an output signal from modelA is used as input to modelB, modelA's output computation should be called first. Timing Issues You must generate all the models you are combining with the same solver mode (either all single-tasking or all multitasking.) In addition, if the models employ continuous states, the same solver should be used for all models. Because each model has its own model-specific definition of the rtModel data structure, you must use an alternative mechanism to control model execution, as follows: • The file rtw/c/src/rtmcmacros.h provides an rtModel API clue that can be used to call the rt_OneStep procedure. • The rtmcmacros.h header file defines the rtModelCommon data structure, which has the minimum common elements in the rtModel structure required to step a model forward one time step. 4-4 Use GRT Malloc to Combine Models • The rtmcsetCommon macro populates an object of type rtModelCommon by copying the respective similar elements in the model’s rtModel object. Your main routine must create one rtModelCommon structure for each model being called by the main routine. • The main routine will subsequently invoke rt_OneStep with a pointer to the rtModelCommon structure instead of a pointer to the rtModel structure. If the base rates for the models are not the same, the main program (such as grt_malloc_main) must set up the timer interrupt to occur at the greatest common divisor rate of the models. The main program calls each model at a time interval. Data Logging and External Mode Support A multiple-model program can log data to separate MAT-files for each model. Only one of the models in a multiple-model program can use external mode. 4-5 4 4-6 Combined Models 5 Configure Model Parameters • “Hardware Targets” on page 9-9 • “Describing the Emulation and Embedded Targets” on page 9-45 • “Describing Embedded Hardware Characteristics” on page 9-54 • “Describing Emulation Hardware Characteristics” on page 9-55 • “Control the Location for Generated Files” on page 5-18 • “Control Generated Files Location Used for Simulation” on page 5-20 • “Control the Location for Code Generation Files” on page 5-22 • “Override Build Folder Settings for Current Session” on page 5-24 5 Configure Model Parameters Platform Options for Development and Deployment When you use Simulink software to create and execute a model, and Simulink Coder software to generate code, you may need to consider up to three platforms, often called hardware targets: • MATLAB Host — The platform that runs MathWorks® software during application development • Embedded Target — The platform on which an application will be deployed when it is put into production • Emulation Target — The platform on which an application under development is tested before deployment The same platform might serve in two or possibly all three capacities, but they remain conceptually distinct. Often the MATLAB host and the emulation target are the same. The embedded target is usually different from, and less powerful than, the MATLAB host or the emulation target; often it can do little more than run a downloaded executable file. When you use Simulink software to execute a model for which you will later generate code, or use Simulink Coder software to generate code for deployment on an embedded target, you must provide information about the embedded target hardware and the compiler that you will use with it. The Simulink software uses this information to get bit-true agreement for the results of integer and fixed-point operations performed in simulation and in code generated for the embedded target. The Simulink Coder code generator uses the information to create code that executes with maximum efficiency. When you generate code for testing on an emulation target, you must additionally provide information about the emulation target hardware and the compiler that you will use with it. The code generator uses this information to create code that provides bit-true agreement for the results of integer and fixed-point operations performed in simulation, in code generated for the embedded target, and in code generated for the emulation target. Agreement can result even though the embedded target and emulation target may use very different hardware, and the compilers for the two targets may use different defaults where the C standard does not completely define behavior. 5-2 Configure Emulation and Embedded Target Hardware Configure Emulation and Embedded Target Hardware The Configuration Parameters dialog Hardware Implementation pane provides options that you can use to describe hardware properties, such as data size and byte ordering, and compiler behavior details that may vary with the compiler, such as integer rounding. The Hardware Implementation pane contains two subpanes: • Embedded Hardware — Describes the embedded target hardware and the compiler that you will use with it. This information affects both simulation and code generation. • Emulation Hardware — Describes the emulation target hardware and the compiler that you will use with it. This information affects only code generation. The two subpanes provide identical options and value choices. By default, the Embedded Hardware subpane initially looks like this: The default assumption is that the embedded target and emulation target are the same, so the Emulation Hardware subpane by default does not need to specify anything and contains only a checked option labeled None. Code generated under this configuration will be suitable for production use, or for testing in an environment identical to the production environment. If you clear the check box, the Emulation Hardware subpane appears, initially showing the same values as the Embedded Hardware subpane. If you change any of these values, then generate code, the code will be able to execute in the environment specified by the Emulation Hardware subpane, 5-3 5 Configure Model Parameters but will behave as if it were executing in the environment specified by the Embedded Hardware subpane. See “Describing Emulation Hardware Characteristics” on page 9-55 for details. If you have used the Code Generation pane to specify a System target file, and the target file specifies a default microprocessor and its hardware properties, the default and properties appear as initial values in the Hardware Implementation pane. Options with only one possible value cannot be changed. Any option that has more than one possible value provides a list of legal values. If you specify any hardware properties manually, check carefully that their values are consistent with the system target file. Otherwise, the generated code may fail to compile or execute, or may execute but give incorrect results. Note Hardware Implementation pane options do not control hardware or compiler behavior. They describe hardware and compiler properties to MATLAB software, which uses the information to generate code for the platform thatruns as efficiently as possible, and gives bit-true agreement for the results of integer and fixed-point operations in simulation, production code, and test code. The rest of this section describes the options in the Embedded Hardware and Emulation Hardware subpanes. Subsequent sections describe considerations that apply only to one or the other subpane. For more about Hardware Implementation options, see “Hardware Implementation Pane”. To see an example of Hardware Implementation pane capabilities, run the rtwdemo_targetsettings example. Identify the Device Vendor The Device vendor option gives the name of the device vendor. To set the option, select a vendor name from the Device vendor menu. Your selection of vendor will determine the available device values in the Device type list. If the desired vendor name does not appear in the menu, select Generic and then use the Device type option to further specify the device. 5-4 Configure Emulation and Embedded Target Hardware Note • For complete lists of Device vendor and Device type values, see “Device vendor” and “Device type” in the Simulink reference documentation. • To add Device vendor and Device type values to the default set that is displayed on the Hardware Implementation pane, see “Registering Additional Device Vendor and Device Type Values” on page 9-47. Identify the Device Type The Device type option selects a hardware device among the supported devices listed for your Device vendor selection. To set the option, select a microprocessor name from the Device type menu. If the desired microprocessor does not appear in the menu, change the Device vendor to Generic. If you specified the Device vendor as Generic, examine the listed device descriptions and select the device type that matches your hardware. If no available device type matches, select Custom. If you select a device type for which the target file specifies default hardware properties, the properties appear as initial values in the subpane. Options with only one possible value cannot be changed. An option that has more than one possible value provides a list of legal values. Select values for your hardware. If the device type is Custom, more options can be set, and each option has a list of possible values. Register Additional Device Vendor and Device Type Values To add Device vendor and Device type values to the default set that is displayed on the Hardware Implementation pane, you can use a hardware device registration API provided by the Simulink Coder software. To use this API, you create an sl_customization.m file, located in your MATLAB path, that invokes the registerTargetInfo function and fills in a hardware device registry entry with device information. The device 5-5 5 Configure Model Parameters information will be registered with Simulink software for each subsequent Simulink session. (To register your device information without restarting MATLAB, issue the MATLAB command sl_refresh_customizations.) For example, the following sl_customization.m file adds device vendor MyDevVendor and device type MyDevType to the Simulink device lists. function sl_customization(cm) cm.registerTargetInfo(@loc_register_device); end function thisDev = loc_register_device thisDev = RTW.HWDeviceRegistry; thisDev.Vendor = 'MyDevVendor'; thisDev.Type = 'MyDevType'; thisDev.Alias = {}; thisDev.Platform = {'Prod', 'Target'}; thisDev.setWordSizes([8 16 32 32 32]); thisDev.LargestAtomicInteger = 'Char'; thisDev.LargestAtomicFloat = 'None'; thisDev.Endianess = 'Unspecified'; thisDev.IntDivRoundTo = 'Undefined'; thisDev.ShiftRightIntArith = true; thisDev.setEnabled({'IntDivRoundTo'}); end If you subsequently select the device in the Hardware Implementation pane, it is displayed as follows: 5-6 Configure Emulation and Embedded Target Hardware To register multiple devices, you can specify an array of RTW.HWDeviceRegistry objects in your sl_customization.m file. For example, function sl_customization(cm) cm.registerTargetInfo(@loc_register_device); end function thisDev = loc_register_device thisDev(1) = RTW.HWDeviceRegistry; thisDev(1).Vendor = 'MyDevVendor'; thisDev(1).Type = 'MyDevType1'; ... thisDev(4) = RTW.HWDeviceRegistry; thisDev(4).Vendor = 'MyDevVendor'; thisDev(4).Type = 'MyDevType4'; ... end The following table lists the RTW.HWDeviceRegistry properties that you can specify in the registerTargetInfo function call in your sl_customization.m file. Property Description Vendor String specifying the Device vendor value for your hardware device. Type String specifying the Device type value for your hardware device. 5-7 5 Configure Model Parameters Property Description Alias Cell array of strings specifying any aliases or legacy names that users might specify that should resolve to this device. Specify each alias or legacy name in the format 'Vendor->Type'. (Embedded Coder software provides the utility functions RTW.isHWDeviceTypeEq and RTW.resolveHWDeviceType for detecting and resolving alias values or legacy values when testing user-specified values for the target device type.) Platform Cell array of enumerated string values specifying whether this device should be listed in the Embedded hardware subpane ({'Prod'}), the Emulation hardware subpane ({'Target'}), or both ({'Prod', 'Target'}). setWordSizes Array of integer sizes to associate with the Number of bits parameters char, short, int, long, and native word size, respectively. LargestAtomicIntegerString specifying an enumerated value for the Largest atomic size: integer parameter: 'Char', 'Short','Int', or 'Long'. LargestAtomicFloat String specifying an enumerated value for the Largest atomic size: floating-point parameter: 'Float', 'Double', or 'None'. 5-8 Endianess String specifying an enumerated value for the Byte ordering parameter: 'Unspecified', 'Little' for little Endian, or 'Big' for big Endian. IntDivRoundTo String specifying an enumerated value for the Signed integer division rounds to parameter: 'Zero', 'Floor', or 'Undefined'. Configure Emulation and Embedded Target Hardware Property Description ShiftRightIntArith Boolean value specifying whether your compiler implements a signed integer right shift as an arithmetic right shift (true) or not (false). setEnabled Cell array of strings specifying which device properties should be enabled (modifiable) in the Hardware Implementation pane when this device type is selected. In addition to the 'Endianess', 'IntDivRoundTo', and 'ShiftRightIntArith' properties listed above, you can enable individual Number of bits parameters using the property names 'BitPerChar', 'BitPerShort', 'BitPerInt', 'BitPerLong', and 'NativeWordSize'. Set Native Word Size for the Device The Number of bits options describe the native word size of the microprocessor, and the bit lengths of char, short, int, and long data. For code generation to succeed: • The bit lengths must be such that char <= short <= int <= long. • Bit lengths must be multiples of 8, with a maximum of 32. • The bit length for long data must not be less than 32. Simulink Coder integer type names are defined in the file rtwtypes.h. The values that you provide must be consistent with the word sizes as defined in the compiler’s limits.h header file. The following table lists the standard Simulink Coder integer type names and maps them to the corresponding Simulink names. Simulink Coder Integer Type Simulink Integer Type boolean_T boolean int8_T int8 uint8_T uint8 5-9 5 Configure Model Parameters Simulink Coder Integer Type Simulink Integer Type int16_T int16 uint16_T uint16 int32_T int32 uint32_T uint32 If no ANSI® C type with a matching word size is available, but a larger ANSI C type is available, the Simulink Coder code generator uses the larger type for int8_T, uint8_T, int16_T, uint16_T, int32_T, and uint32_T. An application can use integer data of any length from 1 (unsigned) or 2 (signed) bits up 32 bits. If the integer length matches the length of an available type, the Simulink Coder code generator uses that type. If no matching type is available, the code generator uses the smallest available type that can hold the data, generating code that never uses unnecessary higher-order bits. For example, on a target that provided 8-bit, 16-bit, and 32-bit integers, a signal specified as 24 bits would be implemented as an int32_T or uint32_T. Code that uses emulated integer data is not maximally efficient, but can be useful during application development for emulating integer lengths that are available only on production hardware. The use of emulation does not affect the results of execution. Set Byte Ordering Used By Device The Byte ordering option specifies whether the target hardware uses Big Endian (most significant byte first) or Little Endian (least significant byte first) byte ordering. If left as Unspecified, the Simulink Coder software generates code that determines the endianness of the target; this is the least efficient option. 5-10 Configure Emulation and Embedded Target Hardware Set Quotient Rounding Technique for Signed Integer Division ANSI C does not completely define the quotient rounding technique to be used when dividing one signed integer by another, so the behavior is implementation-dependent. If both integers are positive, or both are negative, the quotient must round down. If either integer is positive and the other is negative, the quotient can round up or down. The Signed integer division rounds to parameter tells the Simulink Coder code generator how the compiler rounds the result of signed integer division. Providing this information does not affect the operation of the compiler, it only describes that behavior to the code generator, which uses the information to optimize code generated for signed integer division. The parameter options are: • Zero — If the quotient is between two integers, the compiler chooses the integer that is closer to zero as the result. • Floor — If the quotient is between two integers, the compiler chooses the integer that is closer to negative infinity. • Undefined — Choose this option if neither Zero nor Floor describes the compiler’s behavior, or if that behavior is unknown. The following table illustrates the compiler behavior that corresponds to each of these three options: N D Ideal N/D Zero Floor Undefined 33 4 8.25 8 8 8 -33 4 -8.25 -8 -9 -8 or -9 33 -4 -8.25 -8 -9 -8 or -9 -33 -4 8.25 8 8 8 or 9 5-11 5 Configure Model Parameters Note Select Undefined only as a last resort. When the code generator does not know the signed integer division rounding behavior of the compiler, it generates extra code. The compiler’s implementation for signed integer division rounding can be obtained from the compiler documentation, or by experiment if no documentation is available. Set Arithmetic Right Shift Behavior for Signed Integers ANSI C does not define the behavior of right shifts on negative integers, so the behavior is implementation-dependent. The Shift right on a signed integer as arithmetic shift parameter tells the code generator how the compiler implements right shifts on negative integers. Providing this information does not affect the operation of the compiler, it only describes that behavior to the code generator, which uses the information to optimize the code generated for arithmetic right shifts. Select the option if the C compiler implements a signed integer right shift as an arithmetic right shift, and clear the option otherwise. An arithmetic right shift fills bits vacated by the right shift with the value of the most significant bit, which indicates the sign of the number in twos complement notation. The option is selected by default. If your compiler handles right shifts as arithmetic shifts, this is the preferred setting. • When the option is selected, the Simulink Coder software generates simple efficient code whenever the Simulink model performs arithmetic shifts on signed integers. • When the option is cleared, the Simulink Coder software generates fully portable but less efficient code to implement right arithmetic shifts. The compiler’s implementation for arithmetic right shifts can be obtained from the compiler documentation, or by experiment if no documentation is available. 5-12 Configure Embedded Hardware Characteristics Configure Embedded Hardware Characteristics “Describing the Emulation and Embedded Targets” on page 9-45 documents the options available on the Hardware Implementation subpanes. This section describes considerations that apply only to the Embedded Hardware subpane. When you use this subpane, keep the following in mind: • Code generation targets can have word sizes and other hardware characteristics that differ from the MATLAB host. Furthermore, code can be prototyped on hardware that is different from either the deployment target or the MATLAB host. The Simulink Coder code generator takes these differences into account when generating code. • The Simulink product uses some of the information in the Embedded Hardware subpane so that simulation without code generation gives the same results as executing generated code, including detecting error conditions that could arise on the target hardware, such as hardware overflow. • The Simulink Coder software generates code that has bit-true agreement with Simulink results for integer and fixed-point operations. Generated code that emulates unavailable data lengths runs less efficiently than it would without emulation, but the emulation does not affect bit-true agreement with Simulink for integer and fixed-point results. • If you change targets during application development, you must reconfigure the hardware implementation parameters for the new target before generating or regenerating code. Bit-true agreement might not be achieved for results of integer and fixed-point operations in simulation, production code, and test code when code executes on hardware for which it was not generated. • Use the Integer rounding mode parameter on your model’s blocks to simulate the rounding behavior of the C compiler that you intend to use to compile code generated from the model. This setting appears on the Signal Attributes pane of the parameter dialog boxes of blocks that can perform signed integer arithmetic, such as the Product and n-D Lookup Table blocks. • For most blocks, the value of Integer rounding mode completely defines rounding behavior. For blocks that support fixed-point data and the 5-13 5 Configure Model Parameters Simplest rounding mode, the value of Signed integer division rounds to also affects rounding. For details, see “Rounding”. • When models contain Model blocks, models that they reference must be configured to use identical hardware settings. 5-14 Configure Emulation Hardware Characteristics Configure Emulation Hardware Characteristics “Describing the Emulation and Embedded Targets” on page 9-45 documents the options available on the Hardware Implementation subpanes. This section describes considerations that apply only to the Emulation Hardware subpane. Note (If the Emulation Hardware subpane contains a button labeled Configure current execution hardware device, see “Updating from Earlier Versions” on page 9-57, then continue from this point.) The default assumption is that the embedded target and emulation target are the same, so the Emulation Hardware subpane by default does not need to specify anything and contains only a selected check box labeled None. Code generated under this configuration will be suitable for production use, or for testing in an environment identical to the production environment. To generate code that runs on an emulation target for test purposes, but behaves as if it were running on an embedded target in a production application, you must specify the properties of both targets in the Hardware Implementation pane. The Embedded Hardware subpane specifies embedded target hardware properties, as described previously. To specify emulation target properties: 1 Clear the None option in the Emulation Hardware subpane. By default, the Hardware Implementation pane now looks like this: 5-15 5 Configure Model Parameters 2 In the Emulation Hardware subpane, specify the properties of the emulation target, using the instructions in “Describing the Emulation and Embedded Targets” on page 9-45 If you have used the Code Generation pane to specify a System target file, and the target file specifies a default microprocessor and its hardware properties, the default and properties appear as initial values in both subpanes of the Hardware Implementation pane. Options with only one possible value cannot be changed. Any option that has more than one possible value provides a list of legal values. If you specify any hardware properties manually, check carefully that their values are consistent with the system target file. Otherwise, the generated code may fail to compile or execute, or may execute but give incorrect results. If you do not display the Emulation Hardware subpane, the Simulink and Simulink Coder software defaults every Emulation Hardware option to 5-16 Configure Emulation Hardware Characteristics have the same value as the corresponding Embedded Hardware option. If you hide the Emulation Hardware subpane after setting its values, the values that you specified will be lost. The underlying configuration parameters immediately revert to the values that they had when you exposed the subpane, and these values, rather than the values that you specified, will appear if you re-expose the subpane. Update Release 14 Hardware Configuration If your model was created before Release 14 and has not been updated, by default the Hardware Implementation pane initially looks like this: Click Configure current execution hardware device. The Configure current execution hardware device button disappears. The subpane then appears as shown in the first figure in this section. Save your model at this point to avoid redoing Configure current execution hardware device next time you access the Hardware Implementation pane. 5-17 5 Configure Model Parameters Control the Location for Generated Files By default, the files generated by Simulink diagram updates and model builds are placed in a build folder, the root of which is the current working folder (pwd). If you are doing model builds, which potentially generate files for simulation targets as well as code generation targets, artifacts used for simulation and Simulink Coder code generation files coexist in subfolders within that build folder. However, in some situations, you might want the generated files to go to a root folder outside the current working folder. For example, • You need to keep generated files separate from the models and other source materials used to generate them. • You want to reuse or share previously-built simulation targets without having to set the current working folder back to a previous working folder. You might also want to separate generated simulation artifacts from generated production code. To allow you to control the output locations for the files generated by diagram updates and model builds, the software allows you to separately specify the following build folders: • Simulation cache folder — root folder in which to place build artifacts used for simulation • Code generation folder — root folder in which to place Simulink Coder code generation files For specifying the folder locations, the software provides • MATLAB session parameters CacheFolder and CodeGenFolder • Simulink preferences Simulation cache folder and Code generation folder, which, if specified, provide the initial defaults for the MATLAB session parameters • Function Simulink.fileGenControl for directly manipulating the MATLAB session parameters, for example, overriding or restoring the initial default values for the current session 5-18 Control the Location for Generated Files For more information about setting up a simulation cache folder, see “Control Generated Files Location Used for Simulation” on page 5-20. For more information about setting up a code generation folder, see “Control the Location for Code Generation Files” on page 5-22. For more information about directly manipulating the MATLAB session parameters CacheFolder and CodeGenFolder, see “Override Build Folder Settings for Current Session” on page 5-24. 5-19 5 Configure Model Parameters Control Generated Files Location Used for Simulation By default, the files generated by Simulink diagram updates are placed in a build folder, the root of which is the current working folder (pwd). However, in some situations, you might want the generated files to go to a root folder outside the current working folder. For example, • You need to keep generated files separate from the models and other source materials used to generate them. • You want to reuse or share previously-built simulation targets without having to set the current working folder back to a previous working folder. The Simulink preference Simulation cache folder provides control over the output location for files generated by Simulink diagram updates. The preference appears in the Simulink Preferences Window, Main Pane, in the File generation control group. To specify the root folder location for files generated by Simulink diagram updates, set the preference value by entering or browsing to a folder path, for example: The folder path that you specify provides the initial default for the MATLAB session parameter CacheFolder. When you initiate a Simulink diagram update, any files generated are placed in a build folder at the root location specified by CacheFolder (if any), rather than in the current working folder (pwd). For example, using a 32-bit Windows host platform, if you set the Simulation cache folder to 'C:\Work\mymodelsimcache' and then simulate the example model rtwdemo_capi, files are generated into the specified folder as follows: 5-20 Control Generated Files Location Used for Simulation As an alternative to using the Simulink preferences GUI to set Simulation cache folder, you also can get and set the preference value from the command line using get_param and set_param. For example, >> get_param(0, 'CacheFolder') ans = '' >> set_param(0, 'CacheFolder', fullfile('C:','Work','mymodelsimcache')) >> get_param(0, 'CacheFolder') ans = C:\Work\mymodelsimcache Also, you can choose to override the Simulation cache folder preference value for the current MATLAB session. 5-21 5 Configure Model Parameters Control the Location for Code Generation Files By default, the files generated by Simulink model builds are placed in a build folder, the root of which is the current working folder (pwd). Model builds potentially generate files for simulation targets as well as code generation targets, and the resulting build folder contains both artifacts used for simulation and Simulink Coder code generation files. However, in some situations, you might want the generated files to go to one or more root folders outside the current working folder. For example, • You need to keep generated files separate from the models and other source materials used to generate them. • You want to separate generated production code from generated simulation artifacts. The Simulink preference Code generation folder provides control over the output location for files generated by model builds for code generation targets. The preference appears in the Simulink Preferences Window, Main Pane, in the File generation control group. To specify the root folder location for code generation files generated by model builds, set the preference value by entering or browsing to a folder path, for example: The folder path that you specify provides the initial default for the MATLAB session parameter CodeGenFolder. When you initiate a Simulink model build, any code generation files generated are placed in a build folder at the root location specified by CodeGenFolder (if any), rather than in the current working folder (pwd). For example, using a 32-bit Windows host platform, if you set the Code generation folder to 'C:\test\mymodelgencode' and then build the example model rtwdemo_capi, files are generated into the specified folder as follows: 5-22 Control the Location for Code Generation Files As an alternative to using the Simulink preferences GUI to set Code generation folder, you also can get and set the preference value from the command line using get_param and set_param. For example, >> get_param(0, 'CodeGenFolder') ans = '' >> set_param(0, 'CodeGenFolder', fullfile('C:','test','mymodelgencode')) >> get_param(0, 'CodeGenFolder') ans = C:\test\mymodelgencode Also, you can choose to override the Code generation folder preference value for the current MATLAB session. For more information, see “Override Build Folder Settings for Current Session” on page 5-24. 5-23 5 Configure Model Parameters Override Build Folder Settings for Current Session The Simulink preferences Simulation cache folder and Code generation folder provide the initial defaults for the MATLAB session parameters CacheFolder and CodeGenFolder, which determine where files generated by Simulink diagram updates and model builds are placed. However, you can override these build folder settings during the current MATLAB session, using the Simulink.fileGenControl function. This function allows you to directly manipulate the MATLAB session parameters, for example, overriding or restoring the initial default values. The values you set using Simulink.fileGenControl expire at the end of the current MATLAB session. For more information and detailed examples, see the Simulink.fileGenControl function reference page. 5-24 6 Model Protection • “Protect a Referenced Model” on page 6-2 • “Harness Model” on page 6-4 • “Protected Model Report” on page 6-5 • “Code Generation Support in a Protected Model” on page 6-6 • “Protected Model File” on page 6-8 • “Create a Protected Model” on page 6-9 • “Test the Protected Model” on page 6-13 • “Save Base Workspace Definitions” on page 6-15 • “Package a Protected Model” on page 6-16 6 Model Protection Protect a Referenced Model Protect a model when you want to share a model with a third party without revealing the intellectual property. Protecting a model does not use encryption technology. When you create a protected model: • By default, Simulink creates and stores a protected version of the referenced model in the current working folder. The protected model has the same name as the source model, with a .slxp extension. • The original Model block does not change. However, if the Model block parameter Model name does not specify an extension, a protected model, .slxp, takes precedence over a model file, .slx. • The Simulation mode parameter of the protected model is automatically set to Accelerator. You cannot change this value. • You can optionally create a harness model which includes the protected model. A shield icon appears in the lower-left corner of the protected model block in the harness model. For more information, see “Harness Model” on page 6-4. • You can optionally include generated code with the protected model so that a third party can generate code for a model that contains the protected model. Including code generation support with a protected model also allows the third party to simulate a model that references the protected model in Accelerator mode. For more information, see “Code Generation Support in a Protected Model” on page 6-6. • If the Model block uses variants, only the active variant is protected. For more information, see “Set Up Model Variants”. • If you rename a protected model, or change its suffix, the model is unusable until you restore its original name and suffix. You cannot change a protected model internally because any internal change destroys the usability of the file. You can create a protected model using either: • A Model block context menu. For more information, see “Create a Protected Model” on page 6-9 and 6-2 Protect a Referenced Model • A Simulink.ModelReference.protect function. Requirements for Protecting a Model When you create a protected model from a referenced model, the referenced model must meet all requirements listed in “Model Referencing Limitations”, as well as these requirements: • You must have a Simulink Coder license to create a protected model. • A model that you protect must be available on the MATLAB path and not have any unsaved changes. • A model that you protect cannot reference a protected model directly or indirectly. • A model that you protect cannot use a non-inlined S-function directly or indirectly. Model protection has certain limitations, as listed in “Limitations on All Model Referencing” and “Limitations on Accelerator Mode Referenced Models”. 6-3 6 Model Protection Harness Model You can create a harness model for the generated protected model. The harness model opens as a new, untitled model that contains only a Model block which references the protected model. This Model block: • Specifies the Model block parameter, Model name, as the name of the protected model. • Has a shield icon in the lower-left corner. • Has the same number of input and output ports as the protected model. • Defines any model reference arguments that the protected model uses, but does not provide any values. To create a harness model, see “Create a Protected Model” on page 6-9. You can use a harness model to test your protected model. For more information, see “Test the Protected Model” on page 6-13. You can also copy the Model block in your harness model to another model, where it is an interface to the protected model. 6-4 Protected Model Report Protected Model Report You can generate a report for a protected model to include with the protected model. The report provides information to the receiver to determine if the protected model can be used. The report has: • A Summary, including the Simulink version and platform used to create the protected model. • An Interface Report, including model interface information, such as, input and output specifications, exported function information, and whether code generation support is included. A protected model report is generated while the protected model is created. In the Create Protected Model dialog box, select the Create protected model report parameter. For an example, see “Create a Protected Model” on page 6-9. After you create the protected model, to view the protected model report, double-click the protected model block. 6-5 6 Model Protection Code Generation Support in a Protected Model You can create a protected model that supports code generation. When a protected model includes generated code, a third party can generate code for a model that includes the protected model. If you choose to obfuscate the code, all code is obfuscated before compilation. The protected model file contains only obfuscated headers and binaries. No source, such as, .c and .cpp, is present in the protected model file, although the headers are documented in the protected model report. For more information, see “Protected Model File” on page 6-8 and “Protected Model Report” on page 6-5. In the Create Protected Model dialog box, select the Include generated code parameter, which enables the Obfuscate code parameter. For an example on including code generation support, see “Create a Protected Model” on page 6-9. Protected Model Requirements to Support Code Generation Contents and configuration of a model might prevent code generation support of the protected model. Interaction between the parent model and the protected model might also prevent code generation. • Code generation for the protected model is only supported for Accelerator mode and a single target. Both GRT and ERT targets cannot be supported by the same protected model. • A protected model cannot include a model reference hierarchy. • Source code comments in the Code Generation > Comments pane are ignored. Obfuscation of the generated code removes comments because comments might reveal intellectual property. • Custom code in the Code Generation > Custom Code pane should not be included. Custom code is obfuscated, but identifiers are not. • Code generation of a model that includes a protected model produces an error, if: - 6-6 Their interfaces do not match. There are incompatible parameters. Code Generation Support in a Protected Model - A protected model and another model share the same name in the same model reference hierarchy. 6-7 6 Model Protection Protected Model File A protected model file (.slxp) consists of the model itself and supporting files, depending on the options that you selected when you created the protected model. If you created a protected model for simulation only, after simulation, the model.mexext file is placed in the build folder. For simulation with a report, these additional files are unpacked: • slprj/sim/model/html/* • slprj/sim/model/buildinfo.mat If you opted to include code generation support when you created the protected model, after building your model the following files are unpacked (in addition to the preceding files): • slprj/sim/model/*.h • slprj/sim/model/modellib.a (or modellib.lib) • slprj/sim/model/tmwinternal/* • slprj/sim/_sharedutils/* • slprj/target/model/*.h • slprj/target/model/model_rtwlib.a (or model_rtwlib.lib) • slprj/target/model/buildinfo.mat • slprj/target/_sharedutils/* • slprj/target/model/tmwinternal/* For code generation with a report, after building your model these files are unpacked (in addition to the preceding files): • slprj/target/model/html/* • slprj/target/model/buildinfo.mat • slprj/target/_sharedutils/html/* 6-8 Create a Protected Model Create a Protected Model This example shows how to create a protected model to be used for simulation and code generation. 1 Open the model rtwdemo_roll. 2 In the Simulink Editor, right-click the Model block that references the model for which you want to generate protected model code. In this example, right-click HeadingMode. 3 From the context menu, select Block Parameters (ModelReference). 4 In the Block Parameters dialog box, in the Model name field, specify the extension for the model, .slx. When both the model and the protected model exist in the same folder, .slxp takes precedence over .slx. In the Model name field, if you do not specify an extension, when you create the protected model, the original Model block in the model becomes protected. 5 Click Apply and OK. 6 Right-click the Model block. From the context menu, select Subsystem & Model Reference > Create Protected Model for Selected Model Block. 7 In the Create Protected Model dialog box, select Include generated code to include generated code with the protected model. This parameter enables and selects the Obfuscate code parameter. For more information about the generated code, see “Code Generation Support in a Protected Model” on page 6-6. 8 In the Package path field, specify the folder path for the protected model. The default value is the current working folder. 9 To create a harness model for the protected model, select Create harness model for protected model. 6-9 6 Model Protection 10 Click Create. An untitled harness model opens and contains a Model block, which refers to the protected model rtwdemo_heading.slxp. The Simulation mode for the Model block is set to Accelerator. You cannot change the mode. 6-10 Create a Protected Model 11 To view the protected model report, double-click the HeadingMode block. 6-11 6 Model Protection To test the protected model before packaging, see “Test the Protected Model” on page 6-13. To package the protected model for a third party, see “Package a Protected Model” on page 6-16. 6-12 Test the Protected Model Test the Protected Model To test a protected model that you created, you use the generated harness model and the procedure described in “Use Protected Model in Simulation”. You can also compare the output of the protected model to the output of the original model. Because you are the supplier, both the original and the protected model might exist on the MATLAB path. In the original model, if the Model block Model name parameter names the model without providing a suffix, the protected model takes precedence over the unprotected model. If you need to override this default when testing the output, in the Model block Model name parameter, specify the file name with the extension of the unprotected model, .slx. To compare the unprotected and protected versions of a Model block, use the Simulation Data Inspector. This example uses rtwdemo_roll and the protected model, rtwdemo_heading.slxp, which is created in “Create a Protected Model” on page 6-9. 1 If it is not already open, open rtwdemo_roll. 2 Enable logging for the output signal of the Model block, HeadingMode. In the Configuration Parameters dialog box, on the Data Import/Export pane, select the Signal logging parameter and set Signal logging format to Dataset. Click Apply and OK. 3 Right-click the output signal. From the context menu, select Properties. In the Signal Properties dialog box, select Log signal data. Click Apply and OK. For more information, see “Export Signal Data Using Signal Logging”. 4 Right-click the HeadingMode block. From the context menu, select Block Parameters (ModelReference). In the Block Parameters dialog box, specify the Model name parameter with the name of the unprotected model and the extension, rtwdemo_heading.slx. Click Apply and OK. 5 In the Simulink Editor, click the Record button on. Simulate the model. When the simulation is complete, the Simulation Data Inspector opens. 6-13 6 Model Protection 6 In the Simulation Data Inspector, rename the run to indicate that it is for the unprotected model. 7 In the Simulink Editor, right-click the HeadingMode block. From the context menu, select Block Parameters (ModelReference). In the Block Parameters dialog box, specify the Model name parameter with the name of the protected model, rtwdemo_heading.slxp. A shield icon appears on the Model block. 8 In the Simulink Editor, the Record button is still on. Simulate the model, which now refers to the protected model. When the simulation is complete, the Simulation Data Inspector opens. 9 In the Simulation Data Inspector, rename the new run to indicate that it is for the protected model. 10 In the Simulation Data Inspector, select the Compare Runs tab to compare the runs for the unprotected and the protected model. For more information about comparing runs, see “Compare All Logged Signal Data From Multiple Simulations”. 6-14 Save Base Workspace Definitions Save Base Workspace Definitions Referenced models might use object definitions or tunable parameters that are defined in the MATLAB base workspace. These variables are not saved with the model. When you protect a model, you must obtain the definitions of required base workspace entities and ship them with the model. The following base workspace variables must be saved to a MAT-file: • Global tunable parameter • Global data store • Any of the following objects used by a signal that connects to a root-level model Inport or Outport: - Simulink.Signal Simulink.Bus Simulink.Alias Simulink.NumericType that is an alias For more information, see “Workspace Variables in Model Explorer”. Before executing the protected model as a part of a third-party model, the receiver of the protected model must load the MAT-file. 6-15 6 Model Protection Package a Protected Model In addition to the protected model file (.slxp), you might need to include additional files in the protected model package: • Harness model file. • Any required definitions saved in a MAT-file. For more information, see “Save Base Workspace Definitions” on page 6-15. • Instructions on how to retrieve the files. Some ways to deliver the protected model package are: • Provide the .slxp file and other supporting files as separate files. • Combine the files into a ZIP or other container file. • Combine the files using a manifest. For more information, see “Export Files in a Manifest”. • Provide the files in some other standard or proprietary format specified by the receiver. Whichever approach you use to deliver a protected model, include information on how to retrieve the original files. One approach to consider is to use the Simulink Manifest Tools, as described in “Analyze Model Dependencies”. 6-16 Data, Function, and File Definition • Chapter 7, “Data Representation” • Chapter 8, “Entry Point Functions and Scheduling” 7 Data Representation • “Enumerations” on page 7-2 • “Structure Parameters and Generated Code” on page 7-49 • “Parameters” on page 7-10 • “Signals” on page 7-52 • “States” on page 7-83 • “Data Stores” on page 7-93 7 Data Representation Enumerations In this section... “About Enumerated Data Types” on page 7-2 “Default Code for an Enumerated Data Type” on page 7-2 “Type Casting for Enumerations” on page 7-3 “Override Default Methods (Optional)” on page 7-4 “Enumerated Type Limitations” on page 7-7 About Enumerated Data Types Enumerated data is data that is restricted to a finite set of values. An enumerated data type is a MATLAB class that defines a set of enumerated values. Each enumerated value consists of an enumerated name and an underlying integer which the software uses internally and in generated code. The following is a MATLAB class definition for an enumerated data type named BasicColors, which is used in the examples in this section. classdef(Enumeration) BasicColors < Simulink.IntEnumType enumeration Red(0) Yellow(1) Blue(2) end end For information about enumerated data types and their use in Simulink models, see “Use Enumerated Data in Simulink Models”. For information about enumerated data types in Stateflow charts, see “How to Define Enumerated Data in a Chart”. Default Code for an Enumerated Data Type By default, enumerated data types in generated code are defined in the generated header file model_types.h for the model. For example, the default code for BasicColors, which is defined in the previous section, appears as follows: 7-2 Enumerations #ifndef _DEFINED_TYPEDEF_FOR_BasicColors_ #define _DEFINED_TYPEDEF_FOR_BasicColors_ typedef enum { Red = 0, Yellow = 1, Blue = 2, } BasicColors; /* Default value */ #endif Type Casting for Enumerations How Safe Casting Works A Simulink Data Type Conversion block can accept a signal of integer type and convert the input to one of the underlying values of an enumerated type. If the input value does not match any of the underlying values of the enumerated type’s values, Simulink can insert a safe cast to replace the input value with the enumerated type’s default value. Enable and Disable Safe Casting You can enable or disable safe casting for enumerations during code generation for a Simulink Data Type Conversion block or a Stateflow block. To control safe casting, enable or disable the block’s Saturate on integer overflow parameter. The parameter works as follows: • Enabled: Simulink replaces a non-matching input value with the default value of the enumerated values during simulation and generates a safe cast function during code generation. • Disabled: For a non-matching input value, Simulink generates an error during simulation and omits the safe cast function during code generation. While the code is more efficient in this case, it may be more vulnerable to runtime errors. 7-3 7 Data Representation Safe Cast Function in Generated Code This example shows how the safe cast function int32_T ET08_safe_cast_to_BasicColors for the enumeration BasicColors appears in generated code. static int32_T ET08_safe_cast_to_BasicColors(int32_T input) { int32_T output; /* Initialize output value to default value for BasicColors (Red) */ output = 0; if ((input >= 0) && (input <= 2)) { /* Set output value to input value if it is a member of BasicColors */ output = input; } return output; } Through this function, the enumerated type’s default value is used if the input value does not match one of underlying values of the enumerated type’s values. If the block’s Saturate on integer overflow parameter is disabled, this function does not appear in generated code. Override Default Methods (Optional) Every enumerated class has four associated static methods, which it inherits from Simulink.IntEnumType. You can optionally override any or all of these static methods to customize the behavior of an enumerated type. The methods are: • getDefaultValue — Returns the default value of the enumerated data type. • getDescription — Returns a description of the enumerated data type. • getHeaderFile — Specifies a file where the type is defined for generated code. • addClassNameToEnumNames — Specifies whether the class name becomes a prefix in code. 7-4 Enumerations The first of these methods, getDefaultValue, is relevant to both simulation and code generation, and is described in “Specifying a Default Enumerated Value” in the Simulink documentation. The other three methods are relevant only to code generation, and are described in this section. To override any of the methods, include a customized version of the method in the enumerated class definition’s methods section. If you do not want to override any default methods, omit the methods section entirely. The following table summarizes the four methods and the data to supply for each one: Method Purpose Default Return Custom Return getDefaultValue Returns the default value for the class, which must be an instance of the class. The lexically first value in the enumeration. Any enumerated value in the class. See “Instantiate Enumerations”. getDescription Returns a string containing a description of the enumerated class. '' Any string that MATLAB accepts. getHeaderFile Returns a string containing the name of the header file '' The name of the file that contains the enumerated type definition. false true or false addClassNameToEnumNames Returns a boolean value indicating whether to prefix the class name in generated code Specifying a Description To specify a description for an enumerated data type, include the following method in the enumerated class’s methods section: function retVal = getDescription() % GETDESCRIPTION Optional string to describe the data type. retVal = 'description'; end 7-5 7 Data Representation Substitute any legal MATLAB string for description. The generated code that defines the enumerated type will include the specified description. Specify a Header File To prevent the declaration of an enumerated type from being embedded in the generated code, allowing you to provide the declaration in an external file, include the following method in the enumerated class’s methods section: function retVal = getHeaderFile() % GETHEADERFILE File where type is defined for generated code. % If specified, this file is #included in the code. % Otherwise, the type is written out in the generated code. retVal = 'filename'; end Substitute any legal filename for filename. Be sure to provide a filename suffix, typically .h. Providing the method replaces the declaration that would otherwise have appeared in model_types.h with a #include statement like: #include "imported_enum_type.h" The getHeaderFile method does not create the declaration file itself. You must provide a file of the specified name that declares the enumerated data type. Add Prefixes To Class Names By default, enumerated values in generated code have the same names that they have in the enumerated class definition. Alternatively, the code can prefix every enumerated value in an enumerated class with the name of the class. This technique can be useful for preventing identifier conflicts or improving the clarity of the code. To specify class name prefixing, include the following method in an enumerated class’s methods section: function retVal = addClassNameToEnumNames() % ADDCLASSNAMETOENUMNAMES Control whether class name is added as % a prefix to enumerated names in the generated code. % By default the code does not use the class name as a prefix. retVal = boolean; end 7-6 Enumerations Replace boolean with true to enable class name prefixing, or false to suppress prefixing without having to delete the method itself. If boolean is true, each enumerated value in the class appears in generated code as EnumTypeName_EnumName. For BasicColors, which was defined in “About Enumerated Data Types” on page 7-2, the data type definition with class name prefixing looks like this: #ifndef _DEFINED_TYPEDEF_FOR_BasicColors_ #define _DEFINED_TYPEDEF_FOR_BasicColors_ typedef enum { BasicColors_Red = 0, BasicColors_Yellow = 1, BasicColors_Blue = 2, } BasicColors; /* Default value */ #endif In this example, the enumerated class name BasicColors appears as a prefix for each of the enumerated names. The definition is otherwise the same as it would be without name prefixing. Enumerated Type Limitations • Generated code does not support logging enumerated data. 7-7 7 Data Representation Structure Parameters and Generated Code In this section... “About Structure Parameters and Generated Code” on page 7-49 “Include Structure Parameters in Generated Code” on page 7-50 “Control Naming of Structure Parameter Types” on page 7-50 About Structure Parameters and Generated Code Structure parameters provide a way to improve generated code to use structures rather multiple separate variables. You also have the option of configuring the appearance of a structure parameter in generated code. For more information about structure parameters, see“Structure Parameters” in the Simulink documentation. For an example of how to convert a model that uses unstructured workspace variables to a model that uses structure parameters, see sldemo_applyVarStruct. Configure Structure Parameters for Generated Code By default, structure parameters do not appear in generated code. Structure parameters include numeric variables and the code generator inlines numeric values. To make structure type definition appear in generated code for a structure parameter, 1 Create a Simulink.Parameter object. 2 Define the object value to be the parameter structure. 3 Define the object storage class to be a value other than Auto. The code generator places a structure type definition or the tunable parameter structure in model_types.h. By default, the code generator identifies the type with a nondescriptive, automatically generated name, such as struct_z98c0D2qc4btL. 7-8 Structure Parameters and Generated Code For information on how to control the naming of the type, see “Control Naming of Structure Parameter Types” on page 7-50. For an example, see sldemo_applyVarStruct Control Name of Structure Parameter Type To control the naming of a structure parameter type, use a Simulink.Bus object to specify the data type of the Simulink.Parameter object. 1 Use Simulink.Bus.createObject to create a bus object with the same shape as the parameter structure. For example: busInfo=Simulink.Bus.createObject(ControlParam.Value); 2 Assign the bus object name to the data type property of the parameter object. ParamType=eval(busInfo.busName); ControlParam.DataType='Bus: ParamType'; Only Simulink.Parameter can accept the bus object name as a data type. For an example, see sldemo_applyVarStruct 7-9 7 Data Representation Parameters In this section... “About Parameters” on page 7-10 “Nontunable Parameter Storage” on page 7-11 “Tunable Parameter Storage” on page 15-119 “Tunable Parameter Storage Classes” on page 15-121 “Declare Tunable Parameters” on page 15-124 “Tunable Expressions” on page 15-128 “Linear Block Parameter Tunability” on page 15-132 “Configuration Parameter Quick Reference Diagram” on page 7-27 “Generated Code for Parameter Data Types” on page 7-28 “Tunable Workspace Parameter Data Type Considerations” on page 15-133 “Tune Parameters” on page 7-36 “Parameter Objects” on page 7-38 “Structure Parameters and Generated Code” on page 7-49 About Parameters This section discusses how the Simulink Coder product generates parameter storage declarations, and how you can generate the storage declarations you need to interface block parameters to your code. For information about defining block parameters in Simulink models, see “Set Block Parameters”. If you are using S-functions in your model and intend to tune their run-time parameters in the generated code, see “Tuning Run-Time Parameters” in the Simulink documentation. Note that • Parameters must be numeric, logical, or character arrays. • Parameters may not be sparse. • Parameter arrays must not be greater than 2 dimensions. 7-10 Parameters For guidance on implementing a parameter tuning interface using a C API, see “Data Interchange Using the C API” on page 15-137. Simulink external mode offers a way to monitor signals and modify parameter values while generated model code executes. However, external mode might not be the optimal solution for your application. For example, the S-function target does not support external mode. For other targets, you might want your existing code to access parameters and signals of a model directly, rather than using the external mode communications mechanism. For information on external mode, see “Host/Target Communication” on page 15-50. Nontunable Parameter Storage By default, block parameters are not tunable in the generated code. When Inline Parameters is off (the default), the Simulink Coder product has control of parameter storage declarations and the symbolic naming of parameters in the generated code. Nontunable parameters are stored as fields within model_P (formerly rtP), a model-specific global parameter data structure. The Simulink Coder product initializes each field of model_P to the value of the corresponding block parameter at code generation time. When the Inline parameters option is on, block parameters are evaluated at code generation time, and their values appear as constants in the generated code, if possible (in certain circumstances, parameters cannot be inlined, and are then included in a constant parameter or model parameter structure.) As an example of nontunable parameter storage, consider the following model. The workspace variable Kp sets the gain of the Gain block. 7-11 7 Data Representation Assume that Kp is nontunable and has a value of 5.0. The next table shows the variable declarations and the code generated for Kp in the noninlined and inlined cases. The generated code does not preserve the symbolic name Kp. The noninlined code represents the gain of the Gain block as model_P.Gain_Gain. When Kp is noninlined, the parameter is tunable. Inline Parameters Generated Variable Declaration and Code Off struct Parameters_non_tunable_sin { real_T SineWave_Amp; real_T SineWave_Bias; real_T SineWave_Freq; real_T SineWave_Phase; real_T Gain_Gain; }; . . . Parameters_non_tunable_sin non_tunable_sin_P = { 7-12 Parameters Inline Parameters Generated Variable Declaration and Code 1.0 0.0 1.0 0.0 5.0 , , , , /* /* /* /* /* SineWave_Amp : ' /Sine Wave' */ SineWave_Bias : ' /Sine Wave' */ SineWave_Freq : ' /Sine Wave' */ SineWave_Phase : ' /Sine Wave' */ Gain_Gain : ' /Gain' */ }; . . . non_tunable_sin_Y.Out1 = rtb_u * non_tunable_sin_P.Gain_Gain; On non_tunable_sin_Y.Out1 = rtb_u * 5.0; Tunable Parameter Storage A tunable parameter is a block parameter whose value can be changed at run-time. A tunable parameter is inherently noninlined. Consequently, when Inlined parameters is off, all parameters are members of model_P, and thus are tunable. A tunable expression is an expression that contains one or more tunable parameters. When you declare a parameter tunable, you control whether or not the parameter is stored within model_P. You also control the symbolic name of the parameter in the generated code. When you declare a parameter tunable, you specify • The storage class of the parameter. The storage class property of a parameter specifies how the Simulink Coder product declares the parameter in generated code. The term “storage class,” as used in the Simulink Coder product, is not synonymous with the term storage class specifier, as used in the C language. 7-13 7 Data Representation • A storage type qualifier, such as const or volatile. This is simply a string that is included in the variable declaration. • (Implicitly) the symbolic name of the variable or field in which the parameter is stored. The Simulink Coder product derives variable and field names from the names of tunable parameters. The Simulink Coder product generates a variable or struct storage declaration for each tunable parameter. Your choice of storage class controls whether the parameter is declared as a member of model_P or as a separate global variable. You can use the generated storage declaration to make the variable visible to external legacy code. You can also make variables declared in your code visible to the generated code. You are responsible for linking your code to generated code modules. You can use tunable parameters or expressions in your root model and in masked or unmasked subsystems, subject to certain restrictions. (See “Tunable Expressions” on page 15-128.) Override Inlined Parameters for Tuning When the Inline parameters option is selected, you can use the Model Parameter Configuration dialog box to remove individual parameters from inlining and declare them to be tunable. This allows you to improve overall efficiency by inlining most parameters, while at the same time retaining the flexibility of run-time tuning for selected parameters. Another way you can achieve the same result is by using Simulink data objects; see “Parameters” on page 7-10 for specific details. The mechanics of declaring tunable parameters are discussed in “Declare Tunable Parameters” on page 15-124. Tunable Parameter Storage Classes The Simulink Coder product defines four storage classes for tunable parameters. You must declare a tunable parameter to have one of the following storage classes: 7-14 Parameters • SimulinkGlobal (Auto): This is the default storage class. The Simulink Coder product stores the parameter as a member of model_P. Each member of model_P is initialized to the value of the corresponding workspace variable at code generation time. • ExportedGlobal: The generated code instantiates and initializes the parameter and model.h exports it as a global variable. An exported global variable is independent of the model_P data structure. Each exported global variable is initialized to the value of the corresponding workspace variable at code generation time. • ImportedExtern: model_private.h declares the parameter as an extern variable. Your code must supply the variable definition and initializer. • ImportedExternPointer: model_private.h declares the variable as an extern pointer. Your code must supply the pointer variable definition and initializer, if any. The generated code for model.h includes model_private.h to make the extern declarations available to subsystem files. As an example of how the storage class declaration affects the code generated for a parameter, consider the next figure. 7-15 7 Data Representation The workspace variable Kp sets the gain of the Gain block. Assume that the value of Kp is 3.14. The following table shows the variable declarations and the code generated for the gain block when Kp is declared as a tunable parameter. An example is shown for each storage class. Note The Simulink Coder product uses column-major ordering for two-dimensional signal and parameter data. When interfacing your hand-written code to such signals or parameters by using ExportedGlobal, ImportedExtern, or ImportedExternPointer declarations, make sure that your code observes this ordering convention. The symbolic name Kp is preserved in the variable and field names in the generated code. Storage Class SimulinkGlobal (Auto) Generated Variable Declaration and Code typedef struct _Parameters_tunable_sin Parameters_tunable_sin; struct _Parameters_tunable_sin { real_T Kp; }; Parameters_tunable_sin tunable_sin_P = { 3.14 }; . . tunable_sin_Y.Out1 = rtb_u * tunable_sin_P.Kp; ExportedGlobal real_T Kp = 3.14; . . tunable_sin_Y.Out1 = rtb_u * Kp; 7-16 Parameters Storage Class Generated Variable Declaration and Code ImportedExtern extern real_T Kp; . . tunable_sin_Y.Out1 = rtb_u * Kp; ImportedExtern Pointer extern real_T *Kp; . . tunable_sin_Y.Out1 = rtb_u * (*Kp); Declare Tunable Parameters • “Declare Workspace Variables as Tunable Parameters” on page 15-124 • “Declare New Tunable Parameters” on page 15-124 • “Declare Tunable Parameters Using Configuration Parameter Dialog” on page 15-125 • “Select Workspace Variables” on page 15-126 • “Create New Tunable Parameters” on page 15-127 • “Set Tunable Parameter Properties” on page 15-128 • “Remove Unused Tunable Parameters” on page 15-128 Declare Workspace Variables as Tunable Parameters To declare tunable parameters, 1 Open the Model Parameter Configuration dialog box. 2 In the Source list pane, select one or more variables. 3 Click Add to table . The variables then appear as tunable parameters in the Global (tunable) parameters pane. 7-17 7 Data Representation 4 Select a parameter in the Global (tunable) parameters pane. 5 Select a storage class from the Storage class menu. 6 Optionally, select (or enter) a storage type qualifier, such as const or volatile for the parameter. 7 Click Apply, or click OK to apply changes and close the dialog box. Declare New Tunable Parameters To declare tunable parameters, 1 Open the Model Parameter Configuration dialog box. 2 In the Global (tunable) parameters pane, click New. 3 Specify a name for the parameter. 4 Select a storage class from the Storage class menu. 5 Optionally, select (or enter) a storage type qualifier, such as const or volatile for the parameter. 6 Click Apply, or click OK to apply changes and close the dialog box. Declare Tunable Parameters Using Configuration Parameters The Model Configuration Parameters dialog box lets you select base workspace variables and declare them to be tunable parameters in the current model. Using controls in the dialog box, you move variables from a source list to a global (tunable) parameter list for a model. To open the dialog box, 1 Select the Inline parameters check box on the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box. This activates a Configure button, as shown below. 7-18 Parameters 2 Click Configure to open the Model Configuration Parameters dialog box. Note The Model Configuration Parameters dialog box cannot tune parameters within referenced models. See “Parameterize Model References” for tuning techniques that work with referenced models. Select Workspace Variables The Source list pane displays a menu and a scrolling table of numerical workspace variables. To select workspace variables, 1 From the menu, select the source of variables you want listed. 7-19 7 Data Representation To List... Choose... All variables in the MATLAB workspace that have numeric values MATLAB workspace Only variables in the MATLAB workspace that have numeric values and are referenced by the model Referenced workspace variables A list of workspace variables appear in the Source List pane. 2 Select one or more variables from the source list. This enables the Add to table button. 3 Click Add to table to add the selected variables to the tunable parameters list in the Global (tunable) parameters pane. In the Source list, the names of variables added to the tunable parameters list are displayed in bold type (see the preceding figure). Note If you selected a variable with a name that matches a block parameter that is not tunable and you click Add to table , a warning appears during simulation and code generation. To update the list of variables to reflect the current state of the workspace, at any time, click Refresh list . For example, you might use Refresh list if you define or remove variables in the workspace while the Model Parameter Configuration dialog box is open. Create New Tunable Parameters To create a new tunable parameter, 1 In the Global (tunable) parameters pane, click New. 2 In the Name field, enter a name for the parameter. 7-20 Parameters If you enter a name that matches the name of a workspace variable in the Source list pane, that variable is declared tunable and appears in italics in the Source list. 3 Click Apply. The model does not need to be using a parameter before you create it. You can add references to the parameter later. Note If you edit the name of an existing variable in the list, you actually create a new tunable variable with the new name. The previous variable is removed from the list and loses its tunability (that is, it is inlined). Set Tunable Parameter Properties To set the properties of tunable parameters listed in the Global (tunable) parameters pane, select a parameter and then specify a storage class and, optionally, a storage type qualifier. Property Description Storage class Select one of the following to be used for code generation: • SimulinkGlobal (Auto) • ExportedGlobal • ImportedExtern • ImportedExternPointer See “Tunable Parameter Storage Classes” on page 15-121 for definitions. Storage type qualifier For variables with any storage class except SimulinkGlobal (Auto), you can add a qualifier (such as const or volatile) to the generated storage declaration. To do so, you can select a predefined qualifier from the list or add qualifiers not in the list. The code 7-21 7 Data Representation Property Description generator does not check the storage type qualifier for validity, and includes the qualifier string in the generated code without checking syntax . Remove Unused Tunable Parameters To remove unused tunable parameters from the table in the Global (tunable) parameters pane, click Remove. Removed variables are inlined if the Inlined parameters option is enabled. Tunable Expressions • “Tunable Expressions in Masked Subsystems” on page 15-129 • “Tunable Expression Limitations” on page 15-131 The Simulink Coder product supports the use of tunable variables in expressions. An expression that contains one or more tunable parameters is called a tunable expression. Tunable Expressions in Masked Subsystems Tunable expressions are allowed in masked subsystems. You can use tunable parameter names or tunable expressions in a masked subsystem dialog box. When referenced in lower-level subsystems, such parameters remain tunable. As an example, consider the masked subsystem in the next figure. The masked variable k sets the gain parameter of theGain. 7-22 Parameters Suppose that the base workspace variable b is declared tunable with SimulinkGlobal (Auto) storage class. The next figure shows the tunable expression b*3 in the subsystem’s mask dialog box. Tunable Expression in Subsystem Mask Dialog Box The Simulink Coder product produces the following output computation for theGain. The variable b is represented as a member of the global parameters structure, model_P. (For clarity in showing the individual Gain block computation, expression folding is off in this example.) /* Gain: ' /theGain' */ rtb_theGain_C = rtb_SineWave_n * ((subsys_mask_P.b * 3.0)); /* Outport: ' /Out1' */ subsys_mask_Y.Out1 = rtb_theGain_C; As this example shows, for GRT targets, the parameter structure is mangled to create the structure identifier model_P (subject to the identifier length constraint). This is done to avoid namespace clashes in combining code from multiple models using model reference. ERT-based targets provide ways to customize identifier names. When expression folding is on, the above code condenses to /* Outport: ' /Out1' incorporates: * Gain: ' /theGain' */ subsys_mask_Y.Out1 = rtb_SineWave_n * ((subsys_mask_P.b * 3.0)); 7-23 7 Data Representation Expressions that include variables that were declared or modified in mask initialization code are not tunable. As an example, consider the subsystem above, modified as follows: • The mask initialization code is t = 3 * k; • The parameter k of the myGain block is 4 + t. • Workspace variable b = 2. The expression b * 3 is plugged into the mask dialog box as in the preceding figure. Since the mask initialization code can run only once, k is evaluated at code generation time as 4 + (3 * (2 * 3) ) The Simulink Coder product inlines the result. Therefore, despite the fact that b was declared tunable, the code generator produces the following output computation for theGain. (For clarity in showing the individual Gain block computation, expression folding is off in this example.) /* Gain Block: /theGain */ rtb_temp0 *= (22.0); Tunable Expression Limitations Currently, there are certain limitations on the use of tunable variables in expressions. When an unsupported expression is encountered during code generation a warning is issued and the equivalent numeric value is generated in the code. The limitations on tunable expressions are • Complex expressions are not supported, except where the expression is simply the name of a complex variable. • The use of certain operators or functions in expressions containing tunable operands is restricted. Restrictions are applied to four categories of operators or functions, classified in the following table: 7-24 Parameters Category Operators or Functions 1 + - .* ./ < > <= >= == ~= & | 2 * / 3 abs, acos, asin, atan, atan2, boolean, ceil, cos, cosh, exp, floor, log, log10, sign, sin, sinh, sqrt, tan, tanh, 4 single, int8, int16, int32, uint8, uint16, uint32 5 : .^ ^ [] {} . \ .\ ' .' ; , The rules applying to each category are as follows: - Category 1 is unrestricted. These operators can be used in tunable expressions with any combination of scalar or vector operands. - Category 2 operators can be used in tunable expressions where at least one operand is a scalar. That is, scalar/scalar and scalar/matrix operand combinations are supported, but not matrix/matrix. - Category 3 lists functions that support tunable arguments. Tunable arguments passed to these functions retain their tunability. Tunable arguments passed to any other functions lose their tunability. - Category 4 lists the casting functions that do not support tunable arguments. Tunable arguments passed to these functions lose their tunability. Note The Simulink Coder product casts values using MATLAB typecasting rules. The MATLAB typecasting rules are different from C code typecasting rules. For example, using the MATLAB typecasting rules, int8(3.7) returns the result 4, while in C code int8(3.7) returns the result 3. - Category 5 operators are not supported. • Expressions that include variables that were declared or modified in mask initialization code are not tunable. • The Fcn block does not support tunable expressions in code generation. 7-25 7 Data Representation • Model workspace parameters can take on only the Auto storage class, and thus are not tunable. See “Parameterize Model References” for tuning techniques that work with referenced models. • Non-double expressions are not supported. • Blocks that access parameters only by address support the use of tunable parameters, if the parameter expression is a simple variable reference. When an operation such as a data type conversion or a math operation is applied, the Simulink Coder product creates a nontrivial expression that cannot be accessed by address, resulting in an error during the build process. Linear Block Parameter Tunability The following blocks have a Realization parameter that affects the tunability of their parameters: • Transfer Fcn • State-Space • Discrete State-Space The Realization parameter must be set by using the MATLAB set_param function, as in the following example. set_param(gcb,'Realization','auto') The following values are defined for the Realization parameter: • general: The block’s parameters are preserved in the generated code, permitting parameters to be tuned. • sparse: The block’s parameters are represented in the code by transformed values that increase the computational efficiency. Because of the transformation, the block’s parameters are no longer tunable. • auto: This setting is the default. A general realization is used if one or more of the block’s parameters are tunable. Otherwise sparse is used. 7-26 Parameters Note To tune the parameter values of a block of one of the above types without restriction during an external mode simulation, you must set Realization to general. Code Reuse for Subsystems with Mask Parameters The Simulink Coder product can generate reusable (reentrant) code for a model containing identical atomic subsystems. Selecting the Reusable function option for Function packaging enables such code reuse, and causes a single function with arguments to be generated that is called when any of the identical atomic subsystem executes. See “Subsystems” for details and restrictions on the use of this option. Mask parameters become arguments to reusable functions. However, for reuse to occur, each instance of a reusable subsystem must declare the same set of mask parameters. If, for example subsystem A has mask parameters b and K, and subsystem B has mask parameters c and K, then code reuse is not possible, and the Simulink Coder product will generate separate functions for A and B. Configuration Parameter Quick Reference Diagram The next figure shows the code generation and storage class options that control the representation of parameters in generated code. 7-27 7 Data Representation Kp = 5.0; u Kp y SIMULINK CODER CONTROLS SYMBOL USED IN CODE [OFF] 1 y = u* (rtP.); Include parameters as fields in a global structure (field names based on block names) SIMULINK CODER CONTROLS SYMBOL USED IN CODE [Auto] (implicit) Inline Parameters Use numeric value of parameter (if possible) 2 y = u* (5.0); 3 const *p_ = &rtP.[0]; for (i=0; i [i]); } INCLUDED IN LIST OF GLOBAL (TUNABLE) PARAMETERS ON [SimulinkGlobal(Auto)] 4 y = u* (rtP.Kp); ExportedGlobal 5 y = u* (Kp); ImportedExtern 6 y = u* (Kp); Include in a global structure Unstructured storage Symbol preserved (must be unique) ImportedExternPointer 7 y = u* (*Kp); KEY: [option] : default for code generation option : Generated symbol for parameter storage field Generated Code for Parameter Data Types For an example of the code generated from Simulink parameters with different data types, run the model rtwdemo_paramdt. This model shows options that are available for controlling the data type of tunable parameters in the generated code. The model’s subsystem includes several instances of 7-28 Parameters Gain blocks feeding Saturation blocks. Each pair of blocks uses a workspace variable of a particular data type, as shown in the next figure. 7-29 7 Data Representation Inlined parameters (InLineParameters ON + Auto storage class) ==> numeric value inlined 1 single Kinline single single 1 Upper: Kinline Lower: 0 Double-precision (context-sensitive) parameters ==> tunable parameter inherits data type from run-time parameter 2 single Kcs single single 2 Upper: Kcs Lower: 0 Tunable parameters with explicit data type specification ==> parameter is cast to run-time parameter data type in generated code 3 4 5 6 7 single single single single single Ksingle Kint8 Kfixpt Kalias Kuser single single single Upper: Ksingle Lower: 0 single single Upper: Kint8 Lower: 0 single single Upper: Kfixpt Lower: 0 single single Upper: Kalias Lower: 0 single Upper: Kuser Lower: 0 7-30 3 4 5 6 7 Parameters The Simulink engine initializes the parameters in the model by executing the script rtwdemo_paramdt_data.m. You can view the initialization script and inspect the workspace variables in Model Explorer by double-clicking the yellow boxes in the model. In the model, note that the Inline parameters option on the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box is selected. The Model Parameter Configuration dialog box reveals that all base workspace variables (with the exception of Kinline) have their Storage class property set to ExportedGlobal. Consequently, Kinline is a nontunable parameter while the remaining variables are tunable parameters. To generate code for the model, double-click the blue boxes. The following table shows both the MATLAB code used to initialize parameters and the code generated for each parameter in the rtwdemo_paramdt model. Parameter & MATLAB Code Generated Variable Declaration and Code Kinline rtb_Gain1 = rtwdemo_paramdt_U.In1 * 2.0F; Kinline = 2; . . rtwdemo_paramdt_Y.Out1 = rt_SATURATE(rtb_Gain1, 0.0F, 2.0F); Kcs real32_T Kcs = 3.0F; Kcs = 3; . . rtb_Gain1 = rtwdemo_paramdt_U.In2 * Kcs; . . rtwdemo_paramdt_Y.Out2 = rt_SATURATE(rtb_Gain1, 0.0F, Kcs); 7-31 7 Data Representation Parameter & MATLAB Code Generated Variable Declaration and Code Ksingle real32_T Ksingle = 4.0F; Ksingle = single(4); . . rtb_Gain1 = rtwdemo_paramdt_U.In3 * Ksingle; . . rtwdemo_paramdt_Y.Out3 = rt_SATURATE(rtb_Gain1, 0.0F, Ksingle); Kint8 int8_T Kint8 = 5; Kint8 = int8(5); . . rtb_Gain1 = rtwdemo_paramdt_U.In4 * ((real32_T)( Kint8 )); . . rtwdemo_paramdt_Y.Out4 = rt_SATURATE(rtb_Gain1, 0.0F, ((real32_T)( Kint8 ))); Kfixpt int16_T Kfixpt = 192; Kfixpt = Simulink.Parameter; Kfixpt.Value = 6; Kfixpt.DataType = ... . . rtb_Gain1 = rtwdemo_paramdt_U.In5 * 'fixdt(true, 16, 2^-5, 0)'; Kfixpt.CoderInfo.StorageClass = ... 'ExportedGlobal'; (((real32_T)ldexp((real_T)Kfixpt, -5))); . . rtwdemo_paramdt_Y.Out5 = rt_SATURATE(rtb_Gain1, 0.0F, (((real32_T)ldexp((real_T)Kfixpt, -5)))); 7-32 Parameters Parameter & MATLAB Code Generated Variable Declaration and Code Kalias typedef real32_T aliasType; aliasType = ... . Simulink.AliasType('single'); Kalias = Simulink.Parameter; Kalias.Value = 7; . aliasType Kalias = 7.0F; . Kalias.DataType = 'aliasType'; Kalias.CoderInfo.StorageClass = ... 'ExportedGlobal'; . rtb_Gain1 = rtwdemo_paramdt_U.In6 * Kalias; . . rtwdemo_paramdt_Y.Out6 = rt_SATURATE(rtb_Gain1, 0.0F, Kalias); Kuser typedef int16_T userType; userType = Simulink.NumericType; userType.DataTypeMode = ... 'Fixed-point: slope and bias scaling'; userType.Slope = 2^-3; . . userType Kuser = 64; . userType.isAlias = true; Kuser = Simulink.Parameter; . rtb_Gain1 = rtwdemo_paramdt_U.In7 * Kuser.Value = 8; (((real32_T)ldexp((real_T)Kuser, -3))); Kuser.DataType = 'userType'; Kuser.CoderInfo.StorageClass = ... 'ExportedGlobal'; . . rtwdemo_paramdt_Y.Out7 = rt_SATURATE(rtb_Gain1, 0.0F, (((real32_T)ldexp((real_T)Kuser, -3)))); The salient features of the code generated for this model are as follows: • The Simulink Coder product inlines nontunable parameters, for example, Kinline. However, the product does not inline tunable parameters, such as Kcs, Ksingle, and Kint8. • The Simulink engine treats tunable parameters of data type double in a context-sensitive manner, such that the parameter inherits its data type from the context in which the block uses it. For example, Kcs inherits a single data type from the Gain block’s input signal. 7-33 7 Data Representation • If a parameter’s data type matches that of the block’s run-time parameter, the block can use the tunable parameter without any transformation. Consequently, the Simulink Coder product need not cast the parameter from one data type to another, as illustrated by Ksingle and Kalias. However, if a parameter’s data type does not match that of the block’s run-time parameter, the block cannot readily compute its output. In this case, the product casts parameters to the relevant data type. For example, Kint8, Kfixpt, and Kuser require casts to a single data type for compatibility with the input signals to the Gain and Saturation blocks. • If you are using an ERT target and a parameter specifies a data type alias, for example, created by an instance of the Simulink.AliasType class, its variable definition in the generated code uses the alias data type. For example, the Simulink Coder product declares Kalias and Kuser to be of data types aliasType and userType, respectively. • If a parameter specifies a fixed-point data type, the Simulink Coder product initializes its value in the generated code to the value of Q computed from the expression V = SQ + B (see the Simulink Fixed Point documentation for more information about fixed-point semantics and notation), where - V is a real-world value Q is an integer that encodes V S is the slope B is the bias For example, Kfixpt has a real-world value of 6, slope of 2-5, and bias of 0. Consequently, the product declares the value of Kfixpt to be 192. Tunable Workspace Parameter Data Type Considerations If you are using tunable workspace parameters, you need to be aware of potential issues regarding data types. A workspace parameter is tunable when the following conditions exist: • You select the Inline parameters option on the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box • The parameter has a storage class other than Auto 7-34 Parameters When generating code for tunable workspace parameters, the Simulink Coder product checks and compares the data types used for a particular parameter in the workspace and in Block Parameter dialog boxes. If... The Simulink Coder Product... The data types match Uses that data type for the parameter in the generated code. You do not explicitly specify a data type other than double in the workspace Uses the data type specified by the block in the generated code. If multiple blocks share a parameter, they must all specify the same data type. If the data type varies between blocks, the product generates an error similar to the following: Variable 'K' is used in incompatible ways in the dialog fields of the following: cs_params/Gain, cs_params/Gain1. The variable'value is being used both directly and after a transformation. Only one of these usages is permitted for any given variable. You explicitly specify a data type other than double in the workspace Uses the data type from the workspace for the parameter. The block typecasts the parameter to the block specific data type before using it. Guidelines for Specifying Data Types The following table provides guidelines on specifying data types for tunable workspace parameters. If You Want to... Then Specify Data Types in... Minimize memory usage (int8 instead of single) The workspace explicitly Avoid typecasting Blocks only 7-35 7 Data Representation If You Want to... Then Specify Data Types in... Interface to legacy or custom code The workspace explicitly Use the same parameter for multiple blocks that specify different data types The workspace explicitly The Simulink Coder product enforces limitations on the use of data types other than double in the workspace, as explained in “Limitations on Specifying Workspace Data Types Explicitly” on page 15-135. Limitations on Data Type Specifications in Workspace When you explicitly specify a data type other than double in the workspace, blocks typecast the parameter to a corresponding data type. This is an issue for blocks that use pointer access for their parameters. Blocks cannot use pointer access if they need to typecast the parameter before using it (because of a data type mismatch). Another case in which this occurs is for workspace variables with bias or fractional slope. Two possible solutions to these problems are • Remove the explicit data type specification in the workspace for parameters used in such blocks. • Modify the block so that it uses the parameter with the same data type as specified in the workspace. For example, the Lookup Table block uses the data types of its input signal to determine the data type that it uses to access the X-breakpoint parameter. You can prevent the block from typecasting the run-time parameter by converting the input signal to the data type used for X-breakpoints in the workspace. (Similarly, the output signal is used to determine the data types used to access the lookup table Y data.) Tune Parameters Tune Parameters from the Command Line When parameters are MATLAB workspace variables, the Model Parameter Configuration dialog box is the recommended way to see or set the properties 7-36 Parameters of tunable parameters. In addition to that dialog box, you can also use MATLAB get_param and set_param commands. Note You can also use Simulink.Parameter objects for tunable parameters. See “Configure Parameter Objects for Code Generation” on page 7-39 for details. The following commands return the tunable parameters and corresponding properties: • get_param(gcs, 'TunableVars') • get_param(gcs, 'TunableVarsStorageClass') • get_param(gcs, 'TunableVarsTypeQualifier') The following commands declare tunable parameters or set corresponding properties: • set_param(gcs, 'TunableVars', str) The argument str (string) is a comma-separated list of variable names. • set_param(gcs, 'TunableVarsStorageClass', str) The argument str (string) is a comma-separated list of storage class settings. The valid storage class settings are - Auto ExportedGlobal ImportedExtern ImportedExternPointer • set_param(gcs, 'TunableVarsTypeQualifier', str) The argument str (string) is a comma-separated list of storage type qualifiers. 7-37 7 Data Representation The following example declares the variable k1 to be tunable, with storage class ExportedGlobal and type qualifier const. The number of variables and number of specified storage class settings must match. If you specify multiple variables and storage class settings, separate them with a comma. set_param(gcs, 'TunableVars', 'k1') set_param(gcs, 'TunableVarsStorageClass','ExportedGlobal') set_param(gcs, 'TunableVarsTypeQualifier','const') Interfaces for Tuning Parameters The Simulink Coder product includes • Support for developing a Target Language Compiler API for tuning parameters independent of external mode. See “Parameter Functions” in the Target Language Compiler documentation for information. • A C application program interface (API) for tuning parameters independent of external mode. See “Data Interchange Using the C API” on page 15-137 for information. • An interface for exporting ASAP2 files, which you customize to use parameter objects. For details, see “ASAP2 Data Measurement and Calibration” on page 15-174. Parameter Objects • “About Parameter Objects for Code Generation” on page 7-39 • “Use Parameter Objects for Code Generation” on page 7-39 • “Configure Parameter Objects for Code Generation” on page 7-39 • “Storage Classes and Code Generation for Parameter Objects” on page 7-40 • “Generate Code for Parameter Objects from Command Line” on page 7-41 • “Generate Code for Parameter Objects Using Model Explorer” on page 7-42 • “Parameter Object Configuration Quick Reference Diagram” on page 7-46 • “Resolve Conflicts in Parameter Object Configurations” on page 7-47 7-38 Parameters About Parameter Objects for Code Generation Within the class hierarchy of Simulink data objects, the Simulink product provides a class that is designed as base class for parameter storage. This topic explains how to use parameter objects in code generation. The CoderInfo properties of parameter objects are used by the Simulink Coder product during code generation. These properties let you assign storage classes to the objects, thereby controlling how the generated code stores and represents parameters. The Simulink Coder build process also writes information about the properties of parameter objects to the model.rtw file. This information, formatted as Object records, is accessible to Target Language Compiler programs. For general information on Object records, see “Data Object Information in model.rtw”. Before using Simulink parameter objects with the Simulink Coder product, read the discussion of Simulink data objects in the Simulink documentation. Use Parameter Objects for Code Generation The general procedure for using parameter objects in code generation is as follows: 1 Define a subclass of Simulink.Parameter. 2 Instantiate parameter objects from your subclass and set their properties from the command line or by using Model Explorer. 3 Use the objects as parameters within your model. 4 Generate code and build your target executable. Configure Parameter Objects for Code Generation In configuring parameter objects for code generation, you use the following code generation and parameter object properties: • The Inline parameters option (see “Parameters” on page 7-10). • Parameter object properties: 7-39 7 Data Representation - Value. The numeric value of the object, used as an initial (or inlined) - DataType. The data type of the object. This can be any Simulink numeric data type, including a fixed-point, user-defined, or alias data type. - CoderInfo.StorageClass. Controls the generated storage declaration parameter value in generated code. and code for the parameter object. Other parameter object properties (such as user-defined properties of classes derived from Simulink.Parameter) do not affect code generation. Note If Inline parameters is off (the default), the CoderInfo.StorageClass parameter object property is ignored in code generation. Storage Classes and Code Generation for Parameter Objects The Simulink Coder product generates code and storage declarations based on the CoderInfo.StorageClass property of the parameter object. The logic is as follows: • If the storage class is 'Auto' (the default), the parameter object is inlined (if possible), using the Value property. • For storage classes other than 'Auto', the parameter object is handled as a tunable parameter. - A global storage declaration is generated. You can use the generated storage declaration to make the variable visible to your hand-written code. You can also make variables declared in your hand-written code visible to the generated code. - The symbolic name of the parameter object is generally preserved in the generated code. See the table in “Generate Code for Parameter Objects Using Model Explorer” on page 7-42 for examples of code generated for possible settings of CoderInfo.StorageClass. 7-40 Parameters Generate Code for Parameter Objects from Command Line In this section, the Gain block computations of the model shown in the next figure are used as an example of how the Simulink Coder build process generates code for a parameter object. Model Using Parameter Object Kp As Block Parameter In this model, Kp sets the gain of the Gain block. To configure a parameter object such as Kp for code generation: 1 Instantiate a Simulink.Parameter object called Kp. In this example, the parameter object is an instance of the example class SimulinkDemos.Parameter, which is provided with the Simulink product. Kp = Simulink.Parameter Kp = Simulink.Parameter Value: 5 CoderInfo: [1x1 Simulink.ParamCoderInfo] Description: '' DataType: 'auto' 7-41 7 Data Representation Min: Max: DocUnits: Complexity: Dimensions: [] [] '' 'real' '[1x1]' Make sure that the name of the parameter object matches the desired block parameter in your model. This enables the Simulink engine to associate the parameter name with the corresponding object. In the preceding model, the Gain block parameter Kp resolves to the parameter object Kp. 2 Set the object properties you need. You can do this by using the Model Explorer, or you can assign properties by using MATLAB commands, as follows: • To specify the Value property, type Kp.Value = 5.0; • To specify the storage class of for the parameter, set the CoderInfo.StorageClass property, for example: Kp.CoderInfo.StorageClass = 'ExportedGlobal'; The CoderInfo parameters are now Kp.CoderInfo Simulink.ParamCoderInfo StorageClass: 'ExportedGlobal' Alias: '' CustomStorageClass: 'Default' CustomAttributes: [1x1 SimulinkCSC.AttribClass_Simulink_Default] Generate Code for Parameter Objects Using Model Explorer If you prefer, you can create and modify attributes of parameter objects using the Model Explorer. This lets you see the attributes of a parameter in a dialog box, and alleviates the need to remember and type field names. Do the following to instantiate Kp and set its attributes from Model Explorer: 7-42 Parameters 1 Choose Model Explorer from the View menu. Model Explorer opens or activates if it already was open. 2 Select Base Workspace in the Model Hierarchy pane. 3 Select Simulink Parameter from the Add menu. A new parameter named Param appears in the Contents pane. 4 To set Kp.Name in the Model Explorer: a Click the word Param in the Name column to select it. b Rename it by typing Kp in place of Param. c Press Enter or Return. 5 To set Kp.Value in Model Explorer: 7-43 7 Data Representation a Select the Value field at the top of the Dialog pane. b Type 5.0. c Click the Apply button. 6 To set the Kp.CoderInfo.StorageClass in Model Explorer: a Click the Storage class menu and select ExportedGlobal, as shown in the next figure. b Click Apply. The following table shows the variable declarations for Kp and the code generated for the Gain block in the model shown in the preceding model, with the Inline parameters and Eliminate superfluous local variables (Expression folding) check boxes selected (which includes the gain computation in the output computation). An example is shown for each 7-44 Parameters possible setting of CoderInfo.StorageClass. Global structures include the model name (symbolized as model_ or _model). StorageClass Property Generated Variable Declaration and Code Auto model_Y.Out1 = rtb_u * 5.0; SimulinkGlobal struct _Parameters_model { real_T Kp; } . . Parameters_model model_P = { 5.0 }; . . model_Y.Out1 = rtb_u * model_P.Kp; ExportedGlobal extern real_T Kp; . . real_T Kp = 5.0; . . model_Y.Out1 = rtb_u * Kp; 7-45 7 Data Representation StorageClass Property Generated Variable Declaration and Code ImportedExtern extern real_T Kp; . . model_Y.Out1 = rtb_u * Kp; ImportedExternPointer extern real_T *Kp; . . model_Y.Out1 = rtb_u * (*Kp); Parameter Object Configuration Quick Reference Diagram The next figure shows the code generation and storage class options that control the representation of parameter objects in generated code. 7-46 Parameters Kp = Simulink.Parameter; Kp.Value = 5.0; u Kp y SIMULINK CODER CONTROLS SYMBOL USED IN CODE [OFF] 1 y = u* (rtP.); Include parameters as fields in a global structure (field names based on block names) SIMULINK CODER CONTROLS SYMBOL USED IN CODE [Auto] Inline Parameters Use numeric value of parameter (if possible) 2 y = u* (5.0); 3 const *p_ = &rtP.[0]; for (i=0; i [i]); } INCLUDED IN LIST OF GLOBAL (TUNABLE) PARAMETERS ON SimulinkGlobal 4 y = u* (rtP.Kp); ExportedGlobal 5 y = u* (Kp); ImportedExtern 6 y = u* (Kp); Include in a global structure Unstructured storage Symbol preserved (must be unique) ImportedExternPointer 7 y = u* (*Kp); KEY: [option] : default for code generation option : Generated symbol for parameter storage field Resolve Conflicts in Parameter Object Configurations Two methods are available for controlling the tunability of parameters. You can • Define them as Simulink.Parameter objects in the MATLAB workspace 7-47 7 Data Representation • Use the Model Parameter Configuration dialog box The next figures show how you can use each of these methods to control the tunability of parameter Kp. The first figure shows Kp defined as Simulink.Parameter in the Model Explorer. You control the tunability of Kp by specifying the parameter’s storage class. Parameter Object Kp with Auto Storage Class in Model Explorer The next figure shows how you can use the Model Parameter Configuration dialog box to specify a storage class for numeric variables in the MATLAB workspace. 7-48 Parameters Parameter Kp Defined with SimulinkGlobal Storage Class Note Do not use both methods for controlling the tunability of a given parameter. If you use both methods and the storage class settings for the parameter do not match, an error results. Structure Parameters and Generated Code • “About Structure Parameters and Generated Code” on page 7-49 • “Include Structure Parameters in Generated Code” on page 7-50 • “Control Naming of Structure Parameter Types” on page 7-50 About Structure Parameters and Generated Code Structure parameters provide a way to improve generated code to use structures rather multiple separate variables. You also have the option of configuring the appearance of a structure parameter in generated code. For more information about structure parameters, see“Structure Parameters” in the Simulink documentation. For an example of how to convert a model 7-49 7 Data Representation that uses unstructured workspace variables to a model that uses structure parameters, see sldemo_applyVarStruct. Include Structure Parameters in Generated Code By default, structure parameters do not appear in generated code. Structure parameters include numeric variables and the code generator inlines numeric values. To make structure type definition appear in generated code for a structure parameter, 1 Create a Simulink.Parameter object. 2 Define the object value to be the parameter structure. 3 Define the object storage class to be a value other than Auto. The code generator places a structure type definition or the tunable parameter structure in model_types.h. By default, the code generator identifies the type with a nondescriptive, automatically generated name, such as struct_z98c0D2qc4btL. For information on how to control the naming of the type, see “Control Naming of Structure Parameter Types” on page 7-50. For an example, see sldemo_applyVarStruct Control Naming of Structure Parameter Types To control the naming of a structure parameter type, by using a Simulink.Bus object to specify the data type of the Simulink.Parameter object. 1 Use Simulink.Bus.createObject to create a bus object with the same shape as the parameter structure. For example: busInfo=Simulink.Bus.createObject(ControlParam.Value); 2 Assign the bus object name to the data type property of the parameter object. ParamType=eval(busInfo.busName); 7-50 Parameters ControlParam.DataType='Bus: ParamType'; Only Simulink.Parameter can accept the bus object name as a data type. For an example, see sldemo_applyVarStruct 7-51 7 Data Representation Signals In this section... “About Signals” on page 7-52 “Signal Storage Concepts” on page 7-53 “Signals with Auto Storage Class” on page 7-55 “Signals with Test Points” on page 7-59 “Interface Signals to External Code” on page 7-60 “Symbolic Naming Conventions for Signals” on page 7-62 “Summary of Signal Storage Class Options” on page 7-63 “Interfaces for Monitoring Signals” on page 7-64 “Signal Objects” on page 7-65 “Initialize Signals and States Using Signal Objects” on page 7-74 About Signals The Simulink Coder product offers a number of options that let you control how signals in your model are stored and represented in the generated code. This section discusses how you can use these options to • Control whether signal storage is declared in global memory space or locally in functions (that is, in stack variables). • Control the allocation of stack space when using local storage. • Delcare signals as test points to store them in unique memory locations • Reduce memory usage by instructing the Simulink Coder product to store signals in reusable buffers. • Control whether or not signals declared in generated code are interfaceable (visible) to externally written code. You can also specify that signals are to be stored in locations declared by externally written code. • Preserve the symbolic names of signals in generated code by using signal labels. 7-52 Signals The discussion in the following sections refers to code generated from signal_examp, the model shown in the next figure. Signal_examp Model Signal Storage Concepts This section discusses structures and concepts you must understand to choose the best signal storage options for your application: • The global block I/O data structure model_B • The concept of signal storage classes as used in the Simulink Coder product Global Block I/O Structure By default, the Simulink Coder product attempts to optimize memory usage by sharing signal memory and using local variables. However, under a number of circumstances you should place signals in global memory. For example, • You might want a signal to be stored in a structure that is visible to externally written code. • The number and/or size of signals in your model might exceed the stack space available for local variables. In such cases, it is possible to override the default behavior and store selected (or all) signals in a model-specific global block I/O data structure. The global block I/O structure is called model_B (in earlier versions this was called rtB). 7-53 7 Data Representation The following code shows how model_B is defined and declared in code generated (with signal storage optimizations off) from the signal_examp model shown in the Signal_examp Model on page 7-53 figure. (in signal_examp.h) /* Block signals (auto storage) */ extern BlockIO_signal_examp signal_examp_B; (in signal_examp.c) /* Block signals (auto storage) */ BlockIO_signal_examp signal_examp_B; Field names for signals stored in model_B are generated according to the rules described in “Symbolic Naming Conventions for Signals” on page 7-62. Signals Storage Classes In the Simulink Coder product, the storage class property of a signal specifies how the product declares and stores the signal. In some cases this specification is qualified by more options. In the context of the Simulink Coder product, the term “storage class” is not synonymous with the term storage class specifier, as used in the C language. Default Storage Class. Auto is the default storage class and is the storage class you should use for signals that you do not need to interface to external code. Signals with Auto storage class can be stored in local and/or shared variables or in a global data structure. The form of storage depends on the Signal storage reuse, Reuse block outputs, Enable local block outputs, and Minimize data copies between local and global variables options, and on available stack space. See “Signals with Auto Storage Class” on page 7-55 for a full description of code generation options for signals with Auto storage class. Explicitly Assigned Storage Classes. Signals with storage classes other than Auto are stored either as members of model_B, or in unstructured global variables, independent of model_B. These storage classes are for signals that you want to monitor and/or interface to external code. 7-54 Signals The Signal storage reuse, Enable local block outputs, Reuse block outputs, Eliminate superfluous local variables (expression folding), and Minimize data copies between local and global variables optimizations do not apply to signals with storage classes other than Auto. Use the Signal Properties dialog box to assign these storage classes to signals: • SimulinkGlobal(Test Point): Test points are stored as fields of the model_B structure that are not shared or reused by any other signal. See “Signals with Test Points” on page 7-59 for more information. • ExportedGlobal: The signal is stored in a global variable, independent of the model_B data structure. model.h exports the variable. Signals with ExportedGlobal storage class must have unique signal names. See “Interface Signals to External Code” on page 7-60 for more information. • ImportedExtern: model_private.h declares the signal as an extern variable. Your code must supply the variable definition. Signals with ImportedExtern storage class must have unique signal names. See “Interface Signals to External Code” on page 7-60 for more information. • ImportedExternPointer: model_private.h declares the signal as an extern pointer. Your code must define a valid pointer variable. Signals with ImportedExtern storage class must have unique signal names. See “Interface Signals to External Code” on page 7-60 for more information. Signals with Auto Storage Class Options are available for signals with Auto storage class: • Signal storage reuse • Enable local block outputs • Reuse block outputs • Eliminate superfluous local variables (expression folding) • Minimize data copies between local and global variables Use these options to control signal memory reuse and choose local or global (model_B) storage for signals. The Signal storage reuse option is on the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box, as shown in the next figure. 7-55 7 Data Representation These options interact. When the Signal storage reuse option is selected, • The Reuse block outputs option is enabled and selected, and signal memory is reused. • The Enable local block outputs option is enabled and selected. This lets you choose whether reusable signal variables are declared as local variables in functions or as members of model_B. • The Eliminate superfluous local variables (expression folding) is enabled and selected, and block computations collapse into single expressions. • The Minimize data copies between local and global variables is enabled and cleared, and global memory is not reused. The following code examples illustrate the effects of the Signal storage reuse, Enable local block outputs, Reuse block outputs, Eliminate superfluous local variables (expression folding) and Minimize data copies between local and global variables options. The examples were generated from the signal_examp model (see figure Signal_examp Model on page 7-53). The first example illustrates signal storage optimization, with Signal storage reuse, Enable local block outputs, Reuse block outputs, and Minimize data copies between local and global variables selected. (For clarity in showing the individual Gain and Sum block computation, expression folding is off in this example.) The output signal from the Sum block reuses signal_examp_Y.Out1, a variable local to the model output function. 7-56 Signals /* Model output function */ static void signal_examp_output(int_T tid) { /* Sum: ' Sum' incorporates: * Constant: ' /Constant' * Inport: ' >/In1' */ signal_examp_Y.Out1 = signal_examp_U.In1 + signal_examp_P.Constant_Value; /* Gain: ' /Gain' */ signal_examp_Y.Out1 = signal_examp_P.Gain_Gain * signal_examp_Y.Out1; /* tid is required for a uniform function interface. * Argument tid is not used in the function. */ UNUSED_PARAMETER(tid); } If you are constrained by limited stack space, you can turn Enable local block outputs off and still benefit from memory reuse. The following example was generated with Enable local block outputs cleared and Signal storage reuse, Reuse block outputs, and Minimize data copies between local and global variables selected. The output signals from the Sum and Gain blocks use global structure signal_examp_B rather than declaring local variables and in both cases the signal name is gainSig. /* Model output function */ static void signal_examp_output(int_T tid) { /* Sum: ' /Add' incorporates: * Constant: ' /Constant' * Inport: ' /In1' */ signal_examp_B.gainSig = signal_examp_U.In1 + signal_examp_P.Constant_Value; /* Gain: ' /Gain' */ signal_examp_B.gainSig = signal_examp_P.Gain_Gain * signal_examp_B.gainSig; /* Outport: ' /Out1' */ 7-57 7 Data Representation signal_examp_Y.Out1 = signal_examp_B.gainSig; /* tid is required for a uniform function interface. * Argument tid is not used in the function. */ UNUSED_PARAMETER(tid); } When the Signal storage reuse option is cleared, Reuse block outputs, Enable local block outputs, and Minimize data copies between local and global variables are disabled. This makes the block output signals global and unique, signal_examp_B.sumSig and signal_examp_B.gainSig, as shown in the following code. /* Model output function */ static void signal_examp_output(int_T tid) { /* Sum: ' /Add' incorporates: * Constant: ' /Constant' * Inport: ' /In1' */ signal_examp_B.sumSig = signal_examp_U.In1 + signal_examp_P.Constant_Value; /* Gain: ' /Gain' */ signal_examp_B.gainSig = signal_examp_P.Gain_Gain * signal_examp_B.sumSig; /* Outport: ' /Out1' */ signal_examp_Y.Out1 = signal_examp_B.gainSig; /* tid is required for a uniform function interface. * Argument tid is not used in the function. */ UNUSED_PARAMETER(tid); } In large models, disabling Signal storage reuse can significantly increase RAM and ROM usage. Therefore, this approach is not recommended for code deployment; however it can be useful in rapid prototyping environments. 7-58 Signals The following table summarizes the possible combinations of the Signal storage reuse / Reuse block outputs and Enable local block outputs options. Signal storage reuse and Reuse block outputs ON Signal storage reuse OFF (Reuse block outputs disabled) Enable local block outputs ON Reuse signals in local memory (fully optimized) N/A Enable local block outputs OFF Reuse signals in model_B structure Individual signal storage in model_B structure Control Stack Space Allocation The value of the “Maximum stack size (bytes)” parameter, on the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box constrains the use of stack space used by local block output variables. The command-line equivalent for this parameter is MaxStackSize. If the accumulated size of variables in local memory exceeds MaxStackSize, the product places subsequent local variables in global memory space. If it is important that you maximize potential for signal storage optimization, then set MaxStackSize to accommodate the size and number of signals in your model. This minimizes overflow into global memory space and maximizes use of local memory. Local variables offer more optimization potential through mechanisms such as expression folding and buffer reuse. See “Use Stack Space Allocation” on page 20-6 for more information. Signals with Test Points A test point is a signal that is stored in a unique location no other signals share or reuse. See “Test Points” in the Simulink documentation for information about including test points in your model. 7-59 7 Data Representation When you generate code for models that include test points, the Simulink Coder build process allocates a separate memory buffer for each test point. Test points are stored as members of the model_B structure. Declaring a signal as a test point disables the following options for that signal. This can lead to increased code and data size. You do not lose the benefits of optimized storage for any other signals in your model. • Signal storage reuse • Enable local block outputs • Reuse block outputs • Eliminate superfluous local variables (expression folding) • Minimize data copies between local and global variables For an example of storage declarations and code generated for a test point, see “Summary of Signal Storage Class Options” on page 7-63. If you have an Embedded Coder license, you can specify that the Simulink Coder build process ignore test points in the model, allowing optimal buffer allocation, using the “Ignore test point signals” parameter. Ignoring test points facilitates transitioning from prototyping to deployment and avoids accidental degradation of generated code due to workflow artifacts. For more information, see “Ignore test point signals”. Interface Signals to External Code The Simulink Signal Properties dialog box lets you interface selected signals to externally written code. In this way, your hand-written code has access to such signals for monitoring or other purposes. To interface a signal to external code, use the Code Generation tab of the Signal Properties dialog box to assign one of the following storage classes to the signal: • ExportedGlobal • ImportedExtern • ImportedExternPointer Set the storage class as follows: 7-60 Signals 1 In your Simulink block diagram, select the line that carries the signal. Then select Signal Properties from the Edit menu of your model. This opens the Signal Properties dialog box. Alternatively, right-click the line that carries the signal, and select Signal properties from the menu. 2 Select the Code Generation tab of the Signal Properties dialog box. 3 Select the desired storage class (Auto, ExportedGlobal, ImportedExtern, or ImportedExternPointer) from the Storage class menu. The next figure shows ExportedGlobal selected. 4 Optional: For storage classes other than Auto, you can enter a storage type qualifier such as const or volatile in the Storage type qualifier field. The Simulink Coder product does not check this string for errors; whatever you enter is included in the variable declaration. 5 Click Apply. 7-61 7 Data Representation Note You can also interface test points and other signals that are stored as members of model_B to your code. To do this, your code must know the address of the model_B structure where the data is stored, and other information. This information is not automatically exported. The Simulink Coder product provides C/C++ and Target Language Compiler APIs that give your code access to model_B and other data structures. See “Interfaces for Monitoring Signals” on page 7-64 for more information. Symbolic Naming Conventions for Signals When signals have a storage class other than Auto, the Simulink Coder product preserves symbolic information about the signals or their originating blocks in the generated code. For labeled signals, field names in model_B derive from the signal names. In the following example, the field names model_B.sumSig and model_B.gainSig are derived from the corresponding labeled signals in the signal_examp model (shown in figure Signal_examp Model on page 7-53). /* Block signals (auto storage) */ typedef struct _BlockIO_signal_examp { real_T sumSig; real_T gainSig; } BlockIO_signal_examp; /* ' /Add' */ /* ' /Gain' */ When you clear the Signal storage reuse optimization, sumSig is not part of model_B, and a local variable is used for it instead. For unlabeled signals, model_B field names are derived from the name of the source block or subsystem. The components of a generated signal label are • The root model name, followed by • The name of the generating signal object, followed by • A unique name mangling string (if required) The number of characters that a signal label can have is limited by the Maximum identifier length parameter specified on the Symbols pane 7-62 Signals of the Configuration Parameters dialog box. See “Configure Generated Identifiers” on page 9-73 for more detail. When a signal has Auto storage class, the Simulink Coder build process controls generation of variable or field names without regard to signal labels. Summary of Signal Storage Class Options The next table shows, for each signal storage class option, the variable declaration and the code generated for Sum (sumSig) and Gain (gainSig) block outputs of the model shown in figure Signal_examp Model on page 7-53. Storage Class Declaration Auto In model.c or model.cpp (with Signal storage reuse optimizations on) Code rtb_sumSig = signal_examp_U.In1 + real_T rtb_sumSig; signal_examp_P.Constant_Value; rtb_sumSig *= signal_examp_P.Gain_Gain; signal_examp_Y.Out1 = rtb_sumSig; Test point (for sumSig only) In model.h signal_examp_B.sumSig = typedef struct _BlockIO_signal_examp signal_examp_U.In1 + signal_examp_P.Constant_Value; rtb_gainSig = { real_T sumSig; } BlockIO_signal_examp; signal_examp_B.sumSig * signal_examp_P.Gain_Gain; signal_examp_Y.Out1 = rtb_gainSig; In model.c or model.cpp BlockIO_signal_examp signal_examp_B; real_T rtb_gainSig; 7-63 7 Data Representation Storage Class Declaration ExportedGlobal (for sumSig only) In model.h Code sumSig = signal_examp_U.In1 + extern real_T sumSig; signal_examp_P.Constant_Value; rtb_gainSig = sumSig * In model.c or model.cpp signal_examp_P.Gain_Gain; signal_examp_Y.Out1 = rtb_gainSig; real_T sumSig; real_T rtb_gainSig; ImportedExtern In model_private.h sumSig = signal_examp_U.In1 + extern real_T sumSig; signal_examp_P.Constant_Value; rtb_gainSig = sumSig * In model.c or model.cpp signal_examp_P.Gain_Gain; signal_examp_Y.Out1 = rtb_gainSig; real_T rtb_gainSig; ImportedExternPointer In model_private.h (*sumSig) = signal_examp_U.In1 + extern real_T *sumSig; signal_examp_P.Constant_Value; rtb_gainSig = (*sumSig) * In model.c or model.cpp signal_examp_P.Gain_Gain; signal_examp_Y.Out1 = rtb_gainSig; real_T rtb_gainSig; Interfaces for Monitoring Signals The Simulink Coder product includes • Support for developing a Target Language Compiler API for monitoring signals and states independent of external mode. See “Input Signal Functions” and “Output Signal Functions” in the Target Language Compiler documentation for information. • A C application program interface (API) for monitoring signals and states independent of external mode. See “Data Interchange Using the C API” on page 15-137 for information. 7-64 Signals • An interface for exporting ASAP2 files, which you customize to use signal objects. For details, see “ASAP2 Data Measurement and Calibration” on page 15-174. Signal Objects • “About Signal Objects for Code Generation” on page 7-65 • “Use Signal Objects for Code Generation” on page 7-66 • “Configure Signal Objects for Code Generation” on page 7-66 • “Storage Classes and Code Generation for Signal Objects” on page 7-66 • “Generate Code for Signal Objects from Command Line” on page 7-67 • “Generate Code for Signal Objects Using Model Explorer” on page 7-69 • “Resolve Conflicts in Configuration of Signals Objects” on page 7-72 This section discusses how to use signal objects in code generation. Signal objects can be used to represent both signal and state data, and behave similarly to parameter objects, described in “Parameter Objects” on page 7-38. About Signal Objects for Code Generation Within the class hierarchy of Simulink data objects, the Simulink product provides a class that is designed as base class for signal storage. This topic explains how to use signal objects in code generation. The CoderInfo properties of signal objects are used by the Simulink Coder product during code generation. These properties let you assign storage classes to the objects, thereby controlling how the generated code stores and represents signals. The Simulink Coder build process also writes information about the properties of signal objects to the model.rtw file. This information, formatted as Object records, is accessible to Target Language Compiler programs. For general information on Object records, see “Data Object Information in model.rtw”. Before using Simulink signal objects with the Simulink Coder product, read the discussion of Simulink data objects in the Simulink documentation. 7-65 7 Data Representation Use Signal Objects for Code Generation The general procedure for using signal objects in code generation is as follows: 1 Define a subclass of Simulink.Signal. 2 Instantiate signal objects from your subclass and set their properties from the command line or by using Model Explorer. 3 Use the objects as signals within your model. 4 Generate code and build your target executable. Configure Signal Objects for Code Generation In configuring signal objects for code generation, you use the following code generation options and signal object properties: • The Signal storage reuse code generation option (see “Signals” on page 7-52). • The Enable local block outputs code generation option (see “Signals” on page 7-52). • The Minimize data copies between local and global variables code generation option (see “Signals” on page 7-52). • The CoderInfo.StorageClass signal object property: The storage classes defined for signal objects, and their effect on code generation, are the same for model signals and signal objects (see “Signals Storage Classes” on page 7-54). Other signal object properties (such as user-defined properties of classes derived from Simulink.Signal) do not affect code generation. Storage Classes and Code Generation for Signal Objects The way in which the Simulink Coder product uses storage classes to determine how signals are stored is the same with and without signal objects. However, if a signal’s label resolves to a signal object, the object’s CoderInfo.StorageClass property is used in place of the port configuration of the signal. 7-66 Signals The default storage class is Auto. If the storage type is Auto, the Simulink Coder product follows the Signal storage reuse, Reuse block outputs, Enable local block outputs, Eliminate superfluous local variables (expression folding), and Minimize data copies between local and global variables code generation options to determine whether signal objects are stored in reusable and/or local variables. Make sure that these options are set for your application. To generate a test point or signal storage declaration that can interface externally, use an explicit CoderInfo.StorageClass assignment. For example, setting the storage class to SimulinkGlobal, as in the following command, is equivalent to declaring a signal as a test point. SinSig.CoderInfo.StorageClass = 'SimulinkGlobal'; Generate Code for Signal Objects from Command Line The discussion and code examples in this section refer to the model shown in the next figure. To configure a signal object, you must first create it and associate it with a labeled signal in your model. To do this, 1 Define a subclass of Simulink.Signal. In this example, the signal object is an instance of the class Simulink.Signal, which is provided with the Simulink product. 2 Instantiate a signal object from your subclass. The following example instantiates inSig, a signal object of class Simulink.Signal. inSig = Simulink.Signal inSig = 7-67 7 Data Representation Simulink.Signal CoderInfo: [1x1 Simulink.SignalCoderInfo] Description: '' DataType: 'auto' Min: [] Max: [] DocUnits: '' Dimensions: -1 Complexity: 'auto' SampleTime: -1 SamplingMode: 'auto' InitialValue: '' Make sure that the name of the signal object matches the label of the desired signal in your model. This enables the Simulink engine to resolve the signal label to the corresponding object. For example, in the model shown in the above figure, the signal label inSig would resolve to the signal object inSig. 3 You can require signals in a model to resolve to Simulink.Signal objects. To do this for the signal inSig, in the model window right-click the signal line labeled inSig and choose Signal Properties from the context menu. A Signal Properties dialog appears. 7-68 Signals 4 In the Signal Properties dialog box that appears, select the check box labelled Signal name must resolve to Simulink signal object, and click OK or Apply. 5 Set the object properties as required. You can do this by using the Simulink Model Explorer. Alternatively, you can assign properties by using MATLAB commands. For example, assign the signal object’s storage class by setting the CoderInfo.StorageClass property as follows. inSig.CoderInfo.StorageClass = 'ExportedGlobal'; Generate Code for Signal Objects Using Model Explorer If you prefer, you can create signal objects and modify their attributes using Model Explorer. This lets you see and set attributes of a signal in a dialog 7-69 7 Data Representation box pane, and alleviates the need to remember and type field names. Do the following to instantiate inSig and set its attributes from Model Explorer: 1 Choose Model Explorer from the View menu. Model Explorer opens or activates if it already was open. 2 Select Base Workspace in the Model Hierarchy pane. 3 Select Simulink Signal from the Add menu. A new signal named Sig appears in the Contents pane. 4 To set the signal name in Model Explorer, click the word Sig in the Name column to select it, and rename it by typing inSig followed by Return in place of Sig. 7-70 Signals 5 To set the inSig.CoderInfo.StorageClass in Model Explorer, click the Storage class menu and select ExportedGlobal, as shown in the next figure. 6 Click Apply. The following table shows, for each setting of CoderInfo.StorageClass, the variable declaration and the code generated for the inport signal (inSig) of the current model: 7-71 7 Data Representation Storage Class Declaration Code Auto (with In model.h storage optimizations on) typedef struct signal_objs_examp_U.inSig * _ExternalInputs_signal_ objs_examp_tag signal_objs_examp_P.Gain_Gain; rtb_Gain1Sig = { real_T inSig; } ExternalInputs_signal_ objs_examp; SimulinkGlobal In model.h rtb_Gain1Sig = typedef struct signal_objs_examp_U.inSig * _ExternalInputs_signal_objs_examp_tag signal_objs_examp_P.Gain_Gain; { real_T inSig; } ExternalInputs_signal_objs_examp; ExportedGlobal In model.c or model.cpp rtb_Gain1Sig = inSig * real_T inSig; signal_objs_examp_P.Gain_Gain; In model.h extern real_T inSig; ImportedExtern In model_private.h rtb_Gain1Sig = inSig * extern real_T inSig; signal_objs_examp_P.Gain_Gain; ImportedExternPointer In model_private.h rtb_Gain1Sig = (*inSig) * extern real_T *inSig; signal_objs_examp_P.Gain_Gain; Resolve Conflicts in Configuration of Signals Objects If a signal is defined in the Signal Properties dialog box and a signal object of the same name is defined by using the command line or in the Model Explorer, the potential exists for ambiguity when the Simulink engine attempts to resolve the symbol representing the signal name. One way to resolve the 7-72 Signals ambiguity is to specify that a signal must resolve to a Simulink data object. To do this, select the Signal name must resolve to Simulink signal object option in the Signal Properties dialog box. When you do this, you no longer can specify the Storage class property in the Code Generation tab of the Signal Properties dialog box, as the next figure shows. As the preceding figure shows, the Storage class menu is disabled because it is up to the SinSig Simulink.Signal object to specify its own storage class. The signal and signal objects SinSig both have SimulinkGlobal storage class. Therefore, no conflict arises, and SinSig resolves to the signal object SinSig. Note The rules for compatibility between block states/signal objects are identical to those given for signals/signal objects. 7-73 7 Data Representation Initialize Signals and States Using Signal Objects You can use Simulink signal objects to initialize signals and discrete states with user-defined values for simulation and code generation. Data initialization increases application reliability and is a requirement of safety critical applications. Initializing signals for both simulation and code generation can expedite transitions between phases of Model-Based Design. For details on simulation behavior, see “Initialization Behavior Summary for Signal Objects” in the Simulink documentation. Specify Initial Value for Signal Object You can use signal objects that have a storage class other than 'auto’ or 'SimulinkGlobal' to initialize • Discrete states with an initial condition parameter • Any signals in a model except bus signals and signals with constant sample time The initial value is the signal or state value before a simulation takes its first time step. 7-74 Signals Note Some initial value settings may depend on the initialization mode. For more information, see “Underspecified initialization detection”. Classic initialization mode: In this mode, initial value settings for signal objects that represent the following signals and states override the corresponding block parameter initial values if undefined (specified as []): • Output signals of conditionally executed subsystems and Merge blocks • Block states Simplified initialization mode: In this mode, initial values of signal objects associated with the output of the following blocks are ignored. The initial values of the corresponding blocks (which cannot be specified as []) are used instead. • Output signals of conditionally executed subsystems • Merge blocks To specify an initial value, use the Model Explorer or MATLAB commands to do the following: 1 Create the signal object. Model Explorer 7-75 7 Data Representation MATLAB Command S1=Simulink.Signal; The name of the signal object must be the same as the name of the signal that the object is initializing. Although not required, consider setting the Signal name must resolve to Simulink signal object option in the Signal Properties dialog box. This setting makes signal objects in the MATLAB workspace consistent with signals that appear in your model. Consider using the Data Object Wizard to create signal objects. The Data Object Wizard searches a model for signals for which signal objects do not exist. You can then selectively create signal objects for multiple signals listed in the search results with a single operation. For more information about the Data Object Wizard, see “Data Object Wizard” in the Simulink documentation. 7-76 Signals 2 Set the signal object’s storage class to a value other than 'auto’ or 'SimulinkGlobal'. Model Explorer MATLAB Command S1.CoderInfo.StorageClass='ExportedGlobal'; 3 Set the initial value. You can specify any MATLAB string expression that evaluates to a double numeric scalar value or array. 7-77 7 Data Representation Model Explorer MATLAB Command 1.5 [1 2 3] 1+0.5 foo = 1.5; s1.InitialValue = 'foo'; Invalid uint(1) foo = '1.5'; s1.InitialValue = 'foo'; Valid The Simulink engine converts the initial value so the type, complexity, and dimension are consistent with the corresponding block parameter value. If you specify an invalid value or expression, an error message appears when you update the model. Model Explorer MATLAB Command 7-78 Signals S1.InitialValue='0.5' The following example shows a signal object specifying the initial output of an enabled subsystem. Enable 1 2 In1 Gain e 1 Out1 Initial Output = [] Enable Ts = 0.1 Phase Delay = 10 samples Scope In1 Sine Wave Amplitude = 1 Period = 10 samples Ts = 0.1 Out1 s Enabled Subsystem Signal s is initialized to 4.5. Note that to avoid a consistency error, the initial value of the enabled subsystem’s Outport block must be [ ] or 4.5. Signal Object Initialization in Generated Code The initialization behavior for code generation is the same as that for model simulation with the following exceptions: 7-79 7 Data Representation • RSim executables can use the Data Import/Export pane of the Configuration Parameters dialog box to load input values from MAT-files. GRT and ERT executables cannot load input values from MAT-files. • The initial value for a block output signal or root level input or output signal can be overwritten by an external (calling) program. • Setting the initial value for persistent signals is relevant if the value is used or viewed by an external application. For details on initialization behavior for different types of signals and discrete states, see “Initialization Behavior Summary for Signal Objects” in the Simulink documentation. When you initialize Simulink signal objects in a model during code generation, the corresponding initialization statements are placed in model.c or model.cpp in the model’s initialize code. For example, consider the model rtwdemo_sigobj_iv. If you create and initialize signal objects in the base workspace, the Simulink Coder product places initialization code for the signals in the file rtwdemo_sigobj_iv.c under the rtwdemo_sigobj_iv_initialize function, as shown below. /* Model initialize function */ void rtwdemo_sigobj_iv_initialize(boolean_T firstTime) { 7-80 Signals . . . /* exported global signals */ S3 = -3.0; S2 = -2.0; . . . /* exported global states */ X1 = 0.0; X2 = 0.0; /* external inputs */ S1 = -4.5; . . . The following code shows the initialization code for the enabled subsystem’s Unit Delay block state X1 and output signal S2. void MdlStart(void) { . . . /* InitializeConditions for UnitDelay: ' /Unit Delay' */ X1 = aa1; /* Start for enable system: ' /Enabled Subsystem (state X1 inside)' */ /* virtual outports code */ /* (Virtual) Outport Block: ' /Out1' */ S2 = aa2; } 7-81 7 Data Representation Also note that for an enabled subsystem, such as the one shown in the preceding model, the initial value is also used as a reset value if the subsystem’s Outport block parameter Output when disabled is set to reset. The following code from rtwdemo_sigobj_iv.c shows the assignment statement for S3 as it appears in the model output function rtwdeni_sigobj_iv_output. /* Model output function */ static void rtwdemo_sigobj_iv_output(void) { . . . /* Disable for enable system: ' /Enabled Subsystem (state X1 inside)' */ /* (Virtual) Outport Block: ' /Out1' */ S2 = aa2; Tunable Initial Values If you specify a tunable parameter in the initial value for a signal object, the parameter expression is preserved in the initialization code in model.c. For example, if you configure parameter df to be tunable for model signal_iv and you initialize the signal object for discrete state X1 with the expression df*2, the following initialization code appears for signal object X1 in signal_iv.c. void MdlInitialize(void) { /* InitializeConditions for UnitDelay: ' /Unit Delay X1=2' */ X1 = (tunable_param_P.df * 2.0); } For more information about the treatment of tunable parameters in generated code, see “Parameters” on page 7-10. 7-82 States States In this section... “About States” on page 7-83 “State Storage” on page 7-83 “State Storage Classes” on page 7-84 “Interface States to External Code” on page 7-85 “Symbolic Names for States” on page 7-87 “Control Code Generation for Block States” on page 7-90 “Summary of State Storage Class Options” on page 7-91 About States For certain block types, the Simulink Coder product lets you control how block states in your model are stored and represented in the generated code. Using the State Attributes tab of a block dialog box, you can: • Control whether or not states declared in generated code are interfaceable (visible) to externally written code. You can also specify that states be stored in locations declared by externally written code. • Assign symbolic names to block states in generated code. State Storage The discussion of block state storage in this section applies to the following blocks: • Discrete Filter • Discrete PID Controller • Discrete PID Controller (2DOF) • Discrete State-Space • Discrete-Time Integrator • Discrete Transfer Function 7-83 7 Data Representation • Discrete Zero-Pole • Memory • Unit Delay These blocks require persistent memory to store values representing the state of the block between consecutive time intervals. By default, such values are stored in a data type work vector. This vector is usually referred to as the DWork vector. It is represented in generated code as model_DWork, a global data structure. If you want to interface a block state to your hand-written code, you can specify that the state is to be stored in a location other than the DWork vector. You do this by assigning a storage class to the block state. You can also define a symbolic name, to be used in code generation, for a block state. State Storage Classes The storage class property of a block state specifies how the Simulink Coder product declares and stores the state in a variable. Storage class options for block states are similar to those for signals. The available storage classes are • Auto • ExportedGlobal • ImportedExtern • ImportedExternPointer Default Storage Class Auto is the default storage class and is the storage class you should use for states that you do not need to interface to external code. States with Auto storage class are stored as members of the Dwork vector. You can assign a symbolic name to states with Auto storage class. If you do not supply a name, the Simulink Coder product generates one, as described in “Symbolic Names for States” on page 7-87. 7-84 States Explicitly Assigned Storage Classes Block states with storage classes other than Auto are stored in unstructured global variables, independent of the Dwork vector. These storage classes are for states that you want to interface to external code. The following storage classes are available for states: • ExportedGlobal: The state is stored in a global variable. model.h exports the variable. States with ExportedGlobal storage class must have unique names. • ImportedExtern: model_private.h declares the state as an extern variable. Your code must supply the variable definition. States with ImportedExtern storage class must have unique names. • ImportedExternPointer: model_private.h declares the state as an extern pointer. Your code must supply the pointer variable definition. States with ImportedExternPointer storage class must have unique names. The table in “Summary of Signal Storage Class Options” on page 7-63 gives examples of variable declarations and the code generated for block states with each type of storage class. Note Assign a symbolic name to states to specify a storage class other than auto. If you do not supply a name for auto states, the Simulink Coder product generates one, as described in “Symbolic Names for States” on page 7-87. The next section explains how to use the State Attributes tab of the block dialog box to assign storage classes to block states. Interface States to External Code In the State Attributes tab of a block parameter dialog box, you can interface a block’s state to external code by assigning the state a storage class other than Auto (that is, ExportedGlobal, ImportedExtern, or ImportedExternPointer). Set the storage class as follows: 7-85 7 Data Representation 1 In your block diagram, double-click the desired block. This action opens the block dialog box with two or more tabs, which includes State Attributes. 2 Click the State Attributes tab. 3 Enter a name for the variable to be used to store block state in the State name field. The State name field turns yellow to indicate that you changed it. 4 Click Apply to register the variable name. The first two fields beneath the State name, State name must resolve to Simulink signal object and Code generation storage class, become enabled. 5 If the state is to be stored in a Simulink signal object in the base or model workspace, select State name must resolve to Simulink signal object. If you choose this option, you cannot declare a storage class for the state in the block, and the fields below become disabled. 7-86 States 6 Select the desired storage class (ExportedGlobal, ImportedExtern, or ImportedExternPointer) from the Code generation storage class menu. 7 Optional: For storage classes other than Auto, you can enter a storage type qualifier such as const or volatile in the Code generation storage type qualifier field. The Simulink Coder product does not check this string for errors; what you enter is included in the variable declaration. 8 Click OK or Apply and close the dialog box. Symbolic Names for States To determine the variable or field name generated for a block’s state, you can: • Use a default name generated by the Simulink Coder product • Define a symbolic name by using the State name field of the State Attributes tab in a block dialog box Default Block State Naming Convention If you do not define a symbolic name for a block state, the Simulink Coder product uses the following default naming convention: BlockType#_DSTATE where • BlockType is the name of the block type (for example, Discrete_Filter). • # is a unique ID number (#) assigned by the Simulink Coder product if multiple instances of the same block type appear in the model. The ID number is appended to BlockType. • _DSTATE is a string that is always appended to the block type and ID number. For example, consider the model shown in the next figure. 7-87 7 Data Representation Model with Two Discrete Filter Block States Examine the code generated for the states of the two Discrete Filter blocks. Assume that: • Neither block’s state has a user-defined name. • The upper Discrete Filter block has Auto storage class (and is therefore stored in the DWork vector). • The lower Discrete Filter block has ExportedGlobal storage class. The states of the two Discrete Filter blocks are stored in DWork vectors, initialized as shown in the code below: /* data type work */ disc_filt_states_M->Work.dwork = ((void *) &disc_filt_states_DWork); (void)memset((char_T *) &disc_filt_states_DWork, 0, sizeof(D_Work_disc_filt_states)); { int_T i; real_T *dwork_ptr = (real_T *) &disc_filt_states_DWork.DiscFilt_DSTATE; for (i = 0; i < 2; i++) { dwork_ptr[i] = 0.0; } } 7-88 States Define User Block State Names Using the State Attributes tab of a block dialog box, you can define your own symbolic name for a block state: 1 In your block diagram, double-click the desired block. This action opens the block dialog box, containing two or more tabs, which includes State Attributes. 2 Click the State Attributes tab. 3 Enter the symbolic name in the State name field. For example, enter the state name Top_filter. 4 Click Apply. The dialog box now looks like this: 5 Click OK. The following state initialization code was generated from the example model shown in “Generate Code for Signal Objects from Command Line” on page 7-67, under the following conditions: 7-89 7 Data Representation • The upper Discrete Filter block has the state name Top_filter, and Auto storage class (and is therefore stored in the DWork vector). • The lower Discrete Filter block has the state name Lower_filter, and storage class ExportedGlobal. Top_filter is placed in the Dwork vector. /* data type work */ disc_filt_states_M->Work.dwork = ((void *) &disc_filt_states_DWork); (void)memset((char_T *) &disc_filt_states_DWork, 0, sizeof(D_Work_disc_filt_states)); disc_filt_states_DWork.Top_filter = 0.0; /* exported global states */ Lower_filter = 0.0; Control Code Generation for Block States If you are not familiar with Simulink data objects and signal objects, you should read “Signals” on page 7-52 before reading this section. You can associate a block state with a signal object and control code generation for the block state through the signal object: 1 Instantiate the desired signal object, and set its CoderInfo.StorageClass property. 2 Open the dialog box for the block whose state you want to associate with the signal object. 3 Click the State Attributes tab. 4 Enter the name of the signal object in the State name field. 5 Select State name must resolve to Simulink signal object. This step disables the Code generation storage class and Code generation storage type qualifier options in the State Attributes tab, because the signal object specifies these settings. 7-90 States 6 Click Apply and close the dialog box. Note When a block state is associated with a signal object, the mapping between the block state and the signal object must be one-to-one. If two or more identically named entities, such as a block state and a signal, map to the same signal object, the name conflict is flagged as an error at code generation time. Summary of State Storage Class Options Here is a simple model, unit_delay, which contains a Unit Delay block: The following table shows, for each state storage class option, the variable declaration and initialization code generated for a Unit Delay block state. The block state has the user-defined state name udx. Storage Class Declaration Auto In model.h Initialization Code unit_delay_DWork.udx = 0.0; typedef struct D_Work_unit_delay_tag { real_T udx; } D_Work_unit_delay; Exported Global In model.c or model.cpp In model.c or model.cpp real_T udx; udx = 0.0; In model.h extern real_T udx; 7-91 7 Data Representation Storage Class Declaration Initialization Code ImportedExtern In model_private.h In model.c or model.cpp extern real_T udx; udx = unit_delay_P.UnitDelay_X0; ImportedExternPointer In model_private.h In model.c or model.cpp extern real_T *udx; (*udx) = unit_delay_P.UnitDelay_X0; 7-92 Data Stores Data Stores In this section... “About Data Stores” on page 7-93 “Storage Classes for Data Store Memory Blocks” on page 7-93 “Generate Code for Data Store Memory Blocks” on page 7-96 “Nonscalar Data Stores in Generated Code” on page 7-97 “Data Store Buffering in Generated Code” on page 7-99 About Data Stores A data store contains data that is accessible at any point in a model hierarchy at or below the level in which the data store is defined. Data stores can allow subsystems and referenced models to share data without having to use I/O ports to pass the data from level to level. See “Data Stores with Data Store Memory Blocks” for information about data stores in Simulink. This section provides additional information about data store code generation. Storage Classes for Data Store Memory Blocks You can control how Data Store Memory blocks in your model are stored and represented in the generated code by assigning storage classes and type qualifiers. You do this in almost exactly the same way you assign storage classes and type qualifiers for block states. Data Store Memory blocks, like block states, have Auto storage class by default, and their memory is stored within the DWork vector. The symbolic name of the storage location is based on the data store name. You can generate code from multiple Data Store Memory blocks that have the same data store name, subject to the following restriction: at most one of the identically named blocks can have a storage class other than Auto. An error is reported if this condition is not met. For blocks with Auto storage class, the Simulink Coder product generates a unique symbolic name for each block to avoid name clashes. For Data Store 7-93 7 Data Representation Memory blocks with storage classes other than Auto, the generated code uses the data store name as the symbol. In the following model, a Data Store Write block writes to memory declared by the Data Store Memory block myData: To control the storage declaration for a Data Store Memory block, use the Code Generation > Storage class and Code Generation > Storage type qualifier fields of the Data Store Memory block dialog box. The next figure shows the Data Store Memory block dialog box for the preceding model. 7-94 Data Stores Data Store Memory blocks are nonvirtual because code is generated for their initialization in .c and .cpp files and their declarations in header files. The following table shows how the code generated for the Data Store Memory block in the preceding model differs for different settings of Code Generation > Storage class. The table gives the variable declarations and MdlOutputs code generated for the myData block. 7-95 7 Data Representation Storage Class Declaration Auto In model.h Code model_DWork.myData = typedef struct rtb_SineWave; D_Work_tag { real_T myData; } D_Work; In model.c or model.cpp /* Block states (auto storage) */ D_Work model_DWork; In model.c or model.cpp ExportedGlobal myData = rtb_SineWave; /* Exported block states */ real_T myData; In model.h extern real_T myData; In model_private.h ImportedExtern myData = rtb_SineWave; extern real_T myData; ImportedExternPointer In model_private.h (*myData) = rtb_SineWave; extern real_T *myData; Generate Code for Data Store Memory Blocks If you are not familiar with Simulink data objects and signal objects, you should read “Signals” on page 7-52 before reading this section. 7-96 Data Stores You can associate a Data Store Memory block with a signal object, and control code generation for the block through the signal object. To do this: 1 Instantiate the desired signal object. 2 Set the object’s CoderInfo.StorageClass property to indicate the desired storage class. 3 Open the block dialog box for the Data Store Memory block that you want to associate with the signal object. 4 Enter the name of the signal object in the Data store name field. 5 Select Data store name must resolve to Simulink signal object. 6 Do not set the storage class field to a value other than Auto (the default). 7 Click OK or Apply. Note When a Data Store Memory block is associated with a signal object, the mapping between the Data store name and the signal object name must be one-to-one. If two or more identically named entities map to the same signal object, the name conflict is flagged as an error at code generation time. See “Resolve Conflicts in Configuration of Signals Objects” on page 7-72 for more information. Nonscalar Data Stores in Generated Code Stateflow generates efficient code for accessing individual elements of nonscalar data stores. For example, the next figure shows a data store named A that has seven elements. The Stateflow chart assigns the fourth element of the data store from a value computed from the third element. The generated code is efficient and involves no unnecessary access of any of the other elements of A. 7-97 7 Data Representation In contrast, modeling and code generation for data store element selection and assignment in Simulink is more explicit. The next figure shows the same algorithm modeled without using a Stateflow chart. The assignment block 7-98 Data Stores copies each element of the data store back to itself, in addition to updating the element. Data Store Buffering in Generated Code A Data Store Read block is a nonvirtual block that copies the value of the data store to its output buffer when it executes. Since the value is buffered, all downstream blocks connected to the output of the data store read utilize the same value, even if a Data Store Write block updates the data store in between execution of two of the downstream blocks. The next figure shows a model that uses blocks whose priorities have been modified to achieve a particular order of execution: 7-99 7 Data Representation The following execution order applies: 1 The block Data Store Read buffers the current value of the data store A at its output. 2 The block Abs1 uses the buffered output of Data Store Read. 3 The block Data Store Write updates the data store. 4 The block Abs uses the buffered output of Data Store Read. Because the output of Data Store Read is a buffer, both Abs and Abs1 use the same value: the value of the data store at the time that Data Store Read executes. The next figure shows another example: 7-100 Data Stores In this example, the following execution order applies: 1 The block Data Store Read buffers the current value of the data store A at its output. 2 Atomic Subsystem executes. 3 The Sum block adds the output of Atomic Subsystem to the output of Data Store Read. Simulink assumes that Atomic Subsystem might update the data store, so Simulink buffers the data store. Atomic Subsystem executes after Data Store 7-101 7 Data Representation Read buffers its output, and the buffer provides a way for the Sum block to use the value of the data store as it was when Data Store Read executed. In some cases, theSimulink Coder code generator determines that it can optimize away the output buffer for a Data Store Read block, and the generated code will refer to the data store directly, rather than a buffered value of it. The next figure shows an example: In the generated code, the argument of the fabs() function is the data store A rather than a buffered value. 7-102 8 Entry Point Functions and Scheduling • “Entry Point Functions and Scheduling” on page 8-2 • “About Model Execution” on page 8-4 • “Non-Real-Time Single-Tasking Systems” on page 8-6 • “Non-Real-Time Multitasking Systems” on page 8-7 • “Real-Time Single-Tasking Systems” on page 8-9 • “Real-Time Multitasking Systems” on page 8-11 • “Multitasking Systems Using Real-Time Tasking Primitives” on page 8-14 • “Program Timing” on page 8-16 • “Program Execution” on page 8-18 • “External Mode Communication” on page 8-19 • “Data Logging in Single-Tasking and Multitasking Model Execution” on page 8-20 • “Rapid Prototyping and Embedded Model Execution Differences” on page 8-22 • “Rapid Prototyping Model Functions” on page 8-23 • “Embedded Model Functions” on page 8-30 8 Entry Point Functions and Scheduling Entry Point Functions and Scheduling The following functions represent entry points in the generated code for a Simulink model. Function Description model_initialize Initialization entry point in generated code for Simulink model model_SetEventsForThisBaseStep Set event flags for multirate, multitasking operation before calling model_step for Simulink model — not generated as of Version 5.1 (R2008a) model_step Step routine entry point in generated code for Simulink model model_terminate Termination entry point in generated code for Simulink model For ERT-based models, the calling interface generated for each of these functions differs significantly depending on how you set the Generate reusable code parameter. By default, Generate reusable code is off, and the model entry point functions access model data with statically allocated global data structures. When Generate reusable code is on, model data structures are passed in (by reference) as arguments to the model entry point functions. For efficiency, only those data structures that are actually used in the model are passed in. Therefore when Generate reusable code is on, the argument lists generated for the entry point functions vary according to the requirements of the model. The entry points are exported with model.h. To call the entry-point functions from your hand-written code, add an #include model.h directive to your code. For ERT-based models, if Generate reusable code is on, you must examine the generated code to determine the calling interface required for these functions. 8-2 Entry Point Functions and Scheduling For more information, see the reference pages for the listed functions. Note The function reference pages document the default (GRT or ERT with Generate reusable code off) calling interface generated for these functions. 8-3 8 Entry Point Functions and Scheduling About Model Execution Before looking at the two styles of generated code, you need to have a high-level understanding of how the generated model code is executed. The Simulink Coder software generates algorithmic code as defined by your model. You can include your own code in your model by using S-functions. S-functions can range from high-level signal manipulation algorithms to low-level device drivers. The Simulink Coder product also provides a run-time interface that executes the generated model code. The run-time interface and model code are compiled together to create the model executable. The next figure shows a high-level object-oriented view of the executable. Execution driver for model code, operating system interface routines, I/O dependent routines, solver and data logging routines. Model code and S-functions Run-Time Interface The Object-Oriented View of a Real-Time Program In general, the conceptual design of the model execution driver does not change between the rapid prototyping and embedded style of generated code. The following sections describe model execution for single-tasking and multitasking environments both for simulation (non-real-time) and for real time. For most models, the multitasking environment will provide the most efficient model execution (that is, fastest sample rate). The following concepts are useful in describing how models execute. • Initialization: model_initialize initializes the run-time interface code and the model code. • ModelOutputs: Calling all blocks in your model that have a sample hit at the current time and having them produce their output. model_output can 8-4 About Model Execution be done in major or minor time steps. In major time steps, the output is a given simulation time step. In minor time steps, the run-time interface integrates the derivatives to update the continuous states. • ModelUpdate: model_update calls all blocks in your model that have a sample hit at the current point in time and has them update their discrete states or similar type objects. • ModelDerivatives: Calling all blocks in your model that have continuous states and having them update their derivatives. model_derivatives is only called in minor time steps. • ModelTerminate: model_terminate terminates the program if it is designed to run for a finite time. It destroys the real-time model data structure, deallocates memory, and can write data to a file. The identifying names in the preceding list (ModelOutputs, and so on) identify functions in pseudocode examples shown in the following sections. • “Non-Real-Time Single-Tasking Systems” on page 8-6 • “Non-Real-Time Multitasking Systems” on page 8-7 • “Real-Time Single-Tasking Systems” on page 8-9 • “Real-Time Multitasking Systems” on page 8-11 • “Multitasking Systems Using Real-Time Tasking Primitives” on page 8-14 8-5 8 Entry Point Functions and Scheduling Non-Real-Time Single-Tasking Systems The pseudocode below shows the execution of a model for a non-real-time single-tasking system. main() { Initialization While (time < final time) ModelOutputs -- Major time step. LogTXY -- Log time, states and root outports. ModelUpdate -- Major time step. Integrate -- Integration in minor time step for -- models with continuous states. ModelDerivatives Do 0 or more ModelOutputs ModelDerivatives EndDo -- Number of iterations depends upon the solver Integrate derivatives to update continuous states. EndIntegrate EndWhile Termination } The initialization phase begins first. This consists of initializing model states and setting up the execution engine. The model then executes, one step at a time. First ModelOutputs executes at time t, then the workspace I/O data is logged, and then ModelUpdate updates the discrete states. Next, if your model has any continuous states, ModelDerivatives integrates the continuous states’ derivatives to generate the states for time tnew = t + h , where h is the step size. Time then moves forward to tnew and the process repeats. During the ModelOutputs and ModelUpdate phases of model execution, only blocks that reach the current point in time execute. 8-6 Non-Real-Time Multitasking Systems Non-Real-Time Multitasking Systems The pseudocode below shows the execution of a model for a non-real-time multitasking system. main() { Initialization While (time < final time) ModelOutputs(tid=0) -- Major time step. LogTXY -- Log time, states, and root -- outports. ModelUpdate(tid=0) -- Major time step. Integrate -- Integration in minor time step for -- models with continuous states. ModelDerivatives Do 0 or more ModelOutputs(tid=0) ModelDerivatives EndDo (Number of iterations depends upon the solver.) Integrate derivatives to update continuous states. EndIntegrate For i=1:NumTids ModelOutputs(tid=i) -- Major time step. ModelUpdate(tid=i) -- Major time step. EndFor EndWhile Termination } Multitasking operation is more complex than single-tasking execution because the output and update functions are subdivided by the task identifier (tid) that is passed into these functions. This allows for multiple invocations of these functions with different task identifiers using overlapped interrupts, or for multiple tasks when using a real-time operating system. In simulation, multiple tasks are emulated by executing the code in the order that would occur if no preemption existed in a real-time system. Multitasking execution assumes that all task rates are multiples of the base rate. The Simulink product enforces this when you create a fixed-step 8-7 8 Entry Point Functions and Scheduling multitasking model. The multitasking execution loop is very similar to that of single-tasking, except for the use of the task identifier (tid) argument to ModelOutputs and ModelUpdate. 8-8 Real-Time Single-Tasking Systems Real-Time Single-Tasking Systems The pseudocode below shows the execution of a model in a real-time single-tasking system where the model is run at interrupt level. rtOneStep() { Check for interrupt overflow Enable "rtOneStep" interrupt ModelOutputs -- Major time step. LogTXY -- Log time, states and root outports. ModelUpdate -- Major time step. Integrate -- Integration in minor time step for models -- with continuous states. ModelDerivatives Do 0 or more ModelOutputs ModelDerivatives EndDo (Number of iterations depends upon the solver.) Integrate derivatives to update continuous states. EndIntegrate } main() { Initialization (including installation of rtOneStep as an interrupt service routine, ISR, for a real-time clock). While(time < final time) Background task. EndWhile Mask interrupts (Disable rtOneStep from executing.) Complete any background tasks. Shutdown } Real-time single-tasking execution is very similar to non-real-time single-tasking execution, except that instead of free-running the code, the rt_OneStep function is driven by a periodic timer interrupt. 8-9 8 Entry Point Functions and Scheduling At the interval specified by the program’s base sample rate, the interrupt service routine (ISR) preempts the background task to execute the model code. The base sample rate is the fastest in the model. If the model has continuous blocks, then the integration step size determines the base sample rate. For example, if the model code is a controller operating at 100 Hz, then every 0.01 seconds the background task is interrupted. During this interrupt, the controller reads its inputs from the analog-to-digital converter (ADC), calculates its outputs, writes these outputs to the digital-to-analog converter (DAC), and updates its states. Program control then returns to the background task. All these steps must occur before the next interrupt. 8-10 Real-Time Multitasking Systems Real-Time Multitasking Systems The following pseudocode shows how a model executes in a real-time multitasking system where the model is run at interrupt level. rtOneStep() { Check for interrupt overflow Enable "rtOneStep" interrupt ModelOutputs(tid=0) -- Major time step. LogTXY -- Log time, states and root outports. ModelUpdate(tid=0) -- Major time step. Integrate -- Integration in minor time step for -- models with continuous states. ModelDerivatives Do 0 or more ModelOutputs(tid=0) ModelDerivatives EndDo (Number of iterations depends upon the solver.) Integrate derivatives and update continuous states. EndIntegrate For i=1:NumTasks If (hit in task i) ModelOutputs(tid=i) ModelUpdate(tid=i) EndIf EndFor } main() { Initialization (including installation of rtOneStep as an interrupt service routine, ISR, for a real-time clock). While(time < final time) Background task. EndWhile Mask interrupts (Disable rtOneStep from executing.) Complete any background tasks. Shutdown } 8-11 8 Entry Point Functions and Scheduling Running models at interrupt level in a real-time multitasking environment is very similar to the previous single-tasking environment, except that overlapped interrupts are employed for concurrent execution of the tasks. The execution of a model in a single-tasking or multitasking environment when using real-time operating system tasking primitives is very similar to the interrupt-level examples discussed above. The pseudocode below is for a single-tasking model using real-time tasking primitives. tSingleRate() { MainLoop: If clockSem already "given", then error out due to overflow. Wait on clockSem ModelOutputs -- Major time step. LogTXY -- Log time, states and root -- outports ModelUpdate -- Major time step Integrate -- Integration in minor time step -- for models with continuous -- states. ModelDeriviatives Do 0 or more ModelOutputs ModelDerivatives EndDo (Number of iterations depends upon the solver.) Integrate derivatives to update continuous states. EndIntegrate EndMainLoop } main() { Initialization Start/spawn task "tSingleRate". Start clock that does a "semGive" on a clockSem semaphore. Wait on "model-running" semaphore. Shutdown } 8-12 Real-Time Multitasking Systems In this single-tasking environment, the model executes as real-time operating system tasking primitives. In this environment, create a single task (tSingleRate) to run the model code. This task is invoked when a clock tick occurs. The clock tick gives a clockSem (clock semaphore) to the model task (tSingleRate). The model task waits for the semaphore before executing. The clock ticks occur at the fundamental step size (base rate) for your model. 8-13 8 Entry Point Functions and Scheduling Multitasking Systems Using Real-Time Tasking Primitives The pseudocode below is for a multitasking model using real-time tasking primitives. tSubRate(subTaskSem,i) { Loop: Wait on semaphore subTaskSem. ModelOutputs(tid=i) ModelUpdate(tid=i) EndLoop } tBaseRate() { MainLoop: If clockSem already "given", then error out due to overflow. Wait on clockSem For i=1:NumTasks If (hit in task i) If task i is currently executing, then error out due to overflow. Do a "semGive" on subTaskSem for task i. EndIf EndFor ModelOutputs(tid=0) -- major time step. LogTXY -- Log time, states and root outports. ModelUpdate(tid=0) -- major time step. Loop: -- Integration in minor time step for -- models with continuous states. ModelDeriviatives Do 0 or more ModelOutputs(tid=0) ModelDerivatives EndDo (number of iterations depends upon the solver). Integrate derivatives to update continuous states. EndLoop EndMainLoop } main() 8-14 Multitasking Systems Using Real-Time Tasking Primitives { Initialization Start/spawn task "tSubRate". Start/spawn task "tBaseRate". Start clock that does a "semGive" on a clockSem semaphore. Wait on "model-running" semaphore. Shutdown } In this multitasking environment, the model is executed using real-time operating system tasking primitives. Such environments require several model tasks (tBaseRate and several tSubRate tasks) to run the model code. The base rate task (tBaseRate) has a higher priority than the subrate tasks. The subrate task for tid=1 has a higher priority than the subrate task for tid=2, and so on. The base rate task is invoked when a clock tick occurs. The clock tick gives a clockSem to tBaseRate. The first thing tBaseRate does is give semaphores to the subtasks that have a hit at the current point in time. Because the base rate task has a higher priority, it continues to execute. Next it executes the fastest task (tid=0), consisting of blocks in your model that have the fastest sample time. After this execution, it resumes waiting for the clock semaphore. The clock ticks are configured to occur at the fundamental step size for your model. 8-15 8 Entry Point Functions and Scheduling Program Timing Real-time programs require careful timing of the task invocations (either by using an interrupt or a real-time operating system tasking primitive) so that the model code executes to completion before another task invocation occurs. This includes time to read and write data to and from external hardware. The next figure illustrates interrupt timing. Sample interval is appropriate for this model code execution. Time to execute the model code time Time available to process background tasks Sample interval is too short for this model code execution. Time to execute the model code time Task Timing The sample interval must be long enough to allow model code execution between task invocations. In the figure above, the time between two adjacent vertical arrows is the sample interval. The empty boxes in the upper diagram show an example of a program that can complete one step within the interval and still allow time for the background task. The gray box in the lower diagram indicates what happens if the sample interval is too short. Another task invocation occurs before the task is complete. Such timing results in an execution error. Note also that, if the real-time program is designed to run forever (that is, the final time is 0 or infinite so the while loop never exits), then the shutdown code never executes. 8-16 Program Timing For more information on how the timing engine works, see “Timers” on page 1-79. 8-17 8 Entry Point Functions and Scheduling Program Execution As the previous section indicates, a real-time program cannot require 100% of the CPU’s time. This provides an opportunity to run background tasks during the free time. Background tasks include operations such as writing data to a buffer or file, allowing access to program data by third-party data monitoring tools, or using Simulink external mode to update program parameters. It is important, however, that the program be able to preempt the background task so the model code can execute in real time. The way the program manages tasks depends on capabilities of the environment in which it operates. 8-18 External Mode Communication External Mode Communication External mode allows communication between the Simulink block diagram and the standalone program that is built from the generated code. In this mode, the real-time program functions as an interprocess communication server, responding to requests from the Simulink engine. 8-19 8 Entry Point Functions and Scheduling Data Logging in Single-Tasking and Multitasking Model Execution The Simulink Coder data-logging features, described in “Debug” on page 9-80, enable you to save system states, outputs, and time to a MAT-file at the completion of the model execution. The LogTXY function, which performs data logging, operates differently in single-tasking and multitasking environments. If you examine how LogTXY is called in the single-tasking and multitasking environments, you will notice that for single-tasking LogTXY is called after ModelOutputs. During this ModelOutputs call, all blocks that have a hit at time t execute, whereas in multitasking, LogTXY is called after ModelOutputs(tid=0), which executes only the blocks that have a hit at time t and that have a task identifier of 0. This results in differences in the logged values between single-tasking and multitasking logging. Specifically, consider a model with two sample times, the faster sample time having a period of 1.0 second and the slower sample time having a period of 10.0 seconds. At time t = k*10, k=0,1,2... both the fast (tid=0) and slow (tid=1) blocks execute. When executing in multitasking mode, when LogTXY is called, the slow blocks execute, but the previous value is logged, whereas in single-tasking the current value is logged. Another difference occurs when logging data in an enabled subsystem. Consider an enabled subsystem that has a slow signal driving the enable port and fast blocks within the enabled subsystem. In this case, the evaluation of the enable signal occurs in a slow task, and the fast blocks see a delay of one sample period; thus the logged values will show these differences. To summarize differences in logged data between single-tasking and multitasking, differences will be seen when • Any root outport block has a sample time that is slower than the fastest sample time • Any block with states has a sample time that is slower than the fastest sample time • Any block in an enabled subsystem where the signal driving the enable port is slower than the rate of the blocks in the enabled subsystem 8-20 Data Logging in Single-Tasking and Multitasking Model Execution For the first two cases, even though the logged values are different between single-tasking and multitasking, the model results are not different. The only real difference is where (at what point in time) the logging is done. The third (enabled subsystem) case results in a delay that can be seen in a real-time environment. 8-21 8 Entry Point Functions and Scheduling Rapid Prototyping and Embedded Model Execution Differences The rapid prototyping program framework provides a common application programming interface (API) that does not change between model definitions. The Embedded Coder product provides a different framework called the embedded program framework. The embedded program framework provides an optimized API that is tailored to your model. When you use the embedded style of generated code, you are modeling how you would like your code to execute in your embedded system. Therefore, the definitions defined in your model should be specific to your embedded targets. Items such as the model name, parameter, and signal storage class are included as part of the API for the embedded style of code. One major difference between the rapid prototyping and embedded style of generated code is that the latter contains fewer entry-point functions. The embedded style of code can be configured to have only one run-time function, model_step. Thus, when you look again at the model execution pseudocode presented earlier in this chapter, you can eliminate the Loop...EndLoop statements, and group ModelOutputs, LogTXY, and ModelUpdate into a single statement, model_step. For more information about how generated embedded code executes, see “Embedded Model Functions” on page 8-30. 8-22 Rapid Prototyping Model Functions Rapid Prototyping Model Functions The rapid prototyping code defines the following functions that interface with the run-time interface: • Model(): The model registration function. This function initializes the work areas (for example, allocating and setting pointers to various data structures) used by the model. The model registration function calls the MdlInitializeSizes and MdlInitializeSampleTimes functions. These two functions are very similar to the S-function mdlInitializeSizes and mdlInitializeSampleTimes methods. • MdlStart(void): After the model registration functions MdlInitializeSizes and MdlInitializeSampleTimes execute, the run-time interface starts execution by calling MdlStart. This routine is called once at startup. The function MdlStart has four basic sections: - Code to initialize the states for each block in the root model that has states. A subroutine call is made to the “initialize states” routines of conditionally executed subsystems. - Code generated by the one-time initialization (start) function for each block in the model. - Code to enable the blocks in the root model that have enable methods, and the blocks inside triggered or function-call subsystems residing in the root model. Simulink blocks can have enable and disable methods. An enable method is called just before a block starts executing, and the disable method is called just after the block stops executing. - Code for each block in the model that has a constant sample time. • MdlOutputs(int_T tid): MdlOutputs updates the output of blocks. The tid (task identifier) parameter identifies the task that in turn maps when to execute blocks based upon their sample time. This routine is invoked by the run-time interface during major and minor time steps. The major time steps are when the run-time interface is taking an actual time step (that is, it is time to execute a specific task). If your model contains continuous states, the minor time steps will be taken. The minor time steps are when the solver is generating integration stages, which are points between major 8-23 8 Entry Point Functions and Scheduling outputs. These integration stages are used to compute the derivatives used in advancing the continuous states. The solver is called to updates • MdlUpdate(int_T tid): MdlUpdate updates the states and work vector state information (that is, states that are neither continuous nor discrete) saved in work vectors. The tid (task identifier) parameter identifies the task that in turn indicates which sample times are active, allowing you to conditionally update only states of active blocks. This routine is invoked by the run-time interface after the major MdlOutputs has been executed. The solver is also called, and model_Derivatives is called in minor steps by the solver during its integration stages. All blocks that have continuous states have an identical number of derivatives. These blocks are required to compute the derivatives so that the solvers can integrate the states. • MdlTerminate(void): MdlTerminate contains any block shutdown code. MdlTerminate is called by the run-time interface, as part of the termination of the real-time program. The contents of the above functions are directly related to the blocks in your model. A Simulink block can be generalized to the following set of equations. y = f0 (t, xc , xd , u) Output y is a function of continuous state xc, discrete state xd, and input u. Each block writes its specific equation in a section of MdlOutputs. xd +1 = fu (t, xd , u) The discrete states xd are a function of the current state and input. Each block that has a discrete state updates its state in MdlUpdate. x = fd (t, xc , u) The derivatives x are a function of the current input. Each block that has continuous states provides its derivatives to the solver (for example, ode5) in model_Derivatives. The derivatives are used by the solver to integrate the continuous state to produce the next value. The output, y, is generally written to the block I/O structure. Root-level Outport blocks write to the external outputs structure. The continuous and 8-24 Rapid Prototyping Model Functions discrete states are stored in the states structure. The input, u, can originate from another block’s output, which is located in the block I/O structure, an external input (located in the external inputs structure), or a state. These structures are defined in the model.h file that the Simulink Coder software generates. The next example shows the general contents of the rapid prototyping style of C code written to the model.c file. 8-25 8 Entry Point Functions and Scheduling The next figure shows a flow chart describing the execution of the rapid prototyping generated code. 8-26 Rapid Prototyping Model Functions Start Execution MdlStart Execution Loop MdlOutputs MdlUpdate model_Derivatives MdlOutputs model_Derivatives Integration in Minor Time Steps MdlTerminate End Rapid Prototyping Execution Flow Chart Each block places code in specific Mdl routines according to the algorithm that it is implementing. Blocks have input, output, parameters, and states, as well as other general items. For example, in general, block inputs and outputs are written to a block I/O structure (model_B). Block inputs can also come from the external input structure (model_U) or the state structure when connected to a state port of an integrator (model_X), or ground (rtGround) if unconnected or grounded. Block outputs can also go to the external output structure (model_Y). The next figure shows the general mapping between these items. 8-27 8 Entry Point Functions and Scheduling External inputs struct model_U Block I/O struct model_B rtGround Block States struct model_X External outputs struct model_Y Parameter struct model_P Work structs rtRWork, rtIWork, rtPWork, .... Data View of the Generated Code The following list defines the structures shown in the preceding figure: • Block I/O structure (model_B): This structure consists of persistent block output signals. The number of block output signals is the sum of the widths of the data output ports of all nonvirtual blocks in your model. If you activate block I/O optimizations, the Simulink and Simulink Coder products reduce the size of the model_B structure by - Reusing the entries in the model_B structure Making other entries local variables See “Signals” on page 7-52 for more information on these optimizations. Structure field names are determined either by the block’s output signal name (when present) or by the block name and port number when the output signal is left unlabeled. • Block states structures: The continuous states structure (model_X) contains the continuous state information for any blocks in your model that have continuous states. Discrete states are stored in a data structure called the DWork vector (model_DWork). • Block parameters structure (model_P): The parameters structure contains block parameters that can be changed during execution (for example, the parameter of a Gain block). • External inputs structure (model_U): The external inputs structure consists of all root-level Inport block signals. Field names are determined by either 8-28 Rapid Prototyping Model Functions the block’s output signal name, when present, or by the Inport block’s name when the output signal is left unlabeled. • External outputs structure (model_Y): The external outputs structure consists of all root-level Outport blocks. Field names are determined by the root-level Outport block names in your model. • Real work, integer work, and pointer work structures (model_RWork, model_IWork, model_PWork): Blocks might have a need for real, integer, or pointer work areas. For example, the Memory block uses a real work element for each signal. These areas are used to save internal states or similar information. 8-29 8 Entry Point Functions and Scheduling Embedded Model Functions The Embedded Coder target generates the following functions: • model_initialize: Performs model initialization and should be called once before you start executing your model. • If the Single output/update function code generation option is selected, then you see - model_step: Contains the output and update code for all blocks in your model. Otherwise, you see - model_output: Contains the output code for all blocks in your model. model_update: Contains the update code for all blocks in your model. • If the Terminate function required code generation option is selected, then you see - model_terminate: This contains model shutdown code and should be called as part of system shutdown. See “Entry Point Functions and Scheduling” in the Embedded Coder documentation for complete descriptions of these functions. 8-30 Code Generation • Chapter 9, “Configuration” • Chapter 10, “Source Code Generation” • Chapter 11, “Report Generation” 9 Configuration • “Configuring a Model for Code Generation” on page 9-2 • “Application Objectives” on page 9-6 • “Target” on page 9-9 • “Select the Target Language” on page 9-71 • “Code Appearance” on page 9-72 • “Debug” on page 9-80 9 Configuration Configuring a Model for Code Generation In this section... “Code Generation Configuration” on page 9-2 “Open the Model Configuration for Code Generation” on page 9-3 “Configure a Model Programmatically” on page 9-3 Code Generation Configuration When you are ready to generate code for a model, you can modify the model configuration parameters specific to code generation. The code generation parameters affect how the Simulink Coder software generates code and builds an executable from your model. Your application objectives might include a combination of the following code generation objectives: debugging, traceability, execution efficiency, and safety precaution. There are tradeoffs associated with these configuration choices, such as execution speed and memory usage. You can use the Model Advisor and the Code Generation Advisor to help configure any model to achieve your application objectives. For more information, see “Advice About Optimizing Models for Code Generation” on page 16-5 and “Configure Code Generation Objectives Using Code Generation Advisor” on page 9-7. You modify the model configuration parameters for code generation in the Code Generation and Optimization panes of the Configuration Parameters dialog box. The content of the Code Generation pane and its subpanes can change depending on the target that you specify. To open the Code Generation pane, see “Open the Model Configuration for Code Generation” on page 9-3. Some configuration options are available only with the Embedded Coder product. The Optimization pane includes code generation parameters that help to improve the performance of the generated code. To automate the configuration of models, you can use the set_param function from the MATLAB command line to adjust the model configuration parameters. For more information, see “Parameter Command-Line Information Summary” in the Simulink Coder documentation. For an example of automating the configuration of a model, see “Configure a Model Programmatically” on page 9-3. 9-2 Configuring a Model for Code Generation Open the Model Configuration for Code Generation To modify the model configuration parameters for code generation, open the Code Generation pane. There are four ways to open the Code Generation pane from the Simulink editor: • To open the Configuration Parameters dialog box, click the model configuration parameters icon: and select Code Generation. • From the Simulation menu, select Model Configuration Parameters. When the Configuration Parameters dialog box opens, click Code Generation in the Select (left) pane. • From the Code menu, select C/C++ Code > Code Generation Options. • From the View menu in the model window, select Model Explorer, or from the MATLAB command line, type daexplr and press Enter. In the Model Explorer, expand the node for the current model in the left pane and click Configuration (active). The configuration elements are listed in the middle pane. Clicking any of these elements displays the corresponding parameters in the right pane. Alternatively, right-clicking the Code Generation element in the middle pane and choosing Properties from the context menu opens the Code Generation pane in a separate window. Note In a Configuration Parameters dialog box, when you change a check box, menu selection, or edit field, the white background of the element turns to light yellow to indicate that you made an unsaved change. When you click OK, Cancel, or Apply, the background resets to white. For more information on model configurations, see “Configuration Sets”. Configure a Model Programmatically This example shows you how to modify code generation parameters for the active configuration set from the MATLAB command line. Use this approach for creating a script that automates setting parameters for an established 9-3 9 Configuration model configuration. The configuration parameters that you can get and set are listed in “Parameter Command-Line Information Summary” in the Simulink Coder reference. In this example, you modify the configuration parameters to support the Code Generation Advisor application objective, Execution efficiency. Step 1. Open a model. sldemo_f14 Step 2. Get the active configuration set. cs = getActiveConfigSet(model); Step 3. Select the Generic Real-Time (GRT) target. switchTarget(cs,'grt.tlc',[]); Step 4. Modify parameters to optimize execution speed. If your application objective is Execution efficiency, use set_param to modify the following parameters: set_param(cs,'MatFileLogging','off'); set_param(cs,'SupportNonFinite','off'); set_param(cs,'RTWCompilerOptimization','on'); set_param(cs,'OptimizeBlockIOStorage','on'); set_param(cs,'EnhancedBackFolding','on'); set_param(cs,'ConditionallyExecuteInputs','on') set_param(cs,'InlineParams','on'); set_param(cs,'BooleanDataType','on'); set_param(cs,'BlockReduction','on'); set_param(cs,'ExpressionFolding','on'); set_param(cs,'LocalBlockOutputs','on'); set_param(cs,'EfficientFloat2IntCast','on'); set_param(cs,'BufferReuse','on'); Step 5. Save the model configuration to a file. 9-4 Configuring a Model for Code Generation Save the model configuration to a file, `Exec_efficiency_cs.m', and view the parameter settings. saveAs(cs,'Exec_Efficiency_cs'); dbtype Exec_Efficiency_cs 1:50 Using this technique, you can create a script to configure multiple models. An alternative method for configuring multiple models is to save the configuration set to the base workspace. Then, create a configuration reference to point to that configuration set. For more information, see “About Configuration References”. 9-5 9 Configuration Application Objectives In this section... “About Code Generation Objectives” on page 9-6 “Configure Code Generation Objectives Using Code Generation Advisor” on page 9-7 About Code Generation Objectives Depending on the type of application that your model represents, you are likely to have specific code generation objectives in mind. For example, safety and traceability might be more critical than efficient use of memory. If you have specific objectives in mind, you can quickly configure your model to meet those objectives by selecting and prioritizing from the following list of code generation objectives: • Execution efficiency (all targets) • ROM efficiency (ERT-based targets) • RAM efficiency (ERT-based targets) • Safety precaution (ERT-based targets) • Traceability (ERT-based targets) • Debugging (all targets) • MISRA-C:2004 guidelines (ERT-based targets) Based on your objective selections and prioritization, the Code Generation Advisor checks your model and suggests changes that you can make to achieve your code generation objectives. 9-6 Application Objectives Note If you select the MISRA-C:2004 guidelines code generation objective, the Code Generation Advisor checks: • The model configuration settings for compliance with the MISRA-C:2004 configuration setting recommendations. • For blocks that are not supported or recommended for MISRA-C:2004 compliant code generation. Setting code generation objectives and running the Code Generation Advisor provides information on how to meet code generation objectives for your model. The Code Generation Advisor does not alter the generated code. You can use the Code Generation Advisor to make the suggested changes to your model. The generated code is changed only after you modify your model and regenerate code. If you use the Code Generation Advisor to set code generation objectives and check your model, the generated code includes comments identifying which objectives you specified, the checks the Code Generation Advisor ran on the model, and the results of running the checks. For detailed information, see “Application Objectives” in the Embedded Coder documentation. Configure Code Generation Objectives Using Code Generation Advisor To configure the code generation objectives and use the Code Generation Advisor: 1 Open the Configuration Parameters dialog box and select Code Generation. 2 Select or confirm selection of a System target file. 3 Specify the objectives using the Select objectives drop down list (GRT-based targets) or clicking Set objectives button (ERT-based targets). Clicking Set objectives opens the Set Objectives - Code Generation Advisor dialog box. 9-7 9 Configuration 4 Click Check model to run the model checks. The Code Generation Advisor dialog box opens. The Code Generation Advisor uses the code generation objectives to determine which model checks to run. 5 On the left pane, the Code Generation Advisor lists the checks run on the model and the results. Click each warning to see the suggestions for changes that you can make to your model to pass the check. 6 Determine which changes to make to your model. On the right pane of the Code Generation Advisor, follow the instructions listed for each check to modify the model. To run the Code Generation Advisor during code generation, on the Code Generation pane, set the Check model before generating code parameter to either: • On (stop for warnings) - Code generation stops with a check warning. The Code Generation Advisor dialog box opens as described in step 5. • On (proceed with warnings) - Code generation proceeds with check warnings. The Code Generation Advisor interface opens with a list of the checks it ran on the model, along with the results. For more information, see “Set Objectives — Code Generation Advisor Dialog Box” 9-8 Target Target In this section... “Hardware Targets” on page 9-9 “Available Targets” on page 9-10 “About Targets and Code Formats” on page 9-15 “Types of Target Code Formats” on page 9-16 “Targets and Code Formats” on page 9-29 “Targets and Code Styles” on page 9-29 “Backwards Compatibility of Code Formats” on page 9-31 “Selecting a Target” on page 9-34 “Template Makefiles and Make Options” on page 9-38 “Custom Targets” on page 9-44 “Describing the Emulation and Embedded Targets” on page 9-45 “Describing Embedded Hardware Characteristics” on page 9-54 “Describing Emulation Hardware Characteristics” on page 9-55 “Specifying Target Interfaces” on page 9-58 “Selecting and Viewing Code Replacement Libraries” on page 9-61 Hardware Targets When you use Simulink software to create and execute a model, and Simulink Coder software to generate code, you may need to consider up to three platforms, often called hardware targets: • MATLAB Host — The platform that runs MathWorks software during application development • Embedded Target — The platform on which an application will be deployed when it is put into production • Emulation Target — The platform on which an application under development is tested before deployment 9-9 9 Configuration The same platform might serve in two or possibly all three capacities, but they remain conceptually distinct. Often the MATLAB host and the emulation target are the same. The embedded target is usually different from, and less powerful than, the MATLAB host or the emulation target; often it can do little more than run a downloaded executable file. When you use Simulink software to execute a model for which you will later generate code, or use Simulink Coder software to generate code for deployment on an embedded target, you must provide information about the embedded target hardware and the compiler that you will use with it. The Simulink software uses this information to produce bit-true agreement for the results of integer and fixed-point operations performed in simulation and in code generated for the embedded target. The Simulink Coder code generator uses the information to create code that executes with maximum efficiency. When you generate code for testing on an emulation target, you must additionally provide information about the emulation target hardware and the compiler that you will use with it. The code generator uses this information to create code that provides bit-true agreement for the results of integer and fixed-point operations performed in simulation, in code generated for the embedded target, and in code generated for the emulation target. The agreement is possible even though the embedded target and emulation target may use very different hardware, and the compilers for the two targets may use different defaults where the C standard does not completely define behavior. Available Targets The following table lists supported system target files and their associated code formats. The table also gives references to relevant manuals or chapters in this book. All of these targets are built using the make_rtw make command. Note You can select any target of interest using the System Target File Browser. This allows you to experiment with configuration options and save your model with different configurations. However, you cannot build or generate code for non-GRT targets unless you have the required license on your system (Embedded Coder license for ERT, Real-Time Windows Target license for RTWIN, and so on). 9-10 Target Each system target file invokes one or more template makefiles. The template makefile that is invoked activates a particular compiler (for example, Lcc, gcc, or Watcom compilers). This is specified for you by MEXOPTS, which is determined when you run mex -setup to select a compiler for mex. One exception is the Microsoft Visual C++® project target, which has separate System Target File Browser entries. 9-11 9 Configuration Targets Available from the System Target File Browser Target/Code Format System Target File Template Makefile and Comments Embedded Coder (for PC or UNIX3 platforms) ert.tlc ert_shrlib.tlc ert_default_tmf Embedded Coder for Visual C++4 Solution File ert.tlc Embedded Coder for AUTOSAR autosar.tlc ert_default_tmf “Target” (Embedded Coder topic) Generic Real-Time for PC or UNIX platforms grt.tlc grt_default_tmf “Targets and Code Formats” on page 9-29 Generic Real-Time for Visual C++ Solution File grt.tlc Use mex -setup to configure for Lcc, Watcom, vc, gcc, and other compilers RTW.MSVCBuild Creates and builds Visual C++ Solution (.sln) file Use mex -setup to configure for Lcc, Watcom, vc, gcc, and other compilers RTW.MSVCBuild Creates and builds Visual C++ Solution (.sln) file Reference “Target” (Embedded Coder topic) “Target” (Embedded Coder topic) “Targets and Code Formats” on page 9-29 3. UNIX® is a registered trademark of The Open Group in the United States and other countries. 4. Visual C++® is a registered trademark of Microsoft® Corporation. 9-12 Target Targets Available from the System Target File Browser (Continued) Target/Code Format System Target File Template Makefile and Comments Reference Generic Real-Time (dynamic) for PC or UNIX platforms grt_malloc.tlc grt_malloc_default_ tmf “Targets and Code Formats” on page 9-29 Use mex -setup to configure for Lcc, Watcom, vc, gcc, and other compilers Does not support SimStruct. Generic Real-Time (dynamic) for Visual C++ Solution File grt_malloc.tlc Rapid Simulation Target (default for PC or UNIX platforms) rsim.tlc Rapid Simulation Target for LCC compiler rsim.tlc rsim_lcc.tmf “Rapid Simulations” on page 12-2 Rapid Simulation Target for UNIX platforms rsim.tlc rsim_unix.tmf “Rapid Simulations” on page 12-2 Rapid Simulation Target for Visual C++ compiler rsim.tlc rsim_vc.tmf “Rapid Simulations” on page 12-2 Rapid Simulation Target for Watcom compiler rsim.tlc rsim_watc.tmf “Rapid Simulations” on page 12-2 RTW.MSVCBuild Creates and builds Visual C++ Solution (.sln) file rsim_default_tmf Use mex -setup to configure “Targets and Code Formats” on page 9-29 “Rapid Simulations” on page 12-2 9-13 9 Configuration Targets Available from the System Target File Browser (Continued) 9-14 Target/Code Format System Target File Template Makefile and Comments S-Function Target for PC or UNIX platforms rtwsfcn.tlc rtwsfcn_default_tmf S-Function Target for LCC rtwsfcn.tlc rtwsfcn_lcc.tmf “Generated S-Function Block” on page 12-34 S-Function Target for UNIX platforms rtwsfcn.tlc rtwsfcn_unix.tmf “Generated S-Function Block” on page 12-34 S-Function Target for Visual C++ compiler rtwsfcn.tlc rtwsfcn_vc.tmf “Generated S-Function Block” on page 12-34 S-Function Target for Watcom rtwsfcn.tlc rtwsfcn_watc.tmf “Generated S-Function Block” on page 12-34 Tornado (VxWorks) Real-Time Target tornado.tlc tornado.tmf “Asynchronous Support” on page 1-35 ASAM-ASAP2 Data Definition Target asap2.tlc asap2_default_tmf “ASAP2 Data Measurement and Calibration” on page 15-174 Real-Time Windows Target for Open Watcom rtwin.tlc rtwinert.tlc rtwin.tmf rtwinert.tmf “Use Simulink Models” (Real-Time Windows Target topic) xPC Target for Visual C++ or Watcom C/C++ compilers xpctarget.tlc xpc_default_tmf xpctargetert.tlc xpc_ert_tmf xpc_vc.tmf xpc_watc.tmf IDE Link capability idelink_grt.tlc idelink_ert.tlc Use mex -setup to configure N/A Reference “Generated S-Function Block” on page 12-34 “xPC Target Options Configuration Parameter” (xPC Target topic) Desktop IDE/target topics such as “Model Setup” on page 25-2; Embedded IDE/target topics such as “Model Setup” (Embedded Coder topic) Target Targets Supporting Nonzero Start Time When you try to build models with a nonzero start time, if the selected target does not support a nonzero start time, the Simulink Coder software does not generate code and displays an error message. The Rapid Simulation (RSim) target supports a nonzero start time when the RSim Target > Solver selection parameter in the Configuration Parameters dialog box is set to Use Simulink solver module. The other listed targets do not support a nonzero start time. About Targets and Code Formats A target (such as the GRT target) is an environment for generating and building code intended for execution on a certain hardware or operating system platform. A target is defined at the top level by a system target file, which in turn invokes other target-specific files. A code format (such as embedded or real-time) is one property of a target. The code format controls decisions made at several points in the code generation process. These include whether and how certain data structures are generated (for example, SimStruct or rtModel), whether or not static or dynamic memory allocation code is generated, and the calling interface used for generated model functions. In general, the Embedded-C code format is more efficient than the RealTime code format. Embedded-C code format provides more compact data structures, a simpler calling interface, and static memory allocation. These characteristics make the Embedded-C code format the preferred choice for production code generation. In prior releases, only the ERT target and targets derived from the ERT target used the Embedded-C code format. Non-ERT targets used other code formats (for example, RealTime or RealTimeMalloc). In Release 14, the GRT target uses the Embedded-C code format for back end code generation. This includes generation of both algorithmic model code and supervisory timing and task scheduling code. The GRT target (and derived targets) generates a RealTime code format wrapper around the Embedded-C code. This wrapper provides a calling interface that is backward compatible with existing GRT-based custom targets. The wrapper calls are compatible with the main program module of the GRT target (grt_main.c or grt_main.cpp). This use of wrapper calls incurs some calling overhead; 9-15 9 Configuration the pure Embedded-C calling interface generated by the ERT target is more highly optimized. For a description of the calling interface generated by the ERT target, see “Entry Point Functions and Scheduling”. Code format unification simplifies the conversion of GRT-based custom targets to ERT-based targets. See “Making Pre-R2012a Custom GRT-Based Targets ERT-Compatible” on page 9-26 for a discussion of target conversion issues. Types of Target Code Formats • “Real-Time Code Format” on page 9-20 • “Real-Time malloc Code Format” on page 9-21 • “S-Function Code Format” on page 9-23 • “Embedded Code Format” on page 9-23 Your choice of code format is the most important code generation option. The code format specifies the overall framework of the generated code and determines its style. When you choose a target, you implicitly choose a code format. Typically, the system target file will specify the code format by assigning the TLC variable CodeFormat. The following example is from ert.tlc. %assign CodeFormat = "Embedded-C" If the system target file does not assign CodeFormat, the default is RealTime (as in grt.tlc). If you are developing a custom target, you must consider which code format is best for your application and assign CodeFormat accordingly. Choose the RealTime or RealTime malloc code format for rapid prototyping. If your application does not have significant restrictions in code size, memory usage, or stack usage, you might want to continue using the generic real-time (GRT) target throughout development. 9-16 Target For production deployment, and when your application demands that you limit source code size, memory usage, or maintain a simple call structure, you should use the Embedded-C code format. Consider using the Embedded Coder product, if you need added flexibility to configure and optimize code. Finally, you should choose the Model Reference or the S-function formats if you are not concerned about RAM and ROM usage and want to • Use a model as a component, for scalability • Create a proprietary S-function MEX-file object • Interface the generated code using the S-function C API • Speed up your simulation The following table summarizes how different targets support applications: Application Targets Fixed- or variable-step acceleration RSIM, S-Function, Model Reference Fixed-step real-time deployment GRT, GRT-Malloc, ERT, xPC Target, Wind River Systems Tornado, Real-Time Windows Target, Texas Instruments™ DSP, ... The following table summarizes the various options available for each Simulink Coder code format/target, with the exceptions noted. 9-17 9 Configuration Features Supported by Simulink Coder Targets and Code Formats Feature Static memory allocation Wind River Systems RealERT time Shared VxWorks GRT malloc ERT Library /Tornado X X X Dynamic memory allocation RT RSIM Win xPC X X X X X X Other Supported Targets1 X X Continuous time X X X X X X X X C/C++ MEX S-functions (noninlined) X X X X X X X X S-function (inlined) X X X X X X X X X X X2 X2 X X X Minimize RAM/ROM usage Supports external mode X X Rapid prototyping X X Production code 9-18 SFunc X X X2 X X X X X X X2 X3 Target Features Supported by Simulink Coder Targets and Code Formats (Continued) Feature Wind River Systems RealERT time Shared VxWorks GRT malloc ERT Library /Tornado Batch parameter tuning and Monte Carlo methods X System-level Simulator X X4 X4 X4 Non-real-time X executable included X X Multiple instances of model X6 Executes in hard real time X6, SFunc RT RSIM Win xPC X X X X6 X X5 X2, 6, X2, 6, 7 7 X Supports SIL/PIL X X 7 Supports variable-step solvers Other Supported Targets1 X X 1 The Embedded Targets capabilities in Simulink Coder support other targets. 2 Does not apply to GRT based targets. Applies only to an ERT based target. 9-19 9 Configuration The default GRT, GRT malloc, and ERT rt_main files emulate execution of hard real time, and when explicitly connected to a real-time clock execute in hard real time. 4 You can generate code for multiple instances of a Stateflow chart or subsystem containing a chart, except when the chart contains exported graphical functions or the Stateflow model contains machine parented events. 6 You must enable Generate reusable code in the Code Generation > Interface pane of the Configuration Parameters dialog box. 7 Real-Time Code Format • “About Real-Time Code Format” on page 9-20 • “Unsupported Blocks” on page 9-20 • “System Target Files” on page 9-21 • “Template Makefiles” on page 9-21 About Real-Time Code Format. The real-time code format (corresponding to the generic real-time target) is useful for rapid prototyping applications. If you want to generate real-time code while iterating model parameters rapidly, you should begin the design process with the generic real-time target. The real-time code format supports: • Continuous time • Continuous states • C/C++ MEX S-functions (inlined and noninlined) For more information on inlining S-functions, see “Insert S-Function Code” on page 14-46 and “Inlining S-Functions”. The real-time code format declares memory statically, that is, at compile time. Unsupported Blocks. The real-time format does not support the following built-in user-defined blocks: • Interpreted MATLAB Function block (note that Fcn blocks are supported) 9-20 Target • S-Function block — MATLAB language S-functions, Fortran S-functions, or C/C++ MEX S-functions that call into the MATLAB environment (Fcn block calls are supported) System Target Files. • grt.tlc - Generic Real-Time Target • rsim.tlc - Rapid Simulation Target • tornado.tlc - Tornado (VxWorks) Real-Time Target Template Makefiles. • grt - grt_lcc.tmf — Lcc compiler grt_unix.tmf — The Open Group UNIX host grt_vc.tmf — Microsoft Visual C++ grt_watc.tmf — Watcom C • rsim - rsim_lcc.tmf — Lcc compiler rsim_unix.tmf — UNIX host rsim_vc.tmf — Visual C++ rsim_watc.tmf — Watcom C • tornado.tmf • win_watc.tmf Real-Time malloc Code Format • “About Real-Time malloc Code Format” on page 9-22 • “Unsupported Blocks” on page 9-22 • “System Target Files” on page 9-22 • “Template Makefiles” on page 9-23 9-21 9 Configuration About Real-Time malloc Code Format. The real-time malloc code format (corresponding to the generic real-time malloc target) is very similar to the real-time code format. The differences are • Real-time malloc declares memory dynamically. For MathWorks blocks, malloc calls are limited to the model initialization code. Generated code is designed to be free from memory leaks, provided that the model termination function is called. • Real-time malloc allows you to deploy multiple instances of the same model with each instance maintaining its own unique data. • Real-time malloc allows you to combine multiple models together in one executable. For example, to integrate two models into one larger executable, real-time malloc maintains a unique instance of each of the two models. If you do not use the real-time malloc format, the Simulink Coder code generator will not necessarily create uniquely named data structures for each model, potentially resulting in name clashes. grt_malloc_main.c (or .cpp), the main routine for the generic real-time malloc (grt_malloc) target, supports one model by default. See “Use GRT Malloc to Combine Models” on page 4-4 for information on modifying grt_malloc_main.c (or .cpp) to support multiple models. grt_malloc_main.c and grt_malloc_main.cpp are located in the folder matlabroot/rtw/c/grt_malloc. Unsupported Blocks. The real-time malloc format does not support the following built-in blocks, as shown: • Functions & Tables - Interpreted MATLAB Function block (note that Fcn blocks are supported) - S-Function block — MATLAB language S-functions, Fortran S-functions, or C/C++ MEX S-functions that call into the MATLAB environment (Fcn block calls are supported) System Target Files. • grt_malloc.tlc - Generic Real-Time Target with dynamic memory allocation 9-22 Target • tornado.tlc - Tornado (VxWorks) Real-Time Target Template Makefiles. • grt_malloc - grt_malloc_lcc.tmf — Lcc compiler grt_malloc_unix.tmf — The Open Group UNIX host grt_malloc_vc.tmf — Microsoft Visual C++ grt_malloc_watc.tmf — Watcom C • tornado.tmf S-Function Code Format The S-function code format (corresponding to the S-function target) generates code that conforms to the Simulink MEX S-function API. Using the S-function target, you can build an S-function component and use it as an S-Function block in another model. The S-function code format is also used by the accelerated simulation target to create the Accelerator MEX-file. In general, you should not use the S-function code format in a system target file. However, you might need to do special handling in your inlined TLC files to account for this format. You can check the TLC variable CodeFormat to see if the current target is a MEX-file. If CodeFormat = "S-Function" and the TLC variable Accelerator is set to 1, the target is an accelerated simulation MEX-file. See “Generated S-Function Block” on page 12-34, for more information. Embedded Code Format • “About Embedded Code Format” on page 9-24 • “Using the Real-Time Model Data Structure” on page 9-24 • “Making Pre-R2012a Custom GRT-Based Targets ERT-Compatible” on page 9-26 9-23 9 Configuration • “Converting Your Target to Use rtModel” on page 9-27 • “Generating Pre-R2012a GRT Wrapper Code” on page 9-29 About Embedded Code Format. The Embedded-C code format corresponds to the Embedded Coder target (ERT), and targets derived from ERT. This code format includes a number of memory-saving and performance optimizations. See the Embedded Coder “Product Description” and configuration topics such as “Application Objectives”, “Target”, and “Code Appearance” for details. Using the Real-Time Model Data Structure. The Embedded-C format uses the real-time model (RT_MODEL) data structure. This structure is also referred to as the rtModel data structure. You can access rtModel data by using a set of macros analogous to the ssSetxxx and ssGetxxx macros that S-functions use to access SimStruct data, including noninlined S-functions compiled by the Simulink Coder code generator. You need to use the set of macros rtmGetxxx and rtmSetxxx to access the real-time model data structure, which is specific to the Simulink Coder product. The rtModel is an optimized data structure that replaces SimStruct as the top level data structure for a model. The rtmGetxxx and rtmSetxxx macros are used in the generated code as well as from the main.c or main.cpp module. If you are customizing main.c or main.cpp (either a static file or a generated file), you need to use rtmGetxxx and rtmSetxxx instead of the ssSetxxx and ssGetxxx macros. Usage of rtmGetxxx and rtmSetxxx macros is the same as for the ssSetxxx and ssGetxxx versions, except that you replace SimStruct S by real-time model data structure rtM. The following table lists rtmGetxxx and rtmSetxxx macros that are used in grt_main.c, grt_main.cpp, grt_malloc_main.c, and grt_malloc_main.cpp. Macros for Accessing the Real-Time Model Data Structure 9-24 rtm Macro Syntax Description rtmGetdX(rtm) Get the derivatives of a block’s continuous states rtmGetOffsetTimePtr(RT_MDL rtM) Return the pointer of vector that stores sample time offsets of the model associated with rtM Target Macros for Accessing the Real-Time Model Data Structure (Continued) rtm Macro Syntax Description rtmGetNumSampleTimes(RT_MDL rtM) Get the number of sample times that a block has rtmGetPerTaskSampleHitsPtr(RT_MDL) Return a pointer of NumSampleTime × NumSampleTime matrix rtmGetRTWExtModeInfo(RT_MDL rtM) Return an external mode information data structure of the model. This data structure is used internally for external mode. rtmGetRTWLogInfo(RT_MDL) Return a data structure used by Simulink Coder logging. Internal use. rtmGetRTWRTModelMethodsInfo(RT_MDL) Return a data structure of Simulink Coder real-time model methods information. Internal use. rtmGetRTWSolverInfo(RT_MDL) Return data structure containing solver information of the model. Internal use. rtmGetSampleHitPtr(RT_MDL) Return a pointer of Sample Hit flag vector rtmGetSampleTime(RT_MDL rtM, int TID) Get a task’s sample time rtmGetSampleTimePtr(RT_MDL rtM) Get pointer to a task’s sample time rtmGetSampleTimeTaskIDPtr(RT_MDL rtM) Get pointer to a task’s ID rtmGetSimTimeStep(RT_MDL) Return simulation step type ID (MINOR_TIME_STEP, MAJOR_TIME_STEP) rtmGetStepSize(RT_MDL) Return the fundamental step size of the model rtmGetT(RT_MDL,t) Get the current simulation time rtmSetT(RT_MDL,t) Set the time of the next sample hit rtmGetTaskTime(RT_MDL,tid) Get the current time for the current task rtmGetTFinal(RT_MDL) Get the simulation stop time rtmSetTFinal(RT_MDL,finalT) Set the simulation stop time rtmGetTimingData(RT_MDL) Return a data structure used by timing engine of the model. Internal use. 9-25 9 Configuration Macros for Accessing the Real-Time Model Data Structure (Continued) rtm Macro Syntax Description rtmGetTPtr(RT_MDL) Return a pointer of the current time rtmGetTStart(RT_MDL) Get the simulation start time rtmIsContinuousTask(rtm) Determine whether a task is continuous rtmIsMajorTimeStep(rtm) Determine whether the simulation is in a major step rtmIsSampleHit(RT_MDL,tid) Determine whether the sample time is hit For additional details on usage, see “SimStruct Macros and Functions Listed by Usage”. Making Pre-R2012a Custom GRT-Based Targets ERT-Compatible. If you developed a GRT-based custom target in a release before R2012a, it is simple to make your target ERT compatible. By doing so, you can take advantage of many efficiencies. There are several approaches to ERT compatibility: • If your installation does not include an Embedded Coder license, you can convert a GRT-based target as described in “Converting Your Target to Use rtModel” on page 9-27. This enables your custom target to support current GRT features, including back end Embedded-C code generation. • If your installation includes an Embedded Coder license, you can do either of the following: 9-26 - Create an ERT-based target, but continue to use your customized version of grt_main.c or grt_main.cpp module. To do this, you can configure the ERT target to generate a pre-R2012a GRT calling interface, as described in “Generating Pre-R2012a GRT Wrapper Code” on page 9-29. This lets your target support the full ERT feature set, without changing your GRT-based run-time interface. - Reimplement your custom target as a completely ERT-based target, including use of an ERT generated main program. This approach lets Target your target support the full ERT feature set, without the overhead caused by wrapper calls. Note If you intend to use custom storage classes (CSCs) with a custom target, you must use an ERT-based target. See “Custom Storage Classes” in the Embedded Coder documentation for detailed information on CSCs. For details on how GRT targets are made call-compatible with previous Simulink Coder product versions, see “Using the Real-Time Model Data Structure” on page 9-24. Converting Your Target to Use rtModel. The real-time model data structure (rtModel) encapsulates model-specific information in a much more compact form than the SimStruct. Many ERT-related efficiencies depend on generation of rtModel rather than SimStruct, including • Integer absolute and elapsed timing services • Independent timers for asynchronous tasks • Generation of improved C API code for signal, state, and parameter monitoring • Pruning the data structure to minimize its size (ERT-derived targets only) To take advantage of such efficiencies, you must update your GRT-based target to use the rtModel (unless you already did so for Release 13). The conversion requires changes to your system target file, template makefile, and main program module. The following changes to the system target file and template makefile are required to use rtModel instead of SimStruct: • In the system target file, add the following global variable assignment: %assign GenRTModel = TLC_TRUE • In the template makefile, define the symbol USE_RTMODEL. See one of the GRT template makefiles for an example. 9-27 9 Configuration The following changes to your main program module (that is, your customized version of grt_main.c or grt_main.cpp) are required to use rtModel instead of SimStruct: • Include rtmodel.h instead of simstruc.h. • Since the rtModel data structure has a type that includes the model name, define the following macros at the top of the main program file: #define EXPAND_CONCAT(name1,name2) name1 ## name2 #define CONCAT(name1,name2) EXPAND_CONCAT(name1,name2) #define RT_MODEL CONCAT(MODEL,_rtModel) • Change the extern declaration for the function that creates and initializes the SimStruct to extern RT_MODEL *MODEL(void); • Change the definitions of rt_CreateIntegrationData and rt_UpdateContinuousStates to be as shown in the Release 14 version of grt_main.c. • Change function prototypes to have the argument 'RT_MODEL' instead of the argument 'SimStruct'. • The prototypes for the functions rt_GetNextSampleHit, rt_UpdateDiscreteTaskSampleHits, rt_UpdateContinuousStates, rt_UpdateDiscreteEvents, rt_UpdateDiscreteTaskTime, and rt_InitTimingEngine have changed. Change their names to use the prefix rt_Sim instead of rt_ and then change the arguments you pass in to them. See the Release 14 version of grt_main.c for the list of arguments passed in to each function. • Modify all macros that refer to the SimStruct to now refer to the rtModel. SimStruct macros begin with the prefix ss, whereas rtModel macros begin with the prefix rtm. For example, change ssGetErrorStatus to rtmGetErrorStatus. 9-28 Target Generating Pre-R2012a GRT Wrapper Code. The Simulink Coder product supports the “Classic call interface” model option. When this option is selected, the Simulink Coder product generates model function calls that are compatible with the main program module of the pre-R2012a GRT target (grt_main.c or grt_main.cpp). These calls act as wrappers that interface to code generated with R2012a or higher. This option provides a quick way to use code generated with R2012a or higher with a main program module based on pre-R2012a grt_main.c or grt_main.cpp. Targets and Code Formats The Simulink Coder product provides five different code formats. Each code format specifies a framework for code generation suited for specific applications. The five code formats and corresponding application areas are • Real-time — Rapid prototyping • Real-time malloc — Rapid prototyping • S-function — Creating proprietary S-function MEX-file objects, code reuse, and speeding up your simulation • Model reference — Creating MEX-file objects from entire models that other models can use, sometimes in place of S-functions • Embedded C — Deeply embedded systems This chapter discusses the relationship of code formats to the available target configurations, and factors you should consider when choosing a code format and target. This chapter also summarizes the real-time, real-time malloc, S-function, model referencing, and embedded C/C++ code formats. Targets and Code Styles The Simulink Coder software generates two styles of code. One code style is suitable for rapid prototyping (and simulation by using code generation). The other style is suitable for embedded applications. This chapter discusses the program architecture, that is, the structure of code generated by the Simulink Coder code generator, associated with these two styles of code. The next table classifies the targets shipped with the product. For related details about 9-29 9 Configuration code style and target characteristics, see “Types of Target Code Formats” on page 9-16. Code Styles Listed by Target Target Code Style (Using C or C++ Unless Noted) Embedded Coder embedded real-time (ERT) target Embedded — Useful as a starting point when using generated C/C++ code in an embedded application (often referred to as a production code target). Simulink Coder Generic real-time (GRT) target Rapid prototyping — Use as a starting point for creating a rapid prototyping target that does not use real-time operating system tasking primitives, and for verifying the generated code on your workstation. Uses components of ERT, with a different calling interface. Real-time malloc target Rapid prototyping — Similar to the generic real-time (GRT) target except that this target allocates model working memory dynamically rather than statically declaring it in advance. Rapid simulation target (RSim) Rapid prototyping — Non-real-time simulation of your model on your workstation. Useful as a high-speed or batch simulation tool. S-function target Rapid prototyping — Creates a C MEX S-function for simulation of your model within another Simulink model. Tornado (VxWorks) real-time target5 Rapid prototyping — Runs model in real time using the VxWorks real-time operating system tasking primitives. Also useful as a starting point for targeting a real-time operating system. 5. Tornado® and VxWorks® are registered trademarks of Wind River® Systems, Inc. 9-30 Target Code Styles Listed by Target (Continued) Target Code Style (Using C or C++ Unless Noted) Real-Time Windows Target Rapid prototyping — Runs model in real time at interrupt level while your PC is running a Microsoft Windows environment in the background. xPC Target Rapid prototyping — Runs model in real time on target PC running the xPC Target kernel. Third-party vendors supply additional targets for the Simulink Coder product. Generally, these can be classified as rapid prototyping targets. For more information about third-party products, see the MathWorks Connections Program Web page: http://www.mathworks.com/products/connections. This chapter is divided into three sections. The first section discusses model execution, the second section discusses the rapid prototyping style of code, and the third section discusses the embedded style of code. Backwards Compatibility of Code Formats Because GRT targets now use Embedded-C code format, existing applications that depend on the RealTime code format’s calling interface could have compatibility issues. To address this, a set of macros is generated (in model.h) that maps Embedded-C data structures to the identifiers that RealTime code format used. The following, which can be found in any model.h file created for a GRT target, describes these identifier mappings: /* Backward compatible GRT Identifiers */ model_B #define rtB #define BlockIO BlockIO_model #define rtXdot model_Xdot #define StateDerivatives StateDerivatives_model #define tXdis model_Xdis #define StateDisabled StateDisabled_model #define rtY model_Y #define ExternalOutputs ExternalOutputs_model #define rtP model_P #define Parameters Parameters_model 9-31 9 Configuration Since the GRT target now uses the Embedded-C code format for back end code generation, many Embedded-C optimizations are available to all Simulink Coder users. In general, the GRT and ERT targets now have many more common features, but the ERT target offers additional controls for common features. The availability of features is now determined by licensing, rather than being tied to code format. The following table compares features available with a Simulink Coder license with those available under an Embedded Coder license: Comparison of Features Licensed with the Simulink Coder Product Versus the Embedded Coder Product Feature Simulink Coder License Embedded Coder License rtModel data • Full rtModel structure generated • rtModel is optimized for the model • GRT variable declaration: • Optional suppression of error status field and data logging fields structure rtModel_model model_M_; • ERT variable declaration: RT_MODEL_model model_M_; 9-32 Custom storage classes (CSCs) Code generation ignores CSCs; objects are assigned a CSC default to Auto storage class Code generation with CSCs is supported HTML code generation report Basic HTML code generation report Enhanced report with additional detail and hyperlinks to the model Symbol formatting Symbols (for signals, parameters and so on) are generated in accordance with hard-coded default Detailed control over generated symbols. User-defined maximum identifier length for generated symbols Supported Supported Generation of terminate function Always generated Option to suppress terminate function Target Comparison of Features Licensed with the Simulink Coder Product Versus the Embedded Coder Product (Continued) Feature Simulink Coder License Embedded Coder License Combined output/update function Separate output/update functions are generated Option to generate combined output/update function Optimized data initialization Not available Options to suppress generation of unnecessary initialization code for zero-valued memory, I/O ports, and so on Comments generation Basic options to include or suppress comment generation Options to include Simulink block descriptions, Stateflow object descriptions, and Simulink data object descriptions in comments Module Packaging Features (MPF) Not supported Extensive code customization features (see Embedded Coder topics such as “Data Types”, “User-Defined Data Types”, and “Custom Storage Classes”.) Target-optimized data types header file Requires full tmwtypes.h header file Generates optimized rtwtypes.h header file, including definitions required by the target User-defined types User-defined types default to base types in code generation User defined data type aliases are supported in code generation Rate grouping Not supported Supported Auto-generation of main program module Not supported; static main program module is provided. Automated and customizable generation of main program module is supported (static main program also available) Reusable (multi-instance) code generation with static memory allocation Not supported Option to generate reusable code 9-33 9 Configuration Comparison of Features Licensed with the Simulink Coder Product Versus the Embedded Coder Product (Continued) Feature Simulink Coder License Embedded Coder License Software constraint options Support for floating point, complex, and nonfinite numbers is always enabled Options to enable or disable support for floating-point, complex, and nonfinite numbers Application life span Defaults to inf User-specified; determines most efficient word size for integer timers Software-in-the-loop (SIL) testing Model reference simulation target can be used for SIL testing Additional SIL testing support by using auto-generation of SIL block ANSI6-C/C++ code generation Supported Supported ISO®7-C/C++ code generation Supported Supported GNU®8-C/C++ code generation Supported Supported Generate scalar inlined parameters as #DEFINE statements Not supported Supported MAT-file variable name modifier Supported Supported Data exchange: C API, external mode, ASAP2 Supported Supported Selecting a Target The first step to configuring a model for Simulink Coder code generation is to choose and configure a code generation target. When you select a target, 6. ANSI® is a registered trademark of the American National Standards Institute, Inc. 7. ISO® is a registered trademark of the International Organization for Standardization. 8. GNU® is a registered trademark of the Free Software Foundation. 9-34 Target other model configuration parameters change automatically to best serve requirements of the target. For example: • Code interface parameters • Build process parameters, such as the template make file • Target hardware parameters, such as word size and byte ordering Use the Browse button on the Code Generation pane to open the System Target File Browser. The browser lets you select a preset target configuration consisting of a system target file, template makefile, and make command. For a complete list of available target configurations, see “Available Targets” on page 9-10. If you select a target configuration by using the System Target File Browser, your selection appears in the System target file field (target.tlc). If you are using a target configuration that does not appear in the System Target File Browser, enter the name of your system target file in the System target file field. Click Apply or OK to configure for that target. You also can select a target programmatically from MATLAB code, as described in “Selecting a System Target File Programmatically” on page 9-37. After selecting a target, you can modify model configuration parameter settings. If you want to switch between different targets in a single workflow for different code generation purposes (for example, rapid prototyping versus product code deployment), set up different configuration sets for the same model and switch the active configuration set for the current operation. For more information on how to set up configuration sets and change the active configuration set, see “Manage a Configuration Set” in the Simulink documentation. To select a target configuration using the System Target File Browser, 1 Open the Code Generation pane of the Configuration Parameters dialog box. 9-35 9 Configuration 2 Click the Browse button next to the System target file field. This opens the System Target File Browser. The browser displays a list of currently available target configurations, including customizations. When you select a target configuration, the Simulink Coder software automatically chooses the system target file, template makefile, and make command for that configuration. The next step shows the System Target File Browser with the generic real-time target selected. 3 Click the desired entry in the list of available configurations. The background of the list box turns yellow to indicate an unapplied choice has been made. To apply it, click Apply or OK. System Target File Browser When you choose a target configuration, the Simulink Coder software automatically chooses the system target file, template makefile, and make command for that configuration, and displays them in the System target file field. The description of the target file from the browser is placed below its name in the Code Generation pane. 9-36 Target Selecting a System Target File Programmatically Simulink models store model-wide parameters and target-specific data in configuration sets. Every configuration set contains a component that defines the structure of a particular target and the current values of target options. Some of this information is loaded from a system target file when you select a target using the System Target File Browser. You can configure models to generate alternative target code by copying and modifying old or adding new configuration sets and browsing to select a new target. Subsequently, you can interactively select an active configuration from among these sets (only one configuration set can be active at a given time). Scripts that automate target selection need to emulate this process. To program target selection 1 Obtain a handle to the active configuration set with a call to the getActiveConfigSet function. 2 Define string variables that correspond to the required Simulink Coder system target file, template makefile, and make command settings. For example, for the ERT target, you would define variables for the strings 'ert.tlc', 'ert_default_tmf', and 'make_rtw'. 3 Select the system target file with a call to the switchTarget function. In the function call, specify the handle for the active configuration set and the system target file. 4 Set the TemplateMakefile and MakeCommand configuration parameters to the corresponding variables created in step 2. For example: cs = getActiveConfigSet(model); stf = 'ert.tlc'; tmf = 'ert_default_tmf'; mc = 'make_rtw'; switchTarget(cs,stf,[]); set_param(cs,'TemplateMakefile',tmf); set_param(cs,'MakeCommand',mc); 9-37 9 Configuration Template Makefiles and Make Options The Simulink Coder product includes a set of built-in template makefiles that are designed to build programs for specific targets. There are two types of template makefiles: • Compiler-specific template makefiles are designed for use with a particular compiler or development system. By convention, compiler-specific template makefiles are named according to the target and compiler (or development system). For example, grt_vc.tmf is the template makefile for building a generic real-time program under the Visual C++ compiler; ert_lcc.tmf is the template makefile for building an Embedded Coder program under the Lcc compiler. • Default template makefiles make your model designs more portable, by choosing the compiler-specific makefile and compiler for your installation. “Choose and Configure a Compiler” on page 15-2 describes the operation of default template makefiles in detail. Default template makefiles are named target_default_tmf. They are MATLAB language files that, when run, select the TMF for the specified target configuration. For example, grt_default_tmf is the default template makefile for building a generic real-time program; ert_default_tmf is the default template makefile for building an Embedded Coder program. You can supply options to makefiles by using arguments to the Make command field in the Code Generation pane of the Configuration Parameters dialog box. Append the arguments after make_rtw (or make_xpc or other make command), as in the following example: make_rtw OPTS="-DMYDEFINE=1" The syntax for make command options differs slightly for different compilers. Complete details on the structure of template makefiles are provided in the Embedded Coder documentation. This information is provided for those who want to customize template makefiles. This section describes compiler-specific template makefiles and common options you can use with each. 9-38 Target Note To control compiler optimizations for your Simulink Coder makefile build at the Simulink GUI level, use the Compiler optimization level option on the Code Generation pane of the Configuration Parameters dialog box. The Compiler optimization level option provides • Target-independent values Optimizations on (faster runs) and Optimizations off (faster builds), which allow you to easily toggle compiler optimizations on and off during code development • The value Custom for entering custom compiler optimization flags at Simulink GUI level (rather than at other levels of the build process) If you specify compiler options for your Simulink Coder makefile build using OPT_OPTS, MEX_OPTS (except MEX_OPTS="-v"), or MEX_OPT_FILE, the value of Compiler optimization level is ignored and a warning is issued about the ignored parameter. Template Makefiles for UNIX Platforms The template makefiles for UNIX platforms are designed to be used with the Free Software Foundation’s GNU Make. These makefile are set up to conform to the guidelines specified in the IEEE®9 Std 1003.2-1992 (POSIX) standard. • ert_unix.tmf • grt_malloc_unix.tmf • grt_unix.tmf • rsim_unix.tmf • rtwsfcn_unix.tmf You can supply options by using arguments to the make command. • OPTS — User-specific options, for example, make_rtw OPTS="-DMYDEFINE=1" 9. IEEE® is a registered trademark of The Institute of Electrical and Electronics Engineers, Inc. 9-39 9 Configuration • OPT_OPTS— Optimization options. Default is -O. To enable debugging specify as OPT_OPTS=-g. Because of optimization problems in IBM_RS, the default is no optimization. • CPP_OPTS — C++ compiler options. • USER_SRCS — Additional user sources, such as files used by S-functions. • USER_INCLUDES — Additional include paths, for example, USER_INCLUDES="-Iwhere-ever -Iwhere-ever2" These options are also documented in the comments at the head of the respective template makefiles. Template Makefiles for the Microsoft Visual C++ Compiler The Simulink Coder product offers two sets of template makefiles designed for use with the Visual C++ compiler. To build an executable within the Simulink Coder build process, use one of the target_vc.tmf template makefiles: • ert_vc.tmf • grt_malloc_vc.tmf • grt_vc.tmf • rsim_vc.tmf • rtwsfcn_vc.tmf You can supply options by using arguments to the make command. • OPT_OPTS — Optimization option. Default is -O2. To enable debugging specify as OPT_OPTS=-Zi. • OPTS — User-specific options. • CPP_OPTS — C++ compiler options. • USER_SRCS — Additional user sources, such as files used by S-functions. • USER_INCLUDES — Additional include paths, for example, 9-40 Target USER_INCLUDES="-Iwhere-ever -Iwhere-ever2" These options are also documented in the comments at the head of the respective template makefiles. Visual C++ Code Generation Only. To create a Visual C++ project makefile (model.mak) without building an executable, use one of the target_msvc.tmf template makefiles: • ert_msvc.tmf • grt_malloc_msvc.tmf • grt_msvc.tmf These template makefiles are designed to be used with nmake, which is bundled with the Visual C++ compiler. You can supply the following options by using arguments to the nmake command: • OPTS — User-specific options, for example, make_rtw OPTS="/D MYDEFINE=1" • USER_SRCS — Additional user sources, such as files used by S-functions. • USER_INCLUDES — Additional include paths, for example, USER_INCLUDES="-Iwhere-ever -Iwhere-ever2" These options are also documented in the comments at the head of the respective template makefiles. Template Makefiles for the Watcom C/C++ Compiler The Simulink Coder product provides template makefiles to create an executable for the Microsoft Windows platform using Watcom C/C++. These template makefiles are designed to be used with wmake, which is bundled with Watcom C/C++. 9-41 9 Configuration Note The Watcom C compiler is no longer available from the manufacturer. However, the Simulink Coder product continues to ship with Watcom-related template makefiles. • ert_watc.tmf • grt_malloc_watc.tmf • grt_watc.tmf • rsim_watc.tmf • rtwsfcn_watc.tmf You can supply options by using arguments to the make command. Note that the location of the quotes is different from the other compilers and make utilities discussed in this chapter. • OPTS — User-specific options, for example, make_rtw "OPTS=-DMYDEFINE=1" • OPT_OPTS — Optimization options. The default optimization option is -oxat. To turn off optimization and add debugging symbols, specify the -d2 compiler switch in the make command, for example, make_rtw "OPT_OPTS=-d2" • CPP_OPTS — C++ compiler options. • USER_OBJS — Additional user objects, such as files used by S-functions. • USER_PATH — The folder path to the source (.c or .cpp) files that are used to create any .obj files specified in USER_OBJS. Multiple paths must be separated with a semicolon. For example, USER_PATH="path1;path2" • USER_INCLUDES — Additional include paths, for example, USER_INCLUDES="-Iinclude-path1 -Iinclude-path2" 9-42 Target These options are also documented in the comments at the head of the respective template makefiles. Template Makefiles for the LCC Compiler The Simulink Coder product provides template makefiles to create an executable for the Windows platform using Lcc compiler Version 2.4 and GNU Make (gmake). • ert_lcc.tmf • grt_lcc.tmf • grt_malloc_lcc.tmf • rsim_lcc.tmf • rtwsfcn_lcc.tmf You can supply options by using arguments to the make command: • OPTS — User-specific options, for example, make_rtw OPTS="-DMYDEFINE=1" • OPT_OPTS — Optimization options. Default is none. To enable debugging, specify -g4 in the make command: make_rtw OPT_OPTS="-g4" • CPP_OPTS — C++ compiler options. • USER_SRCS — Additional user sources, such as files used by S-functions. • USER_INCLUDES — Additional include paths, for example, USER_INCLUDES="-Iwhere-ever -Iwhere-ever2" For Lcc, have a / as file separator before the filename instead of a \, for example, d:\work\proj1/myfile.c. These options are also documented in the comments at the head of the respective template makefiles. 9-43 9 Configuration Enabling the Simulink Coder Software to Build When Path Names Contain Spaces The Simulink Coder software is able to handle path names that include spaces. Spaces might appear in the path from several sources: • Your MATLAB installation folder • The current MATLAB folder in which you initiate a build • A compiler you are using for a Simulink Coder build If your work environment includes one or more of the preceding scenarios, use the following support mechanisms as they apply:: • Add the following code to your template makefile (.tmf): ALT_MATLAB_ROOT = |>ALT_MATLAB_ROOT<| ALT_MATLAB_BIN = |>ALT_MATLAB_BIN<| !if "$(MATLAB_ROOT)" != "$(ALT_MATLAB_ROOT)" MATLAB_ROOT = $(ALT_MATLAB_ROOT) !endif !if "$(MATLAB_BIN)" != "$(ALT_MATLAB_BIN)" MATLAB_BIN = $(ALT_MATLAB_BIN) !endif This code replaces MATLAB_ROOT with ALT_MATLAB_ROOT when the values of the two tokens are not equal, indicating the path for your MATLAB installation folder includes spaces. Likewise, ALT_MATLAB_BIN replaces MATLAB_BIN. Note the preceding code is specific to nmake. See the supplied Simulink Coder template make files for platform-specific examples. • When using operating system commands, such as system or dos, enclose path that specify executables or command parameters in double quotes (" "). For example, system('dir "D:\Applications\Common Files"') Custom Targets You can create your own system target files to build custom targets that interface with external code or operating environments. 9-44 Target See “About Embedded Target Development” on page 24-2 and the topics it references for details and examples showing how to make your custom targets appear in the System Target File Browser and display relevant controls in panes of the Configuration Parameters dialog box. Describing the Emulation and Embedded Targets The Configuration Parameters dialog Hardware Implementation pane provides options that you can use to describe hardware properties, such as data size and byte ordering, and compiler behavior details that may vary with the compiler, such as integer rounding. The Hardware Implementation pane contains two subpanes: • Embedded Hardware — Describes the embedded target hardware and the compiler that you will use with it. This information affects both simulation and code generation. • Emulation Hardware — Describes the emulation target hardware and the compiler that you will use with it. This information affects only code generation. The two subpanes provide identical options and value choices. By default, the Embedded Hardware subpane initially looks like this: The default assumption is that the embedded target and emulation target are the same, so the Emulation Hardware subpane by default does not need to specify anything and contains only a checked option labeled None. Code generated under this configuration will be suitable for production use, or for testing in an environment identical to the production environment. 9-45 9 Configuration If you clear the check box, the Emulation Hardware subpane appears, initially showing the same values as the Embedded Hardware subpane. If you change any of these values, then generate code, the code will be able to execute in the environment specified by the Emulation Hardware subpane, but will behave as if it were executing in the environment specified by the Embedded Hardware subpane. See “Describing Emulation Hardware Characteristics” on page 9-55 for details. If you have used the Code Generation pane to specify a System target file, and the target file specifies a default microprocessor and its hardware properties, the default and properties appear as initial values in the Hardware Implementation pane. Options with only one possible value cannot be changed. Any option that has more than one possible value provides a list of legal values. If you specify any hardware properties manually, check carefully that their values are consistent with the system target file. Otherwise, the generated code may fail to compile or execute, or may execute but give incorrect results. Note Hardware Implementation pane options do not control hardware or compiler behavior in any way. Their purpose is solely to describe hardware and compiler properties to MATLAB software, which uses the information to generate code for the platform thatruns as efficiently as possible, and gives bit-true agreement for the results of integer and fixed-point operations in simulation, production code, and test code. The rest of this section describes the options in the Embedded Hardware and Emulation Hardware subpanes. Subsequent sections describe considerations that apply only to one or the other subpane. For more about Hardware Implementation options, see “Hardware Implementation Pane”. To see an example of Hardware Implementation pane capabilities, run the rtwdemo_targetsettings example. Describing the Device Vendor The Device vendor option gives the name of the device vendor. To set the option, select a vendor name from the Device vendor menu. Your selection of vendor will determine the available device values in the Device type list. 9-46 Target If the desired vendor name does not appear in the menu, select Generic and then use the Device type option to further specify the device. Note • For complete lists of Device vendor and Device type values, see “Device vendor” and “Device type” in the Simulink reference documentation. • To add Device vendor and Device type values to the default set that is displayed on the Hardware Implementation pane, see “Registering Additional Device Vendor and Device Type Values” on page 9-47. Describing the Device Type The Device type option selects a hardware device among the supported devices listed for your Device vendor selection. To set the option, select a microprocessor name from the Device type menu. If the desired microprocessor does not appear in the menu, change the Device vendor to Generic. If you specified Device vendor as Generic, examine the listed device descriptions and select the device type that matches your hardware. If no available device type matches, select Custom. If you select a device type for which the target file specifies default hardware properties, the properties appear as initial values in the subpane. Options with only one possible value cannot be changed. Any option that has more than one possible value provides a list of legal values. Select values for your hardware. If the device type is Custom, more options can be set, and each option has a list of possible values. Registering Additional Device Vendor and Device Type Values To add Device vendor and Device type values to the default set that is displayed on the Hardware Implementation pane, you can use a hardware device registration API provided by the Simulink Coder software. 9-47 9 Configuration To use this API, you create an sl_customization.m file, located in your MATLAB path, that invokes the registerTargetInfo function and fills in a hardware device registry entry with device information. The device information will be registered with Simulink software for each subsequent Simulink session. (To register your device information without restarting MATLAB, issue the MATLAB command sl_refresh_customizations.) For example, the following sl_customization.m file adds device vendor MyDevVendor and device type MyDevType to the Simulink device lists. function sl_customization(cm) cm.registerTargetInfo(@loc_register_device); end function thisDev = loc_register_device thisDev = RTW.HWDeviceRegistry; thisDev.Vendor = 'MyDevVendor'; thisDev.Type = 'MyDevType'; thisDev.Alias = {}; thisDev.Platform = {'Prod', 'Target'}; thisDev.setWordSizes([8 16 32 32 32]); thisDev.LargestAtomicInteger = 'Char'; thisDev.LargestAtomicFloat = 'None'; thisDev.Endianess = 'Unspecified'; thisDev.IntDivRoundTo = 'Undefined'; thisDev.ShiftRightIntArith = true; thisDev.setEnabled({'IntDivRoundTo'}); end If you subsequently select the device in the Hardware Implementation pane, it is displayed as follows: 9-48 Target To register multiple devices, you can specify an array of RTW.HWDeviceRegistry objects in your sl_customization.m file. For example, function sl_customization(cm) cm.registerTargetInfo(@loc_register_device); end function thisDev = loc_register_device thisDev(1) = RTW.HWDeviceRegistry; thisDev(1).Vendor = 'MyDevVendor'; thisDev(1).Type = 'MyDevType1'; ... thisDev(4) = RTW.HWDeviceRegistry; thisDev(4).Vendor = 'MyDevVendor'; thisDev(4).Type = 'MyDevType4'; ... end The following table lists the RTW.HWDeviceRegistry properties that you can specify in the registerTargetInfo function call in your sl_customization.m file. 9-49 9 Configuration Property Description Vendor String specifying the Device vendor value for your hardware device. Type String specifying the Device type value for your hardware device. Alias Cell array of strings specifying any aliases or legacy names that users might specify that should resolve to this device. Specify each alias or legacy name in the format 'Vendor->Type'. (Embedded Coder software provides the utility functions RTW.isHWDeviceTypeEq and RTW.resolveHWDeviceType for detecting and resolving alias values or legacy values when testing user-specified values for the target device type.) Platform Cell array of enumerated string values specifying whether this device should be listed in the Embedded hardware subpane ({'Prod'}), the Emulation hardware subpane ({'Target'}), or both ({'Prod', 'Target'}). setWordSizes Array of integer sizes to associate with the Number of bits parameters char, short, int, long, and native word size, respectively. LargestAtomicIntegerString specifying an enumerated value for the Largest atomic size: integer parameter: 'Char', 'Short','Int', or 'Long'. LargestAtomicFloat String specifying an enumerated value for the Largest atomic size: floating-point parameter: 'Float', 'Double', or 'None'. 9-50 Endianess String specifying an enumerated value for the Byte ordering parameter: 'Unspecified', 'Little' for little Endian, or 'Big' for big Endian. IntDivRoundTo String specifying an enumerated value for the Signed integer division rounds to parameter: 'Zero', 'Floor', or 'Undefined'. Target Property Description ShiftRightIntArith Boolean value specifying whether your compiler implements a signed integer right shift as an arithmetic right shift (true) or not (false). setEnabled Cell array of strings specifying which device properties should be enabled (modifiable) in the Hardware Implementation pane when this device type is selected. In addition to the 'Endianess', 'IntDivRoundTo', and 'ShiftRightIntArith' properties listed above, you can enable individual Number of bits parameters using the property names 'BitPerChar', 'BitPerShort', 'BitPerInt', 'BitPerLong', and 'NativeWordSize'. Describing the Number of Bits The Number of bits options describe the native word size of the microprocessor, and the bit lengths of char, short, int, and long data. For code generation to succeed: • The bit lengths must be such that char <= short <= int <= long. • Bit lengths must be multiples of 8, with a maximum of 32. • The bit length for long data must not be less than 32. Simulink Coder integer type names are defined in the file rtwtypes.h. The values that you provide must be consistent with the word sizes as defined in the compiler’s limits.h header file. The following table lists the standard Simulink Coder integer type names and maps them to the corresponding Simulink names. Simulink Coder Integer Type Simulink Integer Type boolean_T boolean int8_T int8 uint8_T uint8 9-51 9 Configuration Simulink Coder Integer Type Simulink Integer Type int16_T int16 uint16_T uint16 int32_T int32 uint32_T uint32 If no ANSI C type with a matching word size is available, but a larger ANSI C type is available, the Simulink Coder code generator uses the larger type for int8_T, uint8_T, int16_T, uint16_T, int32_T, and uint32_T. An application can use integer data of any length from 1 (unsigned) or 2 (signed) bits up 32 bits. If the integer length matches the length of an available type, the Simulink Coder code generator uses that type. If no matching type is available, the code generator uses the smallest available type that can hold the data, generating code that never uses unnecessary higher-order bits. For example, on a target that provided 8-bit, 16-bit, and 32-bit integers, a signal specified as 24 bits would be implemented as an int32_T or uint32_T. Code that uses emulated integer data is not maximally efficient, but can be useful during application development for emulating integer lengths that are available only on production hardware. The use of emulation does not affect the results of execution. Describing the Byte Ordering The Byte ordering option specifies whether the target hardware uses Big Endian (most significant byte first) or Little Endian (least significant byte first) byte ordering. If left as Unspecified, the Simulink Coder software generates code that determines the endianness of the target; this is the least efficient option. Describing Quotient Rounding for Signed Integer Division ANSI C does not completely define the rounding technique to be used when dividing one signed integer by another, so the behavior is implementation-dependent. If both integers are positive, or both are negative, 9-52 Target the quotient must round down. If either integer is positive and the other is negative, the quotient can round up or down. The Signed integer division rounds to parameter tells the Simulink Coder code generator how the compiler rounds the result of signed integer division. Providing this information does not affect the operation of the compiler, it only describes that behavior to the code generator, which uses the information to optimize code generated for signed integer division. The parameter options are: • Zero — If the quotient is between two integers, the compiler chooses the integer that is closer to zero as the result. • Floor — If the quotient is between two integers, the compiler chooses the integer that is closer to negative infinity. • Undefined — Choose this option if neither Zero nor Floor describes the compiler’s behavior, or if that behavior is unknown. The following table illustrates the compiler behavior that corresponds to each of these three options: N D Ideal N/D Zero Floor Undefined 33 4 8.25 8 8 8 -33 4 -8.25 -8 -9 -8 or -9 33 -4 -8.25 -8 -9 -8 or -9 -33 -4 8.25 8 8 8 or 9 Note Select Undefined only as a last resort. When the code generator does not know the signed integer division rounding behavior of the compiler, it generates extra code. The compiler’s implementation for signed integer division rounding can be obtained from the compiler documentation, or by experiment if no documentation is available. 9-53 9 Configuration Describing Arithmetic Right Shifts on Signed Integers ANSI C does not define the behavior of right shifts on negative integers, so the behavior is implementation-dependent. The Shift right on a signed integer as arithmetic shift parameter tells the Simulink Coder code generator how the compiler implements right shifts on negative integers. Providing this information does not affect the operation of the compiler, it only describes that behavior to the code generator, which uses the information to optimize the code generated for arithmetic right shifts. Select the option if the C compiler implements a signed integer right shift as an arithmetic right shift, and clear the option otherwise. An arithmetic right shift fills bits vacated by the right shift with the value of the most significant bit, which indicates the sign of the number in twos complement notation. The option is selected by default. If your compiler handles right shifts as arithmetic shifts, this is the preferred setting. • When the option is selected, the Simulink Coder software generates simple efficient code whenever the Simulink model performs arithmetic shifts on signed integers. • When the option is cleared, the Simulink Coder software generates fully portable but less efficient code to implement right arithmetic shifts. The compiler’s implementation for arithmetic right shifts can be obtained from the compiler documentation, or by experiment if no documentation is available. Describing Embedded Hardware Characteristics “Describing the Emulation and Embedded Targets” on page 9-45 documents the options available on the Hardware Implementation subpanes. This section describes considerations that apply only to the Embedded Hardware subpane. When you use this subpane, keep the following in mind: • Code generation targets can have word sizes and other hardware characteristics that differ from the MATLAB host. Furthermore, code can be prototyped on hardware that is different from either the deployment target or the MATLAB host. The Simulink Coder code generator takes these differences into account when generating code. 9-54 Target • The Simulink product uses some of the information in the Embedded Hardware subpane to get the same results from simulation without code generation as executing generated code, including detecting error conditions that could arise on the target hardware, such as hardware overflow. • The Simulink Coder software generates code that produces bit-true agreement with Simulink results for integer and fixed-point operations. Generated code that emulates unavailable data lengths runs less efficiently than it would without emulation, but the emulation does not affect bit-true agreement with Simulink for integer and fixed-point results. • If you change targets at any point during application development, reconfigure the hardware implementation parameters for the new target before generating or regenerating code. Bit-true agreement for the results of integer and fixed-point operations in simulation, production code, and test code might not occur when code executes on hardware for which it was not generated. • Use the Integer rounding mode parameter on your model’s blocks to simulate the rounding behavior of the C compiler that you intend to use to compile code generated from the model. This setting appears on the Signal Attributes pane of the parameter dialog boxes of blocks that can perform signed integer arithmetic, such as the Product and n-D Lookup Table blocks. • For most blocks, the value of Integer rounding mode completely defines rounding behavior. For blocks that support fixed-point data and the Simplest rounding mode, the value of Signed integer division rounds to also affects rounding. For details, see “Rounding”. • When models contain Model blocks, all models that they reference must be configured to use identical hardware settings. Describing Emulation Hardware Characteristics “Describing the Emulation and Embedded Targets” on page 9-45 documents the options available on the Hardware Implementation subpanes. This section describes considerations that apply only to the Emulation Hardware subpane. 9-55 9 Configuration Note (If the Emulation Hardware subpane contains a button labeled Configure current execution hardware device, see “Updating from Earlier Versions” on page 9-57, then continue from this point.) The default assumption is that the embedded target and emulation target are the same, so the Emulation Hardware subpane by default does not need to specify anything and contains only a selected check box labeled None. Code generated under this configuration will be suitable for production use, or for testing in an environment identical to the production environment. To generate code that runs on an emulation target for test purposes, but behaves as if it were running on an embedded target in a production application, you must specify the properties of both targets in the Hardware Implementation pane. The Embedded Hardware subpane specifies embedded target hardware properties, as described previously. To specify emulation target properties: 1 Clear the None option in the Emulation Hardware subpane. 2 In the Emulation Hardware subpane, specify the properties of the emulation target, using the instructions in “Describing the Emulation and Embedded Targets” on page 9-45 If you have used the Code Generation pane to specify a System target file, and the target file specifies a default microprocessor and its hardware properties, the default and properties appear as initial values in both subpanes of the Hardware Implementation pane. 9-56 Target Options with only one possible value cannot be changed. Any option that has more than one possible value provides a list of legal values. If you specify any hardware properties manually, check carefully that their values are consistent with the system target file. Otherwise, the generated code may fail to compile or execute, or may execute but give incorrect results. If you do not display the Emulation Hardware subpane, the Simulink and Simulink Coder software defaults every Emulation Hardware option to have the same value as the corresponding Embedded Hardware option. If you hide the Emulation Hardware subpane after setting its values, the values that you specified will be lost. The underlying configuration parameters immediately revert to the values that they had when you exposed the subpane, and these values, rather than the values that you specified, will appear if you re-expose the subpane. Updating from Earlier Versions If your model was created before Release 14 and has not been updated, by default the Hardware Implementation pane initially looks like this: Click Configure current execution hardware device. The Configure current execution hardware device button disappears. The subpane then appears as shown in the first figure in this section. Save your model at this point to avoid redoing Configure current execution hardware device next time you access the Hardware Implementation pane. 9-57 9 Configuration Specifying Target Interfaces Use the Interface pane to control which math library is used at run time, whether to include one of three APIs in generated code, and certain other interface options. To... Select or Enter... Specify the target-specific math library to use when generating code Select C89/C90 (ANSI), C99 (ISO), GNU99 (GNU), or C++ (ISO) for Code replacement library. (Additional values may be listed for licensed target products, for Embedded Targets and Desktop Targets, or if you have created and registered code replacement libraries with the Embedded Coder product.) Selecting C89/C90 (ANSI) provides the ANSI10 C set of library functions. For example, selecting C89/C90 (ANSI) would result in generated code that calls sin() whether the input argument is double precision or single precision. However, if you select C99 (ISO), the call instead is to the function sinf(), which is single precision. If your compiler supports the ISO11 C math extensions, selecting the ISO C library can result in more efficient code. For more information about code replacement libraries, see “Selecting and Viewing Code Replacement Libraries” on page 9-61. Direct where the Simulink Coder code generator should place fixed-point and other utility code Select Auto or Shared location for Shared code placement. The shared location directs code for utilities to be placed within the slprj folder in your working folder, which is used for building model reference targets. If you select Auto, • When the model contains Model blocks, places utility code within the slprj/target/_sharedutils folder. • When the model does not contain Model blocks, places utility code in the build folder (generally, in model.c or model.cpp). 10. ANSI® is a registered trademark of the American National Standards Institute, Inc. 11. ISO® is a registered trademark of the International Organization for Standardization. 9-58 Target To... Select or Enter... Specify a string to be added to the variable names used when logging data to MAT-files, to distinguish logging data from Simulink Coder and Simulink applications Enter a prefix or suffix, such as rt_ or _rt, for MAT-file variable name modifier. The Simulink Coder code generator prefixes or appends the string to the variable names for system outputs, states, and simulation time specified in the Data Import/Export pane. See “Logging” on page 15-105 for information on MAT-file data logging. Specify an API to be included in generated code Select C API, External mode, or ASAP2 for Interface. When you select C API or External mode, other options appear. C API and External mode are mutually exclusive. However, this is not the case for C API and ASAP2. For more information on working with these interfaces, see “Data Interchange Using the C API” on page 15-137, “Host/Target Communication” on page 15-50, and “ASAP2 Data Measurement and Calibration” on page 15-174. Note Before setting Code replacement library, verify that your compiler supports the library you want to use. If you select a parameter value that your compiler does not support, compiler errors can occur. For example, if you select C99 (ISO) and your compiler does not support the ISO C math extensions, compile-time errors likely will occur. When the Embedded Coder product is installed on your system, the Code Generation > Interface pane expands to include several additional options. For descriptions of Code Generation > Interface pane parameters, see “Code Generation Pane: Interface”. For a summary of option dependencies, see “Interface Dependencies” on page 9-59. Interface Dependencies Several parameters available on the Interface pane have dependencies on settings of other parameters. The following table summarizes the dependencies. 9-59 9 9-60 Configuration Parameter Dependencies? Code replacement library No Shared code placement No Support: floating-point numbers (ERT targets only) No Support: non-finite numbers Yes (ERT targets) No (GRT targets) Support: complex numbers (ERT targets only) No Support: absolute time (ERT targets only) No Support: continuous time (ERT targets only) No Support: non-inlined S-functions (ERT targets only) Yes Requires that you enable Support floating-point numbers and Support non-finite numbers Classic call interface Yes (ERT targets) No (GRT targets) For ERT targets, requires that you enable Support floating-point numbers and disable Single output/update function Single output/update function (ERT targets only) Yes Disable for Classic call interface Terminate function required (ERT targets only) Yes Generate reusable code (ERT targets only) Yes Reusable code error diagnostic (ERT targets only) Yes Dependency Details For ERT targets, enabled by Support floating-point numbers Enabled by Generate reusable code Target Parameter Dependencies? Dependency Details Pass root-level I/O as (ERT targets only) Yes Enabled by Generate reusable code MAT-file logging Yes For GRT targets, requires that you enable Support non-finite numbers; for ERT targets, requires that you enable Support floating-point numbers, Support non-finite numbers, and Terminate function required MAT-file file variable name modifier Yes Enabled by MAT-file logging Suppress error status in real-time model data structure (ERT targets only) No Interface No Generate C API for: signals Yes Set Interface to C API Generate C API for: parameters Yes Set Interface to C API Generate C API for: states Yes Set Interface to C API Transport layer Yes Set Interface to External mode MEX-file arguments Yes Set Interface to External mode Static memory allocation Yes Set Interface to External mode Static memory buffer size Yes Enable Static memory allocation Selecting and Viewing Code Replacement Libraries • “Selecting a Target-Specific Math Library for Your Model” on page 9-62 • “Code Replacement Table Overview” on page 9-63 • “Using the Code Replacement Viewer” on page 9-65 9-61 9 Configuration Selecting a Target-Specific Math Library for Your Model A code replacement library (CRL) is a set of one or more code replacement tables that define the target-specific implementations of math functions and operators to be used in generating code for your Simulink model. The Simulink Coder product provides default CRLs, which you can select from the Code replacement library drop-down list on the Code Generation > Interface pane of the Configuration Parameters dialog box. CRL Description Contains tables... C89/C90 (ANSI) Generates calls to the ISO/IEC 9899:1990 C standard math library for floating-point functions. ansi_tfl_table_tmw.mat C99 (ISO) Generates calls to the ISO/IEC 9899:1999 C standard math library. iso_tfl_table_tmw.mat ansi_tfl_table_tmw.mat GNU99 (GNU) Generates calls to the Free Software Foundation’s GNU gcc math library, which provides C99 extensions as defined by compiler option -std=gnu99. gnu_tfl_table_tmw.mat iso_tfl_table_tmw.mat ansi_tfl_table_tmw.mat C++ (ISO) Generates calls to the ISO/IEC 14882:2003 C++ standard math library. iso_cpp_tfl_table_tmw.mat private_iso_cpp_tfl_table_tmw.mat iso_tfl_table_tmw.mat ansi_tfl_table_tmw.mat CRL tables provide the basis for replacing default math functions and operators in your model code with target-specific code. If you select a library and then hover over the selected library with the cursor, a tool tip is displayed that describes the CRL and lists the code replacement tables it contains. Tables are listed in the order in which they are searched for a function or operator match. 9-62 Target The Simulink Coder product allows you to view the content of CRL code replacement tables using the Code Replacement Viewer, as described in “Using the Code Replacement Viewer” on page 9-65. If you are licensed to use the Embedded Coder product, you additionally can create and register the code replacement tables that make up a CRL. Code Replacement Table Overview Each CRL code replacement table contains one or more table entries, with each table entry representing a potential replacement for a single math function or an operator. Each table entry provides a mapping between a conceptual view of the function or operator (similar to the Simulink block view of the function or operator) and a target-specific implementation of that function or operator. The conceptual view of a function or operator is represented in a CRL table entry by the following elements, which identify the function or operator entry to the code generation process: 9-63 9 Configuration • A function or operator key (a function name such as 'cos' or an operator ID string such as 'RTW_OP_ADD') • A set of conceptual arguments that observe Simulink naming ('y1', 'u1', 'u2', ...), along with their I/O types (output or input) and data types • Other attributes, such as fixed-point saturation and rounding characteristics for operators, to identify the function or operator to the code generation process as exactly as required for matching purposes The target-specific implementation of a function or operator is represented in a CRL table entry by the following elements: • The name of an implementation function (such as 'cos_dbl' or 'u8_add_u8_u8') • A set of implementation arguments, along with their I/O types (output or input) and data types • Parameters providing the build information for the implementation function, including header file and source file names and paths Additionally, a CRL table entry includes a priority value (0-100, with 0 as the highest priority), which defines the entry’s priority relative to other entries in the table. During code generation for your model, when the code generation process encounters a call site for a math function or operator, it creates and partially populates a CRL entry object, for the purpose of querying the CRL for a replacement function. The information provided for the CRL query includes the function or operator key and the conceptual argument list. The CRL entry object is then passed to the CRL. If the CRL contains a matching table entry, a fully-populated CRL entry, including the implementation function name, argument list, and build information, is returned to the call site and used to generate code. Within the CRL that is selected for your model, the tables that comprise the CRL are searched in the order in which they are listed (in the left or right pane of the Code Replacement Viewer or in the CRL’s Code replacement library tool tip). Within each table, if multiple matches are found for a CRL entry object, priority level determines the match that is returned. A 9-64 Target higher-priority (lower-numbered) entry will be used over a similar entry with a lower priority (higher number). Using the Code Replacement Viewer The Code Replacement Viewer allows you to examine the content of CRL code replacement tables. (For an overview of code replacement tables and the information they contain, see the preceding section.) To launch the viewer with all currently registered CRLs displayed, issue the following MATLAB command: >> RTW.viewTfl Select the name of a CRL in the left pane, and the viewer displays information about the CRL in the right pane. For example, the tables that make up the CRL are listed in priority order. In the following display, the GNU CRL has been selected. Click the plus sign (+) next to a CRL name in the left pane to expand its list of tables, and select a table from the list. The viewer displays the function 9-65 9 Configuration and operator entries in the selected table in the middle pane, along with abbreviated table entry information for each entry. In the following display, the ANSI table has been selected. The following fields appear in the abbreviated table entry information provided in the middle pane: 9-66 Field Description Name Name of the function or ID of the operator to be replaced (for example, cos or RTW_OP_ADD). Implementation Name of the implementation function, which can match or differ from Name. NumIn Number of input arguments. In1Type Data type of the first conceptual input argument. In2Type Data type of the second conceptual input argument. OutType Data type of the conceptual output argument. Target Field Description Priority The entry’s search priority, 0-100, relative to other entries of the same name and conceptual argument list within this table. Highest priority is 0, and lowest priority is 100. The default is 100. If the table provides two implementations for a function or operator, the implementation with the higher priority will shadow the one with the lower priority. UsageCount Not used. Select a function or operator entry in the middle pane. The viewer displays detailed information from the table entry in the right pane. In the following display, the second entry for the cos function has been selected. The following fields appear in the detailed table entry information provided in the right pane. 9-67 9 9-68 Configuration Field Description Description Text description of the table entry (can be empty). Key Name of the function or ID of the operator to be replaced (for example, cos or RTW_OP_ADD), and the number of conceptual input arguments. Implementation Name of the implementation function, and the number of implementation input arguments. Implementation type Type of implementation: FCN_IMPL_FUNCT for function or FCN_IMPL_MACRO for macro. Saturation mode Saturation mode supported by the implementation function for an operator replacement: RTW_SATURATE_ON_OVERFLOW, RTW_WRAP_ON_OVERFLOW, or RTW_SATURATE_UNSPECIFIED. Rounding mode Rounding mode supported by the implementation function for an operator replacement: RTW_ROUND_FLOOR, RTW_ROUND_CEILING, RTW_ROUND_ZERO, RTW_ROUND_NEAREST, RTW_ROUND_NEAREST_ML, RTW_ROUND_SIMPLEST, RTW_ROUND_CONV, or RTW_ROUND_UNSPECIFIED. GenCallback file Not used. Implementation header Name of the header file that declares the implementation function. Implementation source Name of the implementation source file. Priority The entry’s search priority, 0-100, relative to other entries of the same name and conceptual argument list within this table. Highest priority is 0, and lowest priority is 100. The default is 100. If the table provides two implementations for a function or operator, the implementation with the higher priority will shadow the one with the lower priority. Target Field Description Total Usage Count Not used. Conceptual argument(s) Name, I/O type (RTW_IO_OUTPUT or RTW_IO_INPUT), and data type for each conceptual argument. Implementation Name, I/O type (RTW_IO_OUTPUT or RTW_IO_INPUT), and data type for each implementation argument. If you select an operator entry, an additional tab containing fixed-point setting information is displayed in the right pane. For example: The following fields appear in the fixed-point setting information provided in the right pane: 9-69 9 9-70 Configuration Field Description Slopes must be the same Indicates whether CRL replacement request processing must check that the slopes on all arguments (input and output) are equal. Used with fixed-point addition and subtraction replacement to disregard specific slope and bias values and map relative slope and bias values to a replacement function. Must have zero net bias Indicates whether CRL replacement request processing must check that the net bias on all arguments is zero. Used with fixed-point addition and subtraction replacement to disregard specific slope and bias values and map relative slope and bias values to a replacement function. Relative scaling factor F Slope adjustment factor (F) part of the relative scaling factor, F2E, for relative scaling CRL entries. Used with fixed-point multiplication and division replacement to map a range of slope and bias values to a replacement function. Relative scaling factor E Fixed exponent (E) part of the relative scaling factor, F2E, for relative scaling CRL entries. Used with fixed-point multiplication and division replacement to map a range of slope and bias values to a replacement function. Select the Target Language Select the Target Language Use the Language menu in the Target selection section of the Code Generation pane to select the target language for the code generated by the Simulink Coder code generator. You can select C or C++. The Simulink Coder software generates .c or .cpp files, depending on your selection, and places the files in your build folder. Note If you select C++, you might need to configure the Simulink Coder software to use a compiler before you build a system. For details, see “Choose and Configure a Compiler” on page 15-2. 9-71 9 Configuration Code Appearance In this section... “Configure Code Comments” on page 9-72 “Configure Generated Identifiers” on page 9-73 Configure Code Comments Configure how the code generator inserts comments into generated code, by modifying parameters on the Comments pane. Note Comments can include international (non-US-ASCII) characters encountered during code generation when found in Simulink block names and block descriptions, user comments on Stateflow diagrams, Stateflow object descriptions, custom TLC files, and code generation template files. 9-72 To... Select... Include comments in generated code Include comments. Selecting this parameter allows you to select one or more comment types to be placed in the code. Include comments for blocks that were eliminated as the result of optimizations (such as parameter inlining) Show eliminated blocks. Code Appearance To... Select... Automatically insert comments that describe a block’s code before the code in the generated file Simulink block / Stateflow object comments. Include comments for parameter variable names and names of source blocks in the model parameter structure declaration in model_prm.h Verbose comments for SimulinkGlobal storage class. If you do not select this parameter, parameter comments are generated if less than 1000 parameters are declared. This reduces the size of the generated file for models with a large number of parameters. When you select the parameter, parameter comments are generated regardless of the number of parameters. For descriptions of Comments pane parameters, see “Code Generation Pane: Comments” in the Simulink Coder reference documentation. Configure Generated Identifiers • “Reserved Keywords” on page 9-74 • “Construction of Symbols” on page 9-78 Configure how the code generator uses symbols to name identifiers and objects by setting parameters on the Symbols pane. Two options are available for GRT targets: Maximum identifier length and Reserved names. These are the only symbols options for GRT targets. The Maximum identifier length field allows you to limit the number of characters in function, type definition, and variable names. The default is 31 characters. This is also the minimum length you can specify; the maximum is 256 characters. Consider increasing identifier length for models having a deep hierarchical structure, and when exercising some of the mnemonic identifier options described below. Within a model containing Model blocks, no collisions of constituent model names can exist. When generating code from a model that uses model 9-73 9 Configuration referencing, the Maximum identifier length must be large enough to accommodate the root model name and the name mangling string (if any). A code generation error occurs if Maximum identifier length is too small. When a name conflict occurs between a symbol within the scope of a higher level model and a symbol within the scope of a referenced model, the symbol from the referenced model is preserved. Name mangling is performed on the symbol from the higher level model. The Reserved names field allows you to specify the set of keywords that the Simulink Coder code generation process should not use, facilitating code integration where functions and variables from external environments are unknown in the Simulink model. For a list of rules for specifying reserved names, see “Reserved names” in the Simulink Coder reference documentation. If your model contains MATLAB Function or Stateflow blocks, the code generation process can use the reserved names specified for those blocks if you select Use the same reserved names as Simulation Target. If the Embedded Coder product is installed on your system, the Symbols pane expands to include options for controlling identifier formats, mangle length, scalar inlined parameters, and Simulink data object naming rules. For details, see “Customize Generated Identifiers” in the Embedded Coder documentation. For descriptions of Symbols pane parameters, see “Code Generation Pane: Symbols”. Reserved Keywords • “C Reserved Keywords” on page 9-75 • “C++ Reserved Keywords” on page 9-75 • “Reserved Keywords for Code Generation” on page 9-76 • “Simulink® Coder™ Code Replacement Library Keywords” on page 9-76 Simulink Coder software reserves certain words for its own use as keywords of the generated code language. Simulink Coder keywords are reserved for use internal to Simulink Coder software and should not be used in Simulink 9-74 Code Appearance models as identifiers or function names. C reserved keywords should also not be used in Simulink models as identifiers or function names. If your model contains any reserved keywords, the code generation build does not complete and an error message is displayed. To address this error, modify your model to use identifiers or names that are not reserved. If you are generating C++ code using the Simulink Coder software, your model must not contain both the “Reserved Keywords for Code Generation” on page 9-76 and the “C++ Reserved Keywords” on page 9-75. Note You can register additional reserved identifiers in the Simulink environment. For more information, see “Reserved names” in the Simulink Coder reference documentation. C Reserved Keywords. auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if static while C++ Reserved Keywords. catch friend protected try class inline public typeid const_cast mutable reinterpret_cast typename delete namespace static_cast using dynamic_cast new template virtual 9-75 9 Configuration explicit operator this export private throw wchar_t Reserved Keywords for Code Generation. abs fortran localZCE rtNaN asm HAVESTDIO localZCSV SeedFileBuffer bool id_t matrix SeedFileBufferLen boolean_T int_T MODEL single byte_T int8_T MT TID01EQ char_T int16_T NCSTATES time_T cint8_T int32_T NULL true cint16_T int64_T NUMST TRUE cint32_T INTEGER_CODE pointer_T uint_T creal_T LINK_DATA_BUFFER_SIZE PROFILING_ENABLED creal32_T LINK_DATA_STREAM PROFILING_NUM_SAMPLES uint16_T creal64_T localB real_T uint32_T cuint8_T localC real32_T uint64_T cuint16_T localDWork real64_T UNUSED_PARAMETER cuint32_T localP RT USE_RTMODEL ERT localX RT_MALLOC VCAST_FLUSH_DATA false localXdis rtInf vector FALSE localXdot rtMinusInf uint8_T Simulink Coder Code Replacement Library Keywords. The list of code replacement library (CRL) reserved keywords for your development environment varies depending on which CRLs currently are registered. Beyond the default ANSI, ISO, and GNU CRLs provided with Simulink Coder software, additional CRLs might be registered and available for use if you have installed other products that provide CRLs (for example, a target product), or if you have used Embedded Coder APIs to create and register custom CRLs. 9-76 Code Appearance To generate a list of reserved keywords for CRLs currently registered in your environment, use the following MATLAB function: crl_ids = RTW.TargetRegistry.getInstance.getTflReservedIdentifiers() This function returns an array of CRL keyword strings. Specifying the return argument is optional. Note To list the CRLs currently registered in your environment, use the MATLAB command RTW.viewTfl. To generate a list of reserved keywords for the CRL that you are using to generate code, call the function passing the name of the CRL as displayed in the Code replacement library menu on the Code Generation > Interface pane of the Configuration Parameters dialog box. For example, crl_ids = RTW.TargetRegistry.getInstance.getTflReservedIdentifiers('GNU99 (GNU)') Here is a partial example of the function output: >> crl_ids = RTW.TargetRegistry.getInstance.getTflReservedIdentifiers('GNU99 (GNU)') crl_ids = 'exp10' 'exp10f' 'acosf' 'acoshf' 'asinf' 'asinhf' 'atanf' 'atanhf' ... 'rt_lu_cplx' 'rt_lu_cplx_sgl' 'rt_lu_real' 'rt_lu_real_sgl' 'rt_mod_boolean' 'rt_rem_boolean' 9-77 9 Configuration 'strcpy' 'utAssert' Note Some of the returned keyword strings appear with the suffix $N, for example, 'rt_atan2$N'. $N expands into the suffix _snf only if nonfinite numbers are supported. For example, 'rt_atan2$N' represents 'rt_atan2_snf' if nonfinite numbers are supported and 'rt_atan2' if nonfinite numbers are not supported. As a precaution, you should treat both forms of the keyword as reserved. Construction of Symbols For GRT, GRT-malloc and RSim targets, the Simulink Coder code generator automatically constructs identifiers for variables and functions in the generated code. These symbols identify • Signals and parameters that have Auto storage class • Subsystem function names that are not user defined • Stateflow names The components of a generated symbol include • The root model name, followed by • The name of the generating object (signal, parameter, state, and so on), followed by • A unique name mangling string The name mangling string is conditionally generated to resolve potential conflicts with other generated symbols. The length of generated symbols is limited by the Maximum identifier length parameter specified on the Symbols pane of the Configuration Parameters dialog box. When there is a potential name collision between two symbols, a name mangling string is generated. The string has the minimum number of characters required to avoid the collision. The other symbol components are then inserted. If Maximum identifier length is not large 9-78 Code Appearance enough to accommodate full expansions of the other components, they are truncated. To avoid this outcome, it is good practice to: • Avoid name collisions. For example, avoid using default block names (for example, Gain1, Gain2...) when the model includes multiple blocks of the same type. Also, make subsystems atomic and reusable. • Where possible, increase the Maximum identifier length parameter to accommodate the length of the symbols you expect to generate. Model referencing might involve additional naming constraints. Within a model that uses referenced models, there can be no collisions between the names of the models. When you generate code from a model that includes referenced models, the Maximum identifier length parameter must be large enough to accommodate the root model name and the name mangling string (if needed). When a name conflict occurs between a symbol within the scope of a higher-level model and a symbol within the scope of a referenced model, the symbol from the referenced model is preserved. Name mangling is performed on the symbol from the higher-level model. For information, see “Configure Generated Identifiers” on page 9-73 and “Parameterize Model References”. The Embedded Coder product provides additional flexibility over how symbols are constructed, by using a Symbol format field that controls the symbol formatting in much greater detail. See “Configure Symbols” in the Embedded Coder documentation for more information. 9-79 9 Configuration Debug Use parameters on the Diagnostics and Code Generation > Debug panes of the Configuration Parameter dialog box to configure a model such that generated code and the build process are optimized for debugging. You can set parameters that apply to the model compilation phase, the target language code generation phase, or both. Parameters in the following table will be helpful if you are writing TLC code for customizing targets, integrating legacy code, or developing new blocks. 9-80 To... Select... Display progress information during code generation in the MATLAB Command Window Verbose build.Compiler output also displays. Prevent the build process from deleting the model.rtw file from the build folder at the end of the build Retain .rtw file. This parameter is useful if you are modifying the target files, in which case you need to look at the model.rtw file. Instruct the TLC profiler to analyze the performance of TLC code executed during code generation and generate a report Profile TLC. The report is in HTML format and can be read in your Web browser. Start the TLC debugger during code generation Start TLC debugger when generating code. Alternatively, enter the argument -dc for the System target file parameter on the Code Generation pane. To start the debugger and run a debugger script, enter -df filename for System target file. Debug To... Select... Generate a report containing statistics indicating how many times the Simulink Coder code generator reads each line of TLC code during code generation Start TLC coverage when generating code. Alternatively, enter the argument -dg for the System Target File parameter on the Code Generation pane. Halt a build if any user-supplied TLC file contains an %assert directive that evaluates to Enable TLC assertion. Alternatively, you can use MATLAB commands to control TLC assertion handling. To set the flag on or off, use the set_param command. The default is off. FALSE set_param(model, 'TLCAssertion', 'on|off') To check the current setting, use get_param. get_param(model, 'TLCAssertion') Detect loss of tunability Diagnostics > Data Validity > Detect loss of tunability. You can use this parameter to report loss of tunability when an expression is reduced to a numeric expression. This can occur if a tunable workspace variable is modified by Mask Initialization code, or is used in an arithmetic expression with unsupported operators or functions. Possible values are: • none — Loss of tunability can occur without notification. • warning — Loss of tunability generates a warning (default). • error — Loss of tunability generates an error. 9-81 9 Configuration To... Select... For a list of supported operators and functions, see “Tunable Expression Limitations” on page 15-131 Enable model verification (assertion) blocks Diagnostics > Data Validity > Model Verification block enabling . Use this parameter to enable or disable model verification blocks such as Assert, Check Static Gap, and related range check blocks. The diagnostic has the same affect on generated code as it does on simulation behavior. For example, simulation and code generation ignore this parameter when model verification blocks are inside an S-function. Possible values are: • User local settings • Enable All • Disable All For Assertion blocks not disabled, generated code for a model includes one of the following statements, depending on the blocks input signal type (Boolean, real, or integer, respectively). utAssert(input_signal); utAssert(input_signal != 0.0); utAssert(input_signal != 0); By default, utAssert has no effect in generated code. For assertions to abort execution, you must enable them by specifying the following make_rtw command for Code Generation > Make command: make_rtw OPTS="-DDOASSERTS" Use the following variant if you want triggered assertions to print the assertion statement instead of aborting execution: 9-82 Debug To... Select... make_rtw OPTS="-DDOASSERTS -DPRINT_ASSERTS" utAssert is defined as #define utAssert(exp) assert(exp). To customize assertion behavior, provide your own definition of utAssert in a handwritten header file that overrides the default utAssert.h. For details on how to include a customized header file in generated code, see “Configure Model for External Code Integration” on page 14-33. When running a model in accelerator mode, the Simulink engine calls back to itself to execute assertion blocks instead of using generated code. Thus, user-defined callbacks are still called when assertions fail. For more information about the TLC debugging options, see “Debugging”. Also, consider using the Model Advisor as a tool for troubleshooting model builds. For descriptions of Debug pane parameters, see “Code Generation Pane: Debug” in the Simulink Coder reference documentation. 9-83 9 9-84 Configuration 10 Source Code Generation • “Initiate Code Generation” on page 10-2 • “Reload Generated Code” on page 10-3 • “Generated Source Files and File Dependencies” on page 10-4 • “Files and Folders Created by Build Process” on page 10-24 • “How Code Is Generated From a Model” on page 10-31 • “Code Generation of Matrices and Arrays” on page 10-33 • “Shared Utility Code” on page 10-37 • “Generating Code Using Simulink Coder™” on page 10-49 10 Source Code Generation Initiate Code Generation You can generate code for your model with or without the compilation, linking, and other processing that occurs as part of a full model build. To generate code without initiating a full model build, select the Generate code only option on the Code Generation pane of the Configuration Parameters dialog box and click Generate Code. To initiate a full model build, clear the Generate code only option and click the Build button, or use any of the methods described in “Initiate the Build Process” on page 15-14. 10-2 Reload Generated Code Reload Generated Code You can reload the code generated for a model from the Model Explorer. 1 Click the Code for model node in the Model Hierarchy pane. 2 In the Code pane, click the Refresh link. The Simulink Coder software reloads the code for the model from the build folder. 10-3 10 Source Code Generation Generated Source Files and File Dependencies In this section... “About Generated Files and File Dependencies” on page 10-4 “Header Dependencies When Interfacing Legacy/Custom Code with Generated Code” on page 10-6 “Dependencies of the Generated Code” on page 10-16 “Specify Include Paths in Simulink® Coder™ Generated Source Files” on page 10-21 About Generated Files and File Dependencies The Simulink Coder software generates code into a set of source files that vary little among different targets. Not all possible files are generated for every model. Some files are created only when the model includes subsystems, calls external interfaces, or uses particular types of data. The Simulink Coder code generator handles most of the code formatting decisions (such as identifier construction and code packaging) in consistent ways. The source and make files created during the Simulink Coder build process are generated into your build folder, which is created or reused in your current folder. Some files are unconditionally generated, while the existence of others depend on target settings and options (for example, support files for C API or external mode). See “Files and Folders Created by Build Process” on page 10-24 for descriptions of the generated files. Note The file packaging of Embedded Coder targets differs slightly from the file packaging described below. See “Generate Code Modules” in the Embedded Coder documentation for more information. Generated source file dependencies are depicted in the next figure. Arrows coming from a file point to files it includes. Other dependencies exist, for example on Simulink header files tmwtypes.h and simstruc_types.h, plus C or C++ library files. The figure maps inclusion relations between only those files that are generated in the build folder. Utility and model reference code 10-4 Generated Source Files and File Dependencies located in a project folder might also be referenced by these files. See “Project Folder Structure for Model Reference Targets” on page 3-16 for details. The figure shows that parent system header files (model.h) include all child subsystem header files (subsystem.h). In more layered models, subsystems similarly include their children’s header files, on down the model hierarchy. As a consequence, subsystems are able to recursively “see” into their descendants’ subsystems, as well as to see into the root system (because every subsystem.c or subsystem.cpp includes model.h and model_private.h). model_private.h model.c subsystem.c model_data.c subsystem.h rtmodel.h is a dummy include file used only for grt and grt_malloc targets. model_types.h model.h rtmodel.h Simulink® Coder™ Generated File Dependencies Note In the preceding figure, files model.h, model_private.h, and subsystem.h also depend on the Simulink Coder header file rtwtypes.h. Targets that are not based on the ERT target can have additional dependencies on tmwtypes.h and simstruct_types.h. 10-5 10 Source Code Generation Header Dependencies When Interfacing Legacy/Custom Code with Generated Code You can incorporate legacy or custom code into a Simulink Coder build in any of several ways. One common approach is by creating S-functions. For details on this approach, see “Insert S-Function Code” on page 14-46. Another approach is to interface code using global variables created by declaring storage classes for signals and parameters. This requires customizing an outer code harness, typically referred to as a main.c or main.cpp file, to properly execute to the generated code. In addition, the harness can contain custom code. These scenarios require you to include header files specific to the Simulink Coder product to make available function declarations, type definitions, and defines to the legacy or custom code. rtwtypes.h The header file rtwtypes.h defines data types, structures, and macros required by the generated code. Normally, you should include rtwtypes.h for both GRT and ERT targets instead of including tmwtypes.h or simstruc_types.h. However, the contents of the header file varies depending on your target selection. For... rtwtypes.h GRT target Provides a complete set of definitions by including tmwtypes.h and simstruct_types.h, both of which depend on • System headers limits.h and float.h • Simulink Coder headers: rtw_matlogging.h, rtw_extmode.h, rtw_continuous.h, and rtw_solver.h ERT target and targets based on the ERT target 10-6 Is optimized, when possible, to include a minimum set of #define statements, enumerations, and so on; does not include tmwtypes.h and simstruct_types.h Generated Source Files and File Dependencies The Simulink Coder build process generates the optimized version of rtwtypes.h for the ERT target when both of the following conditions exist: • The Classic call interface option on the Code Generation > Interface pane of the Configuration Parameters dialog box is cleared. • The model contains no noninlined S-functions You should always include rtwtypes.h. If you include it for GRT targets, for example, it is easier to use your code with ERT-based targets. rtwtypes.h for GRT targets: #ifndef __RTWTYPES_H__ #define __RTWTYPES_H__ #include "tmwtypes.h" /* This ID is used to detect inclusion of an incompatible * rtwtypes.h */ #define RTWTYPES_ID_C08S16I32L32N32F1 #include "simstruc_types.h" #ifndef POINTER_T # define POINTER_T typedef void * pointer_T; #endif #ifndef TRUE # define TRUE (1) #endif #ifndef FALSE # define FALSE (0) #endif #endif Top of rtwtypes.h for ERT targets: #ifndef __RTWTYPES_H__ #define __RTWTYPES_H__ #ifndef __TMWTYPES__ #define __TMWTYPES__ 10-7 10 Source Code Generation #include /*=======================================================================* * Target hardware information * Device type: 32-bit Generic * Number of bits: * char: 8 long: 32 short: int: 32 native word size: 16 32 * Byte ordering: Unspecified * Signed integer division rounds to: Undefined * Shift right on a signed integer as arithmetic shift: on *=======================================================================*/ /* This ID is used to detect inclusion of an incompatible rtwtypes.h */ #define RTWTYPES_ID_C08S16I32L32N32F1 /*=======================================================================* * Fixed width word size data types: * * int8_T, int16_T, int32_T - signed 8, 16, or 32 bit integers * * uint8_T, uint16_T, uint32_T - unsigned 8, 16, or 32 bit integers * * real32_T, real64_T - 32 and 64 bit floating point numbers * *=======================================================================*/ typedef signed char int8_T; typedef unsigned char uint8_T; typedef short int16_T; typedef unsigned short uint16_T; typedef int int32_T; typedef unsigned int uint32_T; typedef float real32_T; typedef double real64_T; . . . For GRT and ERT targets, the location of rtwtypes.h depends on whether the build uses the shared utilities location. If you use a shared location, the Simulink Coder build process places rtwtypes.h in slprj/target/_sharedutils; otherwise, it places rtwtypes.h in the standard build folder (model_target_rtw). See “Logging” on page 15-105 for more information on when and how to use the shared utilities location. 10-8 Generated Source Files and File Dependencies The header file rtwtypes.h should be included by source files that use Simulink Coder type names or other Simulink Coder definitions. A typical example is for files that declare variables using a Simulink Coder data type, for example, uint32_T myvar;. A source file that is intended to be used by the Simulink Coder product and by a Simulink S-function can leverage the preprocessor macro MATLAB_MEX_FILE, which is defined by the mex function: #ifdef MATLAB_MEX_FILE #include "tmwtypes.h" #else #include "rtwtypes.h" #endif A source file meant to be used as the Simulink Coder main.c (or .cpp) file would also include rtwtypes.h without any preprocessor checks. #include "rtwtypes.h" Custom source files that are generated using the Target Language Compiler can also emit these include statements into their generated file. model.h The header file model.h declares model data structures and a public interface to the model entry points and data structures. This header file also provides an interface to the real-time model data structure (model_M) by using access macros. If your code interfaces to model functions or model data structures, as illustrated below, you should include model.h: • Exported global signals extern int32_T INPUT; /* ' /In' */ • Global structure definitions /* Block parameters (auto storage) */ extern Parameters_mymodel mymodel_P; • RTM macro definitions 10-9 10 Source Code Generation #ifndef rtmGetSampleTime # define rtmGetSampleTime(rtm, idx) ((rtm)->Timing.sampleTimes[idx]) #endif • Model entry point functions (ERT example) extern void mymodel_initialize(void); extern void mymodel_step(void); extern void mymodel_terminate(void); A Simulink Coder target’s main.c (or .cpp) file should include model.h. If the main.c (or .cpp) file is generated from a TLC script, the TLC source can include model.h using: #include "% .h" If main.c or main.cpp is a static source file, a fixed header filename can be used, rtmodel.h for GRT or autobuild.h for ERT. These files include the model.h header file: #include "model.h" /* If main.c is generated */ or #include "rtmodel.h" /* If static main.c is used with GRT */ or #include "autobuild.h" /* If static main.c is used with ERT */ Other custom source files might need to include model.h to interface to model data, for example exported global parameters or signals. The model.h file itself can have additional header dependencies, as listed in the tables System Header Files on page 10-11 and Simulink® Coder™ Header Files on page 10-13, due to requirements of generated code. 10-10 Generated Source Files and File Dependencies System Header Files Header File Purpose GRT Targets ERT Targets Defines math constants Not included Included when generated code honors the Stop time solver configuration parameter due to one of the following Simulink Coder interface option settings: • MAT-file logging selected • Interface set to External mode Provides floating-point math functions Included when the model contains a floating-point math function Included when the model contains a floating-point math function that is not overridden by an entry in the code replacement library (CRL) selected for the model For more information about CRLs, see “Selecting and Viewing Code Replacement Libraries” on page 9-61 in this chapter, and the CRL chapter in the Embedded Coder User’s Guide. Defines NULL Included when the model contains a utility function that needs it Included when the model contains a utility function that needs it Provides file I/O functions Included when the model includes a To File block Included when the model includes a To File block, or you open the Configuration Parameters dialog box and select Code Generation > Interface > MAT-file logging. See “MAT-file logging”. 10-11 10 Source Code Generation System Header Files (Continued) Header File Purpose GRT Targets ERT Targets Provides utility functions such as div() and abs() Included when the model includes • A Stateflow chart Included when the model includes • A Stateflow chart and you select the Support floating-point numbers Simulink Coder interface configuration parameter • A Math Function block configured for mod() or rem(), which generate calls to div() Provides memory functions such as memset() and memcpy() Always included due to use of memset() in model initialization code • A Math Function block configured for mod() or rem(), which generate calls to div() Included when block or model initialization code calls memcpy() or memset() For a list of relevant blocks, enter showblockdatatypetable in the MATLAB Command Window and look for blocks with the N2 note. To omit calls to memset() from model initialization code, select the Remove root level I/O zero initialization and Remove internal data zero initialization optimization configuration parameters. 10-12 Generated Source Files and File Dependencies Simulink Coder Header Files Header File Purpose GRT Targets ERT Targets dt_info.h Defines data structures for external mode Included when you configure a model for external mode Included when you configure a model for external mode ext_work.h Defines external mode functions Included when you configure a model for external mode Included when you configure a model for external mode fixedpoint.h Provides fixed-point support for noninlined S-functions Always included Included when either of the following conditions exists: • The model uses noninlined S-functions • You select the Simulink Coder interface configuration parameter Classic call interface model_types.h Defines model-specific data types Always included Always included rt_logging.h Supports MAT-file logging Always included Included when you open the Configuration Parameters dialog box and select Code Generation > Interface > MAT-file logging. See “MAT-file logging”. rt_nonfinite.h Provides support for nonfinite numbers in the generated code Always included Included when you select one of the following Simulink Coder interface configuration parameters: • MAT-file logging • Support non-finite numbers (and the generated code requires nonfinite numbers) 10-13 10 Source Code Generation Simulink Coder Header Files (Continued) Header File Purpose rtw_continuous.h Supports continuous time rtw_extmode.h Supports external mode rtw_matlogging.h Supports MAT-file logging GRT Targets ERT Targets Included when you select the Simulink Coder interface simstruc_types.h configuration parameter Support continuous time and simstruc.h is not already included Always included by Always included by Included when you configure the model for external mode simstruc_types.h and simstruc.h is not already included Included by Included by rtw_logging.h simstruc_types.h and rtw_logging.h rtw_solver.h Supports continuous states Included when you select the Simulink Coder interface simstruc_types.h configuration parameter Support floating-point numbers and simstruc.h is not already included rtwtypes.h Defines Simulink Coder data types; generated file Always included; use the complete version of the file, which includes tmwtypes.h and Always included by simstruc_types.h (see simstruc_types.h for dependencies) 10-14 Always included; use the complete or optimized version of the file as explained in “rtwtypes.h” on page 10-6 Generated Source Files and File Dependencies Simulink Coder Header Files (Continued) Header File Purpose GRT Targets ERT Targets simstruc.h Provides support for calling noninlined S-functions that use the Simstruct definition; also includes limits.h, string.h, tmwtypes.h, and Always included Included when either of the following conditions exists: • The model uses noninlined S-functions • You select the Simulink Coder interface configuration parameter Classic call interface simstruc_types.h simstruc_types.h Provides definitions used by generated code and includes the header files Always included with rtwtypes.h Not included; rtwtypes.h contains definitions and model.h contains header files rtw_matlogging.h, rtw_extmode.h, rtw_continuous.h, rtw_solver.h, and sysran_types.h sysran_types.h Supports external mode Always included by Included when you configure the model for external mode simstruc_types.h and simstruc.h is not already included Note Header file dependencies noted in the preceding table apply to the system target files grt.tlc and ert.tlc. Targets derived from these base targets may have additional header dependencies. Also, code generation for blocks from blocksets, embedded targets, and custom S-functions may introduce additional header dependencies. 10-15 10 Source Code Generation Dependencies of the Generated Code The Simulink Coder software can directly build standalone executables for the host system such as when using the GRT target. Several processor- and operating system-specific targets also provide automated builds using a cross-compiler. All of these targets are typically makefile-based interfaces for which the Simulink Coder software provides a “Template MakeFile (TMF) to makefile” conversion capability. Part of this conversion process is to include, in the generated makefile, source file, header file, and library file information (the dependencies) for a compilation. In other instances, the generated model code needs to be integrated into a specific application. Or, it may be desired to enter the generated files and any file dependencies into a configuration management system. This section discusses the various aspects of the generated code dependencies and how to determine them. Typically, the generated code for a model consists of a small set of files: • model.c or model.cpp • model.h • model_data.c or model_data.cpp • model_private.h • rtwtypes.h These are generated in the build folder for a standalone model or a subfolder under the slprj folder for a model reference target. There is also a top-level main.c (or .cpp) file that calls the top model functions to execute the model. main.c (or .cpp) is a static (not generated) file (such as grt_main.c or grt_main.cpp for GRT-based targets), and is either a static file (ert_main.c or ert_main.cpp) or is dynamically generated for ERT-based targets. The preceding files also have dependencies on other files, which occur due to: • Including other header files • Using macros declared in other header files • Calling functions declared in other source files 10-16 Generated Source Files and File Dependencies • Accessing variables declared in other source files These dependencies are introduced for a number of reasons such as: • Blocks in a model generate code that makes function calls. This can occur in several forms: - The called functions are declared in other source files. In some cases such as a blockset, these source file dependencies are typically managed by compiling them into a library file. - In other cases, the called functions are provided by the compilers own run-time library, such as for functions in the ANSI12 C header, math.h. - Some function dependencies are themselves generated files. Some examples are for fixed-point utilities and nonfinite support. These dependencies are referred to as shared utilities. The generated functions can appear in files in the build folder for standalone models or in the _sharedutils folder under the slprj folder for builds that involve model reference. • Models with continuous time require solver source code files. • Simulink Coder options such as external mode, C API, and MAT-file logging are examples that trigger additional dependencies. • Specifying custom code can introduce dependencies. Providing the Dependencies The Simulink Coder product provides several mechanisms for feeding file dependency information into the Simulink Coder build process. The mechanisms available to you depend on whether your dependencies are block based or are model or target based. For block dependencies, consider using • S-functions and blocksets - folders that contain S-function MEX-files used by a model are added to the header include path. 12. ANSI® is a registered trademark of the American National Standards Institute, Inc. 10-17 10 Source Code Generation - Makefile rules are created for these folders to allow source code to be found. - For S-functions that are not inlined with a TLC file, the S-function source filename is added to the list of sources to compile. - The S-Function block parameter SFunctionModules provides the ability to specify additional source filenames. - The rtwmakecfg.m mechanism provides further capability in specifying dependencies. See “Use rtwmakecfg.m API to Customize Generated Makefiles” on page 14-124 for more information. For more information on applying these approaches to legacy or custom code integration, see “Integrate External Code Using Legacy Code Tool” on page 14-28. • S-Function Builder block, which provides its own GUI for specifying dependency information For model- or target-based dependencies, such as custom header files, consider using • The Code Generation > Custom Code pane of the Configuration Parameters dialog box, which provides the ability to specify additional libraries, source files, and include folders. • TLC functions LibAddToCommonIncludes() and LibAddToModelSources(), which allow you to specify dependencies during the TLC phase. See “LibAddToCommonIncludes(incFileName)” and “LibAddSourceFileCustomSection (file, builtInSection, newSection)” in the Target Language Compiler documentation for details. The Embedded Coder product also provides a TLC-based customization template capability for generating additional source files. Makefile Considerations As previously mentioned, Simulink Coder targets are typically makefile based and the Simulink Coder product provides a “Template MakeFile (TMF) to makefile” conversion capability. The template makefile contains a token expansion mechanism in which the build process expands different tokens in the makefile to include the additional dependency information. The resulting 10-18 Generated Source Files and File Dependencies makefile contains the complete dependency information. See “Customize Template Makefiles” on page 24-75 for more information on working with template makefiles. The generated makefile contains the following information: • Names of the source file dependencies (by using various SRC variables) • folders where source files are located (by using unique rules) • Location of the header files (by using the INCLUDE variables) • Precompiled library dependencies (by using the LIB variables) • Libraries which need to be compiled and created (by using rules and the LIB variables) A property of make utilities is that the specific location for a given source C or C++ file does not need to be specified. If a rule exists for that folder and the source filename is a prerequisite in the makefile, the make utility can find the source file and compile it. Similarly, the C or C++ compiler (preprocessor) does not require absolute paths to the headers. Given the name of header file by using an #include directive and an include path, it is able to find the header. The generated C or C++ source code depends on this standard compiler capability. Also, libraries are typically created and linked against, but occlude the specific functions that are being used. Although the build process succeeds and can create a minimum-size executable, these properties can make it difficult to manually determine the minimum list of file dependencies along with their fully qualified paths. The makefile can be used as a starting point to determining the dependencies that the generated model code has. An additional approach to determining the dependencies is by using linker information, such as a linker map file, to determine the symbol dependencies. The location of Simulink Coder and blockset source and header files is provided below to assist in locating the dependencies. 10-19 10 Source Code Generation Simulink Coder Static File Dependencies Several locations in the MATLAB folder tree contain static file dependencies specific to the Simulink Coder product: • matlabroot/rtw/c/src/ This folder has subfolders and contains additional files that may need to be compiled. Examples include solver functions (for continuous time support), external mode support files, C API support files, and S-function support files. Source files in this folder are included into the build process using in the SRC variables of the makefile. • matlabroot/rtw/extern/include/*.h • matlabroot/simulink/include/*.h These folders contain additional header file dependencies such as tmwtypes.h, simstruc_types.h, and simstruc.h. Note For ERT-based targets, several header dependencies from the above locations can be avoided. ERT-based targets generate the minimum set of type definitions, macros, and so on, in the file rtwtypes.h. Blockset Static File Dependencies Blockset products leverage the rtwmakecfg.m mechanism to provide the Simulink Coder software with dependency information. As such, the rtwmakecfg.m file provided by the blockset contains the listing of include path and source path dependencies for the blockset. Typically, blocksets create a library from the source files, which the generated model code can then link against. The libraries are created and identified using the rtwmakecfg.m mechanism. To locate the rtwmakecfg.m files for blocksets in your MATLAB installed tree, use the following command: >> which -all rtwmakecfg.m For example, for the DSP System Toolbox product, the which command displays a path similar to the following: 10-20 Generated Source Files and File Dependencies C:\Program Files\MATLAB\toolbox\dspblks\dspmex\rtwmakecfg.m If the model being compiled uses one or more of the blocksets listed by the which command, you can determine folder and file dependency information from the respective rtwmakecfg.m file. For example, here is an excerpt of the rtwmakecfg.m file for the DSP System Toolbox product. function makeInfo=rtwmakecfg() %RTWMAKECFG adds include and source directories to RTW make files. % makeInfo=RTWMAKECFG returns a structured array containing build info. % Please refer to the rtwmakecfg API section in the Simulink Coder % documentation for details on the format of this structure. . . . makeInfo.includePath = { ... fullfile(matlabroot,'toolbox','dspblks','include') }; makeInfo.sourcePath = {}; Specify Include Paths in Simulink Coder Generated Source Files You can add #include statements to generated code. Such references can come from several sources, including TLC scripts for inlining S-functions, custom storage classes, bus objects, and data type objects. The included files typically consist of header files for legacy code or other customizations. Additionally, you can specify compiler include paths with the -I compiler option. The Simulink Coder build process uses the specified paths to search for included header files. Usage scenarios for the generated code include, but are not limited to, the following: • Simulink Coder generated code is compiled with a custom build process that requires an environment-specific set of #include statements. In this scenario, the code generator is likely invoked with the Generate code only check box selected. Consider using fully qualified paths, relative 10-21 10 Source Code Generation paths, or just the header filenames in the #include statements, and additionally leverage include paths. • The generated code is compiled using the Simulink Coder build process. In this case, compiler include paths (-I) can be provided to the Simulink Coder build process in several ways: - The Code Generation > Custom Code pane of the Configuration Parameters dialog box allows you to specify additional include paths. The include paths are propagated into the generated makefile when the template makefile (TMF) is converted to the actual makefile. - The rtwmakecfg.m mechanism allows S-functions to introduce additional include paths into the Simulink Coder build process. The include paths are propagated when the template makefile (TMF) is converted to the actual makefile. - When building a custom Simulink Coder target that is makefile-based, the desired include paths can be directly added into the targets template makefile. - A USER_INCLUDES make variable that specifies a folder in which the Simulink Coder build process should search for included files can be specified on the Simulink Coder make command. For example, make_rtw USER_INCLUDES=-Id:\work\feature1 The user includes are passed to the command-line invocation of the make utility, which will add them to the overall flags passed to the compiler. Recommended Approaches The following are recommended approaches for using #include statements and include paths in conjunction with the Simulink Coder build process to generate code that remains portable and minimizes compatibility problems with future versions. Assume that additional header files are located at c:\work\feature1\foo.h c:\work\feature2\bar.h 10-22 Generated Source Files and File Dependencies • A simple approach is to include in the #include statements only the filename, such as #include "foo.h" #include "bar.h" Then, the include path passed to the compiler should contain all folders in which the headers files exist: cc -Ic:\work\feature1 -Ic:\work\feature2 ... • A second recommended approach is to use relative paths in #include statements and provide an anchor folder for these relative paths using an include path, for example, #include "feature1\foo.h" #include "feature2\bar.h" Then specify the anchor folder (for example \work) to the compiler: cc -Ic:\work ... Folder Dependencies to Avoid When using the Simulink Coder build process, avoid dependencies on its build and project folder structure, such as the model_ert_rtw build folder or the slprj project folder. Thus, the #include statements should not just be relative to where the generated source file exists. For example, if your MATLAB current working folder is c:\work, a generated model.c source file would be generated into a subfolder such as c:\work\model_ert_rtw\model.c The model.c file would have #include statements of the form #include "..\feature1\foo.h" #include "..\feature2\bar.h" However, as this creates a dependency on the Simulink Coder folder structure, you should instead use one of the approaches described above. 10-23 10 Source Code Generation Files and Folders Created by Build Process The following sections discuss • “Files Created During the Build Process” on page 10-24 • “Folders Used During the Build Process” on page 10-28 Files Created During the Build Process This section lists model.* files created during the code generation and build process for the GRT and GRT malloc targets when used with stand-alone models. Additional folders and files are created to support shared utilities and model references. The build process derives many of the files from the model file you create with Simulink. You can think of the model file as a very high-level programming language source file. Note Files generated by the Embedded Coder build process are packaged slightly differently. Depending on model architectures and code generation options, the Simulink Coder build process might generate other files. Descriptions of the principal generated files follow. Note that these descriptions use the generic term model for the model name: • model.rtw An ASCII file, representing the compiled model, generated by the Simulink Coder build process. This file is analogous to the object file created from a high-level language source program. By default, the Simulink Coder build process deletes this file when the build process is complete. However, you can choose to retain the file for inspection. • model.c C source code that corresponds to the model file and is generated by the Target Language Compiler. This file contains - 10-24 Include files model.h and model_private.h Files and Folders Created by Build Process - All data except data placed in model_data.c Model-specific scheduler code Model-specific solver code Model registration code Algorithm code Optional GRT wrapper functions • model.h Defines model data structures and a public interface to the model entry points and data structures. Also provides an interface to the real-time model data structure (model_rtM) via access macros. model.h is included by subsystem .c files in the model. It includes - Exported Simulink data symbols Exported Stateflow machine parented data Model data structures, including rtM Model entry point functions • model_private.h Contains local define constants and local data required by the model and subsystems. This file is included by the generated source files in the model. You might need to include model_private.h when interfacing legacy hand-written code to a model. See “Header Dependencies When Interfacing Legacy/Custom Code with Generated Code” on page 10-6 for more information. This header file contains - Imported Simulink data symbols Imported Stateflow machine parented data Stateflow entry points Simulink Coder details (various macros, enums, and so forth that are private to the code) • model_types.h Provides forward declarations for the real-time model data structure and the parameters data structure. These structure might be used by function 10-25 10 Source Code Generation declarations of reusable functions. model_types.h is included by all the generated header files in the model. • model_data.c A conditionally generated C source code file containing declarations for the parameters data structure and the constant block I/O data structure, and any zero representations for structure data types that are used in the model. If these data structures are not used in the model, model_data.c is not generated. Note that these structures are declared extern in model.h. When present, this file contains - Constant block I/O parameters - Constant parameters Include files model.h and model_private.h Definitions for the zero representations for any user-defined structure data types used by the model • model.exe (Microsoft Windows platforms) or model (UNIX platforms), generated in the current folder, not in the build folder Executable program file created under control of the make utility by your development system (unless you have explicitly specified that Simulink Coder generate code only and skip the rest of the build process) • model.mk Customized makefile generated by the Simulink Coder build process. This file builds an executable program file. • rtmodel.h Contains #include directives required by static main program modules such as grt_main.c and grt_malloc_main.c. Since these modules are not created at code generation time, they include rt_model.h to access model-specific data structures and entry points. If you create your own main program module, take care to include rtmodel.h. • rtwtypes.h For GRT targets, a header file that includes simstruc_types.h, which, in turn, includes tmwtypes.h. For Embedded Coder ERT targets, rtwtypes.h provides the defines, enums, and so on, instead of including tmwtypes.h and simstruc_types.h. The rtwtypes.h file generated for 10-26 Files and Folders Created by Build Process ERT is an optimized (reduced) file based on the settings provided with the model that is being built. See “Header Dependencies When Interfacing Legacy/Custom Code with Generated Code” on page 10-6 in the Simulink Coder documentation for more information. • rt_nonfinite.c C source file that declares and initializes global nonfinite values for inf, minus inf, and nan. Nonfinite comparison functions are also provided. This file is always generated for GRT-based targets and optionally generated for other targets. • rt_nonfinite.h C header file that defines extern references to nonfinite variables and functions. This file is always generated for GRT-based targets and optionally generated for other targets. • rtw_proj.tmw Simulink Coder file generated for the make utility to use to determine when to rebuild objects when the name of the current Simulink Coder project changes • model.bat Windows batch file used to set up the compiler environment and invoke the make command • modelsources.txt List of additional sources that should be included in the compilation. Optional files: • model_targ_data_map.m MATLAB language file used by external mode to initialize the external mode connection • model_dt.h C header file used for supporting external mode. Declares structures that contain data type and data type transition information for generated model data structures. • subsystem.c 10-27 10 Source Code Generation C source code for each noninlined nonvirtual subsystem or copy thereof when the subsystem is configured to place code in a separate file • subsystem.h C header file containing exported symbols for noninlined nonvirtual subsystems. Analogous to model.h. • model_capi.h, model_capi.c Header and sources file that contain data structures that describe the model’s signals, states, and parameters without using external mode. See “Data Interchange Using the C API” on page 15-137 in Simulink Coder User’s Guide for more information. • rt_sfcn_helper.h, rt_sfcn_helper.c Header and source files providing functions usec by noninlined S-functions in a model. The functions rt_CallSys, rt_enableSys, and rt_DisableSys are used when noninlined S-functions call downstream function-call subsystems. In addition, when you select the Create code generation report check box, the Simulink Coder software generates a set of HTML files (one for each source file plus a model_contents.html index file) in the html subfolder within your build folder. The above source files have dependency relationships, and there are additional file dependencies that you might need to take into account. These are described in “Generated Source Files and File Dependencies” on page 10-4 in the Simulink Coder documentation. Folders Used During the Build Process The Simulink Coder build process places output files in three folders: • The working folder If you choose to generate an executable program file, the Simulink Coder build process writes the file model.exe (Windows) or model (UNIX) to your working folder. • The build folder — model_target_rtw 10-28 Files and Folders Created by Build Process A subfolder within your working folder. The build folder name is model_target_rtw, where model is the name of the source model and target is the selected target type (for example, grt for the generic real-time target). The build folder stores generated source code and all other files created during the build process (except the executable program file). • Project folder — slprj A subfolder within your working folder. When models referenced via Model blocks are built for simulation or Simulink Coder code generation, files are placed in slprj. The Embedded Coder configuration has an option that places generated shared code in slprj without the use of model reference. Subfolders in slprj provide separate places for simulation code, some Simulink Coder code, utility code shared between models, and other files. Of particular importance to Simulink Coder users are: - Header files from models referenced by this model slprj/target/model/referenced_model_includes - Model reference Simulink Coder target files slprj/target/model - MAT-files used during code generation of model reference Simulink Coder target and stand-alone code generation slprj/target/model/tmwinternal - Shared (fixed-point) utilities slprj/target/_sharedutils See “Work with Project Folders” on page 3-14 for more information on organizing your files with respect to project folders. The build folder always contains the generated code modules model.c, model.h, and the generated makefile model.mk. Depending on the target, code generation, and build options you select, the build folder might also include • model.rtw • Object files (.obj or .o) 10-29 10 Source Code Generation • Code modules generated from subsystems • HTML summary reports of files generated (in the html subfolder) • TLC profiler report files • Block I/O, state, and parameter tuning information file (model_capi.c) • Simulink Coder project (model.tmw) files For additional information about using project folders, see “Project Folder Structure for Model Reference Targets” on page 3-16 and “Customize Build to Use Shared Utility Code” on page 22-34 in the Simulink Coder documentation. 10-30 How Code Is Generated From a Model How Code Is Generated From a Model In this section... “Model Compilation” on page 10-31 “Code Generation” on page 10-31 Model Compilation The build process begins with the Simulink software compiling the block diagram. During this stage, Simulink • Evaluates simulation and block parameters • Propagates signal widths and sample times • Determines the execution order of blocks within the model • Computes work vector sizes, such as those used by S-functions. (For more information about work vectors, see “DWork Vector Basics”). When Simulink completes this processing, it compiles an intermediate representation of the model. This intermediate description is stored in a language-independent format in the ASCII file model.rtw. The model.rtw file is the input to the next stage of the build process. For a general description of the model.rtw file format, see “model.rtw file”. Code Generation The Simulink Coder code generator uses the Target Language Compiler (TLC) and a supporting TLC function library to transform the intermediate model description stored in model.rtw into target-specific code. The target language compiled by the TLC is an interpreted programming language designed to convert a model description to code. The TLC executes a TLC program comprising several target files (.tlc scripts). The TLC scripts specify how to generate code from the model, using the model.rtw file as input. The TLC 1 Reads the model.rtw file 10-31 10 Source Code Generation 2 Compiles and executes commands in a system target file The system target file is the entry point or main file. You select it from those available on the MATLAB path with the system target file browser or you can type the name of any such file on your system prior to building. 3 Compiles and executes commands in block-level target files For blocks in the Simulink model, there is a corresponding target file that is either dynamically generated or statically provided. Note The Simulink Coder software executes all user-written S-function target files, but optionally executes block target files for Simulink blocks. 4 Writes a source code version of the Simulink block diagram 10-32 Code Generation of Matrices and Arrays Code Generation of Matrices and Arrays In this section... “Simulink® Coder™ Matrix Parameters” on page 10-34 “Internal Data Storage for Complex Number Arrays” on page 10-36 MATLAB, Simulink, and Simulink Coder software store matrix data and arrays(1–D, 2–D, ...) in column-major format as a vector. Column-major format orders elements in a matrix starting from the first column, top to bottom, and then moving on to the next column. For example, the following 3x3 matrix: A = 1 4 7 2 5 8 3 6 9 translates to an array of length 9 in the following order: A(1) A(2) A(3) A(4) A(5) = = = = = A(1,1) A(2,1) A(3,1) A(1,2) A(2,2) = = = = = 1; 4; 7; 2; 5; and so on. In column-major format, the next element of an array in memory is always accessed by incrementing the first index of the array. For example, these element pairs are stored sequentially in memory: A(i) and A(i+1), B(i,j) and B(i+1,j), C(i,j,k) and C(i+1,j,k). For more information on the internal representation of MATLAB data, see “MATLAB Data” in the MATLAB External Interfaces document. Code generation software uses column-major format for several reasons: • The world of signal and array processing is largely column major: MATLAB, LAPack, Fortran90, DSP libraries. 10-33 10 Source Code Generation • A column is equivalent to a channel in frame-based processing. In this case, column-major storage is more efficient. • A column major array is self-consistent with its component submatrices: - A column major 2–D array is a simple concatenation of 1–D arrays. - Row-major n-D arrays have their stride of 1 for the highest dimension. Any submatrix manipulations are typically accessing a scattered data set in memory, which does not allow for efficient indexing. A column major 3–D array is a simple concatenation of 2–D arrays. The stride of the first dimension is always 1 element, where the stride is the number of memory locations to index to the next element in the same dimension. The stride of the n’th dimension element is always the product of sizes of the lower dimensions. Simulink Coder Matrix Parameters The compiled model file, model.rtw, represents matrices as strings in MATLAB syntax, with no implied storage format. This format allows you to copy the string out of an .rtw file and paste it into a MATLAB file and have it recognized by MATLAB. Simulink Coder software declares Simulink block matrix parameters as scalar or 1-D array variables real_T scalar; real_T mat[ nRows * nCols ]; where real_T can be any of the data types supported by Simulink, and matches the variable type given in the model file. For example, the 3-by-3 matrix in the 2–D Look-Up Table block 1 4 7 2 5 8 3 6 9 is stored in model.rtw as Parameter { 10-34 Code Generation of Matrices and Arrays Name "OutputValues" Value Matrix(3,3) [[1.0, 2.0, 3.0]; [4.0, 5.0, 6.0]; [7.0, 8.0, 9.0];] String "t" StringType "Variable" ASTNode { IsNonTerminal 0 Op SL_NOT_INLINED ModelParameterIdx 3 } } and results in this definition in model.h typedef struct Parameters_tag { real_T s1_Look_Up_Table_2_D_Table[9]; /* Variable:s1_Look_Up_Table_2_D_Table * External Mode Tunable:yes * Referenced by block: * /Look-Up Table (2-D */ [ ... other parameter definitions ... ] } Parameters; The model.h file declares the actual storage for the matrix parameter and you can see that the format is column-major. 1 2 3 4 5 6 7 8 9 Parameters model_P = { 10-35 10 Source Code Generation /* 3 x 3 matrix s1_Look_Up_Table_2_D_Table */ { 1.0, 4.0, 7.0, 2.0, 5.0, 8.0, 3.0, 6.0, 9.0 }, [ ... other parameter declarations ...] }; Note C typically uses row-major format, while MATLAB and Simulink use column-major format. The code generation software cannot be configured to generate code with row-major ordering. If you are integrating other C code with the generated code, you might need to transpose the data into column-major format as a 1–D array. Internal Data Storage for Complex Number Arrays Simulink and Simulink Coder internal data storage formatting differs from MATLAB internal data storage formatting only in the storage of complex number arrays. In MATLAB, the real and imaginary parts are stored in separate arrays. In the Simulink and Simulink Coder products they are stored in an "interleaved" format, where the numbers in memory alternate real, imaginary, real, imaginary, and so forth. This convention allows efficient implementations of small signals on Simulink lines and for Mux blocks and other "virtual" signal manipulation blocks (i.e., they don’t actively copy their inputs, merely the references to them). 10-36 Shared Utility Code Shared Utility Code In this section... “About Shared Utility Code” on page 10-37 “Controlling Shared Utility Code Placement” on page 10-38 “rtwtypes.h and Shared Utility Code” on page 10-38 “Incremental Shared Utility Code Generation and Compilation” on page 10-39 “Shared Utility Checksum” on page 10-39 “Shared Fixed-Point Utility Functions” on page 10-41 “Share User-Defined Data Types Across Models” on page 10-43 About Shared Utility Code Blocks in a model can require common functionality to implement their algorithm. In many cases, it is most efficient to modularize this functionality into standalone support or helper functions, rather than inlining the code for the functionally for each block instance. Typically, functions that can have multiple callers are packaged into a library. Traditionally, such functions are defined statically, that is, the function source code exists in a file before you use the Simulink Coder software to generate code for your model. In other cases, several model- and block-specific properties can affect which functions are used and their behavior. Additionally, these properties can affect type definitions (for example, typedef) in shared utility header files. Since there are many possible combinations of properties that determine unique behavior, it is not practical to statically define all possible function files before code generation. Instead, you can use the Simulink Coder shared utility mechanism, which generates support functions during code generation process. 10-37 10 Source Code Generation Controlling Shared Utility Code Placement You control the shared utility code placement mechanism with the Shared code placement option on the Code Generation > Interface pane of the Configuration Parameters dialog box. By default, the option is set to Auto. For this setting, if the model being built does not include any Model blocks, the Simulink Coder build process places any code required for fixed-point and other utilities in one of the following: • The model.c or model.cpp file • In a separate file in the Simulink Coder build folder (for example, vdp_grt_rtw) Thus, the code is specific to the model. If a model does contain Model blocks, the Simulink Coder build process creates and uses a shared utilities folder within slprj. Model reference builds require the use of shared utilities. The naming convention for shared utility folders is slprj/target/_sharedutils, where target is sim for simulations with Model blocks or the name of the system target file for Simulink Coder target builds. Some examples follow: slprj/sim/_sharedutils % folder used with simulation slprj/grt/_sharedutils % folder used with grt.tlc STF slprj/ert/_sharedutils % folder used with ert.tlc STF slprj/mytarget/_sharedutils % folder used with mytarget.tlc STF To force a model build to use the slprj folder for shared utility generation, even when the current model contains no Model blocks, set the Shared code placements option to Shared location. This forces the Simulink Coder build process to place utilities under the slprj folder rather than in the normal Simulink Coder build folder. This setting is useful when you are manually combining code from several models, as it prevents symbol collisions between the models. rtwtypes.h and Shared Utility Code The generated header file rtwtypes.h provides defines, enumerations, and so on. The location of this file is controlled by whether the build process is using the shared utilities folder. Typically, the Simulink Coder build 10-38 Shared Utility Code process places rtwtypes.h in the standard build folder, model_target_rtw. However, if a shared folder is required, the product places rtwtypes.h in slprj/target/_sharedutils. Incremental Shared Utility Code Generation and Compilation As explained in “Controlling Shared Utility Code Placement” on page 10-38, you can specify that C source files, which contain function definitions, and header files, which contain macro definitions, be generated in a shared utilities folder. For the purpose of this discussion, the term functions means functions and macros. A shared function can be used by blocks within the same model and by blocks in different models when using model reference or when building multiple standalone models from the same start build folder. However, the Simulink Coder software generates the code for a given function only once for the block that first triggers code generation. As the product determines the need to generate function code for subsequent blocks, it performs a file existence check. If the file exists, the function is not regenerated. Thus, the shared utility code mechanism requires that a given function and file name represent the same functional behavior regardless of which block or model generates the function. To satisfy this requirement: • Model properties that affect function behavior are included in a shared utility checksum or affect the function and file name. • Block properties that affect the function behavior also affect the function and file name. During compilation, makefile rules for the shared utilities folder are configured to compile only new C files, and incrementally archive the object file into the shared utility library, rtwshared.lib or rtwshared.a. Thus, incremental compilation is also done. Shared Utility Checksum As explained in “Incremental Shared Utility Code Generation and Compilation” on page 10-39, the Simulink Coder software uses the shared utilities folder when you explicitly configure a model to use the 10-39 10 Source Code Generation shared location or the model contains Model blocks. During the code generation process, if relative to the current folder, the configuration file slprj/target/_sharedutils/checksummap.mat exists, the product reads that file and makes sure that the current model being built has identical settings for the required model properties. If mismatches occur between the properties defined in checksummap.mat and the current model properties, a Warning dialog appears. The following table lists properties that must match for the shared utility checksum. 10-40 Category Properties Hardware Implementation configuration properties get_param(bdroot, 'TargetShiftRightIntArith') get_param(bdroot, 'TargetEndianess') get_param(bdroot, 'ProdEndianess') get_param(bdroot, 'TargetBitPerChar') get_param(bdroot, 'TargetBitPerShort') get_param(bdroot, 'TargetBitPerInt') get_param(bdroot, 'TargetBitPerLong') get_param(bdroot, 'ProdHWWordLengths') get_param(bdroot, 'TargetWordSize') get_param(bdroot, 'ProdWordSize') get_param(bdroot, 'TargetHWDeviceType') get_param(bdroot, 'ProdHWDeviceType') Shared Utility Code Category Properties get_param(bdroot, 'TargetIntDivRoundTo') get_param(bdroot, 'ProdIntDivRoundTo' Additional configuration properties get_param(bdroot, 'TargetLibSuffix') get_param(bdroot, 'TargetLang') get_param(bdroot, 'TemplateMakefile') ERT target properties get_param(bdroot, 'PurelyIntegerCode') get_param(bdroot, 'SupportNonInlinedSFcns' Platform property Return value of the computer command Shared Fixed-Point Utility Functions An important set of generated functions that are placed in the shared utility folder are the fixed-point support functions. Based on model and block properties, there are many possible versions of fixed-point utilities functions that make it impractical to provide a complete set as static files. Generating only the required fixed-point utility functions during the code generation process is an efficient alternative. The shared utility checksum mechanism makes sure that several critical properties are identical for all models that use the shared utilities. For the fixed-point functions, there are additional properties that affect function behavior. These properties are coded into the functions and file names to maintain requirements. The additional properties include Category Function/Property Block properties • Fixed-point operation being performed by the block • Fixed-point data type and scaling (Slope, Bias) of function inputs and outputs • Overflow handling mode (Saturation, Wrap) • Rounding Mode (Floor, Ceil, Zero) Model properties get_param(bdroot, 'NoFixptDivByZeroProtection') 10-41 10 Source Code Generation The naming convention for the fixed-point utilities is based on the properties as follows: operation + [zero protection] + output data type + output bits + [input1 data] + input1 bits + [input2 data type + input2 bits] + [shift direction] + [saturate mode] + [round mode] Below are examples of generated fixed-point utility files, the function or macro names in the file are identical to the file name without the extension. FIX2FIX_U12_U16.c FIX2FIX_S9_S9_SR99.c ACCUM_POS_S30_S30.h MUL_S30_S30_S16.h div_nzp_s16s32_floor.c div_s32_sat_floor.c For these examples, the respective fields correspond as follows: Operation FIX2FIX FIX2FIX ACCUM_POS MUL div div Zero protection NULL NULL NULL NULL _nzp NULL Output data type _U _S _S _S _s _s Output bits 12 9 30 30 16 32 Input data type _U _S _S _S [and _S] s NULL Input bits 16 9 30 30 [and 16] 32 NULL Shift direction NULL SR99 NULL NULL NULL NULL Saturate mode NULL NULL NULL NULL NULL _sat Round mode NULL NULL NULL NULL _floor _floor Note For the ACCUM_POS example, the output variable is also used as one of the input variables. Therefore, only the output and second input is contained in the file and macro name. For the second div example, both inputs and the output have identical data type and bits. Therefore, only the output is included in the file and function name. 10-42 Shared Utility Code Share User-Defined Data Types Across Models • “About Sharing Data Types” on page 10-43 • “Example: Sharing Simulink Data Type Objects” on page 10-44 • “Example: Sharing Enumerated Data Types” on page 10-45 About Sharing Data Types By default, user-defined data types that are shared among multiple models generate duplicate type definitions in the model_types.h file for each model. However, Simulink Coder software provides the ability to generate user-defined data type definitions into a header file in the _sharedutils folder that can be shared across multiple models, removing the need for duplicate copies of the data type definitions. User-defined data types that you can set up in a shared header file include: • Simulink data type objects that you instantiate from the classes Simulink.AliasType, Simulink.Bus, and Simulink.NumericType. • Enumeration types that you define in MATLAB code The general procedure for setting up user-defined data types to be shared among multiple models is as follows: 1 Define the data type. 2 Set data scope and header file properties that allow the data type to be shared. 3 Use the data type as a signal type in your models. 4 Before generating code for each model, set the Shared code placement parameter on the Code Generation > Interface pane of the Configuration Parameters dialog box to the value Shared location. 5 Generate code. 10-43 10 Source Code Generation Note You can configure the definition of the user-defined data type to occur in a header file that is located in the _sharedutils folder, however user-defined data type names are not used by the shared utility functions that are generated into the _sharedutils folder. Currently, the user-defined data type names are used only by model code located in code folders for each model. For more information, see “Example: Sharing Simulink Data Type Objects” on page 10-44 and “Example: Sharing Enumerated Data Types” on page 10-45. Example: Sharing Simulink Data Type Objects To export a user-defined Simulink data type object for sharing among multiple models. 1 In the base workspace, create a data type object of one of the following classes: • Simulink.AliasType • Simulink.Bus • Simulink.NumericType For example: a = Simulink.AliasType 2 To specify that the data type should be exported to a specified header file, use the data type object property DataScope. Specify the value 'Exported' for the DataScope property. For example: a.DataScope = 'Exported' 3 To specify the name of the header file to which the data type should be exported, use the data type object property HeaderFile. For example: a.HeaderFile = 'a.h' Alternatively, if you leave the HeaderFile value empty, the name of the generated header file defaults to the name of the data type, in this case, a.h. 10-44 Shared Utility Code 4 Use the data type object as a signal type in a model. 5 Before generating code, if you want to generate the header file into the shared utilities folder for sharing definitions between multiple models, set the Shared code placement parameter on the Code Generation > Interface pane of the Configuration Parameters dialog box to the value Shared location. 6 Generate code. Here is an example of the definition code that is generated to a.h in the shared utilities folder: #ifndef RTW_HEADER_a_h_ #define RTW_HEADER_a_h_ #include "rtwtypes.h" typedef double a; #endif /* RTW_HEADER_a_h_ */ To share the data type definition from other models, the alternatives include: • Simply use the same workspace variable in multiple models. If the contents of the data type object are the same, generating code will not regenerate the header file. For example, model A and model B can export the same data type to the same header file in the shared utilities folder. • Define the same data type object in other models, but set it up to import the shared data type definition from the header file. Specify the value 'Imported' for the data type object property DataScope. For example: a = Simulink.AliasType a.DataScope = 'Imported' a.HeaderFile = 'a.h' Example: Sharing Enumerated Data Types To export a user-defined enumerated data type for sharing among multiple models: 1 Define an enumerated data type in MATLAB code. For example, the following MATLAB file defines BasicColors: 10-45 10 Source Code Generation % BasicColors.m classdef(Enumeration) BasicColors < Simulink.IntEnumType enumeration Red(0) Yellow(1) Blue(2) end methods (Static = true) function retVal = getDefaultValue() retVal = BasicColors.Blue; end end end 2 To specify that the data type should be exported to a specified header file, you must override the default getDataScope method of the enumerated class. Specify the value 'Exported' as the getDataScope return value. For example: methods (Static = true) ... function retVal = getDataScope() retVal = 'Exported'; end ... end 3 To specify the name of the header file to which the data type should be exported, you must override the default getHeaderFile method of the enumerated class. Specify a file name as the getHeaderFile return value. For example: methods (Static = true) ... function retVal = getHeaderFile() retVal = 'BasicColors.h'; end ... end 10-46 Shared Utility Code Alternatively, if you leave the return value of the getHeaderFile method unspecified, the name of the generated header file defaults to the name of the data type, in this case, BasicColors.h. 4 Here is BasicColors.m after the data scope and header file changes. % BasicColors.m classdef(Enumeration) BasicColors < Simulink.IntEnumType enumeration Red(0) Yellow(1) Blue(2) end methods (Static = true) function retVal = getDefaultValue() retVal = BasicColors.Blue; end function retVal = getDataScope() retVal = 'Exported'; end function retVal = getHeaderFile() retVal = 'BasicColors.h'; end end end Make sure BasicColors.m is present in the MATLAB path. 5 Use the type enum:BasicColors as a signal type in a model. 6 Before generating code, if you want to generate the header file into the shared utilities folder for sharing definitions between multiple models, set the Shared code placement parameter on the Code Generation > Interface pane of the Configuration Parameters dialog box to the value Shared location. 7 Generate code. Here is an example of the definition code that is generated to BasicColors.h in the shared utilities folder: #ifndef RTW_HEADER_BasicColors_h #define RTW_HEADER_BasicColors_h 10-47 10 Source Code Generation /* Type definition for enum:BasicColors type */ typedef enum { Red = 0, Yellow, Blue } BasicColors; #endif To share the data type definition from other models, the alternatives include: • Simply use the same enumerated type as a signal type in multiple models. If the contents of the enumerated type are the same, generating code will not regenerate the header file. For example, model A and model B can export the same data type to the same header file in the shared utilities folder. • Define the same enumerated type in other models, but set it up to import the shared data type definition from the header file. In the enumerated type definition file, specify the value 'Imported' as the getDataScope return value. For example: methods (Static = true) ... function retVal = getDataScope() retVal = 'Imported'; end ... end 10-48 Generating Code Using Simulink Coder™ Generating Code Using Simulink Coder™ This example shows how to select a target for a Simulink model, generate C code for real-time simulation, and view generated files. 1. Open the model. model='rtwdemo_rtwintro'; open_system(model) 2. Open the Configuration Parameters dialog box from the model editor by clicking Simulation > Configuration Parameters. Alternately, type the following commands at the MATLAB command prompt cs = getActiveConfigSet(model); openDialog(cs); 3. Select the Code Generation node. 10-49 10 Source Code Generation 4. In the Target Selection pane, click Browse to select a target. You can generate code for a particular target environment or purpose. Some built-in targeting options are provided using system target files, which control the code generation process for a target. 10-50 Generating Code Using Simulink Coder™ 5. Select the Generic Real-Time (GRT) target and click Apply. 10-51 10 Source Code Generation Optionally, in the Code Generation Advisor pane set the Select objective field to Execution efficiency or Debugging. Then click Check model... to identify and systematically change parameters to meet your objectives. 6. In the Code Generation pane, click Build to generate code. 7. View the code generation report that appears. The report includes links to model files such as rtwdemo_rtwintro.c and associated utility and header files. 10-52 Generating Code Using Simulink Coder™ The figure below contains a portion of rtwdemo_rtwintro.c 10-53 10 10-54 Source Code Generation Generating Code Using Simulink Coder™ 8. Close the model. bdclose(model) rtwdemoclean; 10-55 10 10-56 Source Code Generation 11 Report Generation • “Reports for Code Generation” on page 11-2 • “HTML Code Generation Report Location” on page 11-3 • “HTML Code Generation Report for Referenced Models” on page 11-4 • “Generate a Code Generation Report” on page 11-5 • “Generate Code Generation Report After Build Process” on page 11-6 • “Open Code Generation Report” on page 11-8 • “Generate Code Generation Report Programmatically” on page 11-10 • “Search in the Code Generation Report” on page 11-11 • “View Code Generation Report in Model Explorer” on page 11-12 • “Package and Share the Code Generation Report” on page 11-14 • “Document Generated Code with Simulink® Report Generator™” on page 11-16 11 Report Generation Reports for Code Generation Simulink Coder software provides an HTML code generation report so that you can view and analyze the generated code. When your model is built, the code generation process produces an HTML file that is displayed in an HTML browser or in the Model Explorer. The code generation report includes: • The Summary section lists version, date, and code generation objectives information. The Configuration settings at the time of code generation link opens a noneditable view of the Configuration Parameters dialog box. The dialog box shows the Simulink model settings at the time of code generation, including TLC options. • The Subsystem Report section contains information on nonvirtual subsystems in the model. • In the Generated Files section on the Contents pane, you can click the names of source code files generated from your model to view their contents in a MATLAB Web browser window. In the displayed source code, global variables are hypertext that links to their definitions. • A Search box in the left navigation pane. For more information, see “Search in the Code Generation Report” on page 11-11. For an example, see “Generate a Code Generation Report” on page 11-5 and “View Code Generation Report in Model Explorer” on page 11-12. The contents of HTML reports varies depending on different target types. You can generate individual HTML reports for a subsystem or referenced model. For more information, see “HTML Code Generation Report for Referenced Models” on page 11-4 and “Generate Code for Referenced Models” on page 3-4. If you have a Simulink Report Generator license, you can document your code generation project in multiple formats, including HTML, PDF, RTF, Microsoft Word, and XML. For an example of how to create a Microsoft Word report, see “Document Generated Code with Simulink® Report Generator™” on page 11-16. 11-2 HTML Code Generation Report Location HTML Code Generation Report Location The default location for the code generation report files is in the html subfolder of the build folder, model_target_rtw/html/. target is the name of the System target file specified on the Code Generation pane. The default name for the top-level HTML report file is model_codegen_rpt.html or subsystem_codegen_rpt.html. For more information on the location of the build folder, see “Control the Location for Generated Files” on page 5-18. 11-3 11 Report Generation HTML Code Generation Report for Referenced Models To generate a code generation report for a top model and code generation reports for each referenced model, you need to specify the Create code generation report on the Code Generation > Report pane for the top model and each referenced model. You can open the code generation report of a referenced model in one of two ways: • From the top-model code generation report, you can access the referenced model code generation report by clicking a link under Referenced Models in the left navigation pane. Clicking a link opens the code generation report for the referenced model in the browser. To navigate back to the top model code generation report, use the Back button at the top of the left navigation pane. • From the referenced model diagram window, select Code > C/C++ Code > Code Generation Report > Open Model Report. To generate a code generation report for a referenced model individually, follow the instructions in “Generate a Code Generation Report” on page 11-5 and “Open Code Generation Report” on page 11-8 for the referenced model. 11-4 Generate a Code Generation Report Generate a Code Generation Report To generate a code generation report when the model is built: 1 In the model diagram window, select Code > C/C++ Code > Code Generation Report > Options. The Configuration Parameters dialog box opens with the Code Generation > Report pane visible. 2 Select the Create code generation report parameter. 3 If you want the code generation report to automatically open after generating code, select the Open report automatically parameter (which is enabled by selecting Create code generation report). 4 Generate code. The build process writes the code generation report files to the html subfolder of the build folder (see “HTML Code Generation Report Location” on page 11-3). Next, the build process automatically opens a MATLAB Web browser window and displays the code generation report. To open an HTML code generation report at any time after a build, see “Open Code Generation Report” on page 11-8 and “Generate Code Generation Report After Build Process” on page 11-6. 11-5 11 Report Generation Generate Code Generation Report After Build Process After generating code, if you did not configure your model to create a code generation report, you can generate a code generation report without rebuilding your model. 1 In the model diagram window, select Code > C/C++ Code > Code Generation Report > Open Model Report. 2 If your current working folder contains the code generation files the following dialog opens. Click Generate Report. 3 If the code generation files are not in your current working directory, the following dialog opens. Enter the full path of the build folder for your model, ../model_target_rtw and click Open Report. 11-6 Generate Code Generation Report After Build Process The software generates a report from the code generation files in the build folder you specified. Note An alternative method for generating the report after the build process is complete is to configure your model to generate a report and build your model. In this case, Embedded Coder generates the report without regenerating the code. 11-7 11 Report Generation Open Code Generation Report You can refer to existing code generation reports at any time. If you generated a code generation report, you can open the report by selecting Code > C/C++ Code > Code Generation Report > Open Model Report. If you are opening a report for a subsystem, select Open Subsystem Report. If your current working folder does not contain the code generation files and the code generation report, the following dialog opens: Enter the full path of the build folder for your model, ../model_target_rtw and click Open Report. Alternatively, you can open the code generation report (model_codegen_rpt.html or subsystem_codegen_rpt.html) manually into a MATLAB Web browser window, or into another Web browser. For the location of the generated report files, see “HTML Code Generation Report Location” on page 11-3. Limitation If you modify legacy or custom code after building your model or generating the code generation report, you must rebuild your model or regenerate the report for the code generation report to include the updated legacy source files. For example, if you modify your legacy code and then use the Code > C/C++ Code > Code Generation Report > Open Model Report menu to open an existing report, the software does not check if the legacy source file is 11-8 Open Code Generation Report out of date compared to the generated code. Therefore, the code generation report is not regenerated and the report includes the out-of-date legacy code. This issue also occurs if you open a code generation report using the coder.report.open function. To regenerate the code generation report, do one of the following: • Rebuild your model. • Generate the report using the coder.report.generate function. 11-9 11 Report Generation Generate Code Generation Report Programmatically At the MATLAB command line, you can generate, open, and close an HTML Code Generation Report with the following functions: • coder.report.generate generates the code generation report for the specified model. • coder.report.open opens an existing code generation report. • coder.report.close closes the code generation report. 11-10 Search in the Code Generation Report Search in the Code Generation Report When the code generation report is displayed in the MATLAB Web browser window, you can search the report using the Search box in the left navigation pane. The search is not case sensitive. Pressing Ctrl-F sets focus to the Search box. Type text into the Search box and hit Enter to start the search. The search highlights any found terms in the displayed page and scrolls to the first instance found. Press Enter to scroll through the subsequent search hits. If no terms are found, the background of the search box is highlighted red. 11-11 11 Report Generation View Code Generation Report in Model Explorer After generating an HTML code generation report, you can view the report in the right pane of the Model Explorer. You can also browse the generated files directly in the Model Explorer. When you generate code, or open a model that has generated code for its current target configuration in your working folder, the Hierarchy (left) pane of Model Explorer contains a node named Code for model. Under that node are other nodes, typically called This Model and Shared Code. Clicking This Model displays in the Contents (middle) pane a list of generated source code files in the build folder of that model. The next figure shows code for the rtwdemo_counter model. In this example, the file S:/rtwdemo_counter_grt_rtw/rtwdemo_counter.c is being displayed. To view any file in the Contents pane, click it once. The views in the Document (right) pane are read only. The code listings there contain hyperlinks to functions and macros in the generated code. Clicking the file hyperlink opens that source file in a text editing window where you can modify its contents. 11-12 View Code Generation Report in Model Explorer If an open model contains Model blocks, and if generated code for any of these models exists in the current slprj folder, nodes for the referenced models appear in the Hierarchy pane one level below the node for the top model. Such referenced models do not need to be open for you to browse and read their generated source files. If the Simulink Coder software generates shared utility code for a model, a node named Shared Code appears directly under the This Model node. It collects any source files that exist in the ./slprj/target/_sharedutils subfolder. Note You cannot use the Search tool built into Model Explorer toolbar to search generated code displayed in the Code Viewer. On PCs, typing Ctrl+F when focused on the Document pane opens a Find dialog box that you can use to search for strings in the currently displayed file. You can also search for text in the HTML report window, and you can open any of the files in the editor. 11-13 11 Report Generation Package and Share the Code Generation Report In this section... “Package the Code Generation Report” on page 11-14 “View the Code Generation Report” on page 11-15 Package the Code Generation Report To share the code generation report, you can package the code generation report files and supporting files into a zip file for transfer. The default location for the code generation report files is in two folders: • /slprj • html subfolder of the build folder, model_target_rtw, for example rtwdemo_counter_grt_rtw/html To create a zip file from the MATLAB command window: 1 In the Current Folder browser, select the two folders: • /slprj • Build folder: model_target_rtw 2 Right-click to open the context menu. 3 In the context menu, select Create Zip File. A file appears in the Current Folder browser. 4 Name the zip file. Alternatively, you can use the MATLAB zip command to zip the code generation report files: zip('myzip',{'slprj','rtwdemo_counter_grt_rtw'}) 11-14 Package and Share the Code Generation Report Note If you need to relocate the static and generated code files for a model to another development environment, such as a system or an integrated development environment (IDE) that does not include MATLAB and Simulink products, use the Simulink Coder pack-and-go utility. For more information, see “Relocate Code to Another Development Environment” on page 15-33. View the Code Generation Report To view the code generation report after transfer, unzip the file and save the two folders at the same folder level in the hierarchy. Navigate to the model_target_rtw/html/ folder and open the top-level HTML report file named model_codgen_rpt.html or subsystem_codegen_rpt.html in a Web browser. 11-15 11 Report Generation Document Generated Code with Simulink Report Generator In this section... “Generate Code for the Model” on page 11-17 “Open the Report Generator” on page 11-18 “Set Report Name, Location, and Format” on page 11-20 “Include Models and Subsystems in a Report” on page 11-21 “Customize the Report” on page 11-22 “Generate the Report” on page 11-23 The Simulink Report Generator software creates documentation from your model in multiple formats, including HTML, PDF, RTF, Microsoft Word, and XML. This example shows one way to document a code generation project in Microsoft Word. The generated report includes: • System snapshots (model and subsystem diagrams) • Block execution order list • Simulink Coder and model version information for generated code • List of generated files • Optimization configuration parameter settings • Simulink Coder target selection and build process configuration parameter settings • Subsystem map • File name, path, and generated code listings for the source code To adjust Simulink Report Generator settings to include custom code and then generate a report for a model, complete the following tasks: 1 “Generate Code for the Model” on page 11-17 2 “Open the Report Generator” on page 11-18 11-16 Document Generated Code with Simulink® Report Generator™ 3 “Set Report Name, Location, and Format” on page 11-20 4 “Include Models and Subsystems in a Report” on page 11-21 5 “Customize the Report” on page 11-22 6 “Generate the Report” on page 11-23 For more information on generating other reports, see the Simulink Report Generator User Guide. Generate Code for the Model Before you use the Report Generator to document your project, generate code for the model. 1 In the MATLAB Current Folder browser, navigate to a folder where you have write access. 2 Create a working folder from the MATLAB command line by typing: mkdir report_ex 3 Make report_ex your working folder: cd report_ex 4 Open the sldemo_f14 model by clicking the following model name below or by entering the model name on the MATLAB command line. 5 In the model window, choose File > Save As, navigate to the working folder, report_ex, and save a copy of the sldemo_f14 model as myf14. 6 Open the Model Explorer by selecting Model Explorer from the model View menu. 7 In the Model Hierarchy pane, click the expander for the model name to reveal its components. 8 In the left pane, click Configuration (Active). 11-17 11 Report Generation 9 Select the Solver tab. In the Solver options section, specify the Type parameter as Fixed-step. 10 Select the General tab. Select Generate code only. Scroll down if the configuration parameter is not visible. 11 Click Apply. 12 Click Generate code. The Simulink Coder build process generates code for the model. Open the Report Generator After you generate the code, open the Report Generator. 1 In the model diagram window, select Tools > Report Generator. 11-18 Document Generated Code with Simulink® Report Generator™ 2 In the Report Explorer window, in the options pane (center), click the folder rtw (\toolbox\rtw). Click the setup file that it contains, codegen.rpt. 11-19 11 Report Generation 3 Double-click codegen.rpt or select it and click the Open report button . The Report Explorer displays the structure of the setup file in the outline pane (left). Set Report Name, Location, and Format Before generating a report, you can specify report output options, such as the folder, file name, and format. For example, to generate a Microsoft Word report named MyCGModelReport.rtf: 11-20 Document Generated Code with Simulink® Report Generator™ 1 In the properties pane, under Report Options, review the options listed. 2 Leave the Directory field set to Present working directory. 3 For Filename, select Custom: and replace index with the name MyModelCGReport. 4 For File format, specify Rich Text Format and replace Standard Print with Numbered Chapters & Sections. Include Models and Subsystems in a Report Specify the models and subsystems that you want to include in the generated report by setting options in the Model Loop component. 11-21 11 Report Generation 1 In the outline pane (left), select Model Loop. Report Generator displays Model Loop component options in the properties pane. 2 If not already selected, select Current block diagram for the Model name option. 3 In the outline pane, click Report - codegen.rpt*. Customize the Report After specifying the models and subsystems to include in the report, you can customize the sections included in the report. 1 In the outline pane (left), expand the node Chapter - Generated Code. By default, the report includes two sections, each containing one of two report components. 2 Expand the node Section 1 — Code Generation Summary. 3 Select Code Generation Summary. Options for the component are displayed in the properties pane. 11-22 Document Generated Code with Simulink® Report Generator™ 4 Click Help to review the report customizations that you can make with the Code Generation Summary component. For this example, do not customize the component. 5 In the Report Explorer window, expand the node Section 1 — Generated Code Listing. 6 Select Import Generated Code. Options for the component are displayed in the properties pane. 7 Click Help to review the report customizations that you can make with the Import Generated Code component. Generate the Report After you adjust the report options, from the Report Explorer window, generate the report by clicking File > Report. A Message List dialog box opens, which displays messages that you can monitor as the report is generated. Model snapshots also appear during report generation. The Message List dialog box might be hidden behind other dialog boxes. When the report is complete, open the report, MyModelCGReport.rtf in the folder report_ex (in this example). 11-23 11 Report Generation For alternative ways of generating reports with the Simulink Report Generator, see “Report Generation”. 11-24 Deployment • Chapter 12, “Desktops” • Chapter 13, “Real-Time Systems” • Chapter 14, “External Code Integration” • Chapter 15, “Program Building, Interaction, and Debugging” 12 Desktops • “Rapid Simulations” on page 12-2 • “Generated S-Function Block” on page 12-34 12 Desktops Rapid Simulations In this section... “About Rapid Simulation” on page 12-2 “Rapid Simulation Performance” on page 12-3 “General Rapid Simulation Workflow” on page 12-3 “Identify Rapid Simulation Requirements” on page 12-4 “Configure Inports to Provide Simulation Source Data” on page 12-6 “Configure and Build Model for Rapid Simulation” on page 12-6 “Set Up Rapid Simulation Input Data” on page 12-9 “Scripts for Batch and Monte Carlo Simulations” on page 12-19 “Run Rapid Simulations” on page 12-20 “Rapid Simulation Target Limitations” on page 12-33 About Rapid Simulation After you create a model, you can use the Simulink Coder rapid simulation (RSim) target to characterize the model behavior. The RSim target executable that results from the build process is for non-real-time execution on your host computer. The executable is highly optimized for simulating models of hybrid dynamic systems, including models that use variable-step solvers and zero-crossing detection. The speed of the generated code makes the RSim target ideal for batch or Monte Carlo simulations. Use the RSim target to generate an executable that runs fast, standalone simulations. You can repeat simulations with varying data sets, interactively or programmatically with scripts, without rebuilding the model. This can accelerate the characterization and tuning of model behavior and code generation testing. Using command-line options: • Define parameter values and input signals in one or more MAT-files that you can load and reload at the start of simulations without rebuilding your model. 12-2 Rapid Simulations • Redirect logging data to one or more MAT-files that you can then analyze and compare. • Control simulation time. • Specify External mode options. Note To run an RSim executable, configure your computer to run MATLAB and have the MATLAB and Simulink installation folders accessible. To deploy a standalone host executable ( i.e., without MATLAB and Simulink installed), consider using the Host-Based Shared Library target (ert_shrlib)." Rapid Simulation Performance The performance advantage that you gain from rapid simulation varies. Larger simulations achieve speed improvements of up to 10 times faster than standard Simulink simulations. Some models might not show any noticeable improvement in simulation speed. To determine the speed difference for your model, time your standard Simulink simulation and compare the results with a rapid simulation. In addition, test the model performance in Rapid Accelerator simulation mode. General Rapid Simulation Workflow Like other stages of Model-Based Design, characterization and tuning of model behavior is an iterative process, as shown in the general workflow diagram in the figure. Tasks in the workflow are: 1 Identify your rapid simulation requirements. 2 Configure Inport blocks that provide input source data for rapid simulations. 3 Configure the model for rapid simulation. 4 Set up simulation input data. 5 Run the rapid simulations. 12-3 12 Desktops Identify rapid simulation requirements Model includes Yes Configure Inport blocks Inport blocks? No Configure and build model Set up input data Batch or Monte Carlo simulations? Yes Program script No Run simulation Analyze simulation results Yes Change input data? Done Identify Rapid Simulation Requirements The first step to setting up a rapid simulation is to identify your simulation requirements. 12-4 Question... For More Information, See... How long do you want simulations to run? “Configure and Build Model for Rapid Simulation” on page 12-6 Are there any solver requirements? Do you expect to use the same solver for which the model is configured for your rapid simulations? “Configure and Build Model for Rapid Simulation” on page 12-6 Rapid Simulations Question... For More Information, See... Do your rapid simulations need to accommodate flexible custom code interfacing? Or, do your simulations need to retain storage class settings? “Configure and Build Model for Rapid Simulation” on page 12-6 Will you be running simulations with multiple data sets? “Set Up Rapid Simulation Input Data” on page 12-9 Will the input data consist of global parameters, signals, or both? “Set Up Rapid Simulation Input Data” on page 12-9 What type of source blocks provide input data to the model — From File, Inport, From Workspace? “Set Up Rapid Simulation Input Data” on page 12-9 Will the model’s parameter vector (model_P) be used as input data? “Create a MAT-File That Includes a Model Parameter Structure” on page 12-10 What is the data type of the input parameters and signals? “Set Up Rapid Simulation Input Data” on page 12-9 Will the source data consist of one variable or multiple variables? “Set Up Rapid Simulation Input Data” on page 12-9 Does the input data include tunable parameters? “Create a MAT-File That Includes a Model Parameter Structure” on page 12-10 Do you need to gain access to tunable parameter information — model checksum and parameter data types, identifiers, and complexity? “Create a MAT-File That Includes a Model Parameter Structure” on page 12-10 Will you have a need to vary the simulation stop time for simulation runs? “Configure and Build Model for Rapid Simulation” on page 12-6 and“Override a Model Simulation Stop Time” on page 12-23 Do you want to set a time limit for the simulation? Consider setting a time limit if your model experiences frequent zero crossings and has a small minor step size. “Set a Clock Time Limit for a Rapid Simulation” on page 12-23 12-5 12 Desktops Question... For More Information, See... Do you need to preserve the output of each simulation run? “Specify a New Output File Name for a Simulation” on page 12-32 and “Specify New Output File Names for To File Blocks” on page 12-33 Do you expect to run the simulations interactively or in batch mode? “Scripts for Batch and Monte Carlo Simulations” on page 12-19 Configure Inports to Provide Simulation Source Data You can use Inport blocks as a source of input data for rapid simulations. To do so, configure the blocks so that they can import data from external MAT-files. By default, the Inport block inherits parameter settings from downstream blocks. In most cases, to import data from an external MAT-file, you must explicitly set the following parameters to match the source data in the MAT-file. • Main > Interpolate data • Signal Attributes > Port dimensions • Signal Attributes > Data type • Signal Attributes > Signal type If you do not have control over the model content, you might need to modify the data in the MAT-file to conform to what the model expects for input. Input data characteristics and specifications of the Inport block that receives the data must match. For details on adjusting these parameters and on creating a MAT-file for use with an Inport block, see “Create a MAT-File for an Inport Block” on page 12-15. For descriptions of the preceding block parameters, see the description of the Inport block in the Simulink documentation. Configure and Build Model for Rapid Simulation After you identify your rapid simulation requirements, configure the model for rapid simulation. 1 Open the Configuration Parameters dialog box. 12-6 Rapid Simulations 2 Go to the Code Generation pane. 3 On the Code Generation pane, click Browse. The System Target File Browser opens. 4 Select rsim.tlc (Rapid Simulation Target) and click OK. On the Code Generation pane, the Simulink Coder software populates the Make command and Template makefile fields with default settings and adds the RSim Target pane under Code Generation. 5 Click RSim Target to view the RSim Target pane. 6 Set the RSim target configuration parameters to your rapid simulation requirements. 12-7 12 Desktops If You Want to... Then... Generate code that allows the RSim executable to load parameters from a MAT-file Select Enable RSim executable to load parameters from a MAT-file (default). Let the target choose a solver based on the solver already configured for the model. Set Solver selection to auto (default). The Simulink Coder software uses a built-in solver if a fixed-step solver is specified on the Solver pane or calls the Simulink solver module (a shared library) if a variable-step solver is specified. Explicitly instruct the target to use a fixed-step solver Set Solver selection to Use fixed-step solvers. In the Configuration Parameters dialog box, on the Solver pane, specify a fixed-step solver. Explicitly instruct the target to use a variable-step solver Set Solver selection to Use Simulink solver module. In the Configuration Parameters dialog box, on the Solver pane, specify a variable-step solver. Force all storage classes to Auto for flexible custom code interfacing Select Force storage classes to AUTO (default). Retain storage class settings, such as ExportedGlobal or ImportedExtern, due to application requirements Clear Force storage classes to AUTO. 7 Set up data import and export options. On the Data Import/Export pane, in the Save to Workspace section, select the Time, States, Outputs, and Final States options, as they apply. By default, the Simulink Coder software saves simulation logging results to a file named model.mat. For more information, see “Export Simulation Data”. 8 If you are using External mode communications, set up the interface, using the Code Generation > Interface pane. See “Host/Target Communication” on page 15-50 for details. 9 Return to the Code Generation pane and click Build. The Simulink Coder code generator builds a highly optimized executable that you can run on your host computer with varying data, without rebuilding. 12-8 Rapid Simulations For more information on compilers that are compatible with the Simulink Coder product, see “Choose and Configure a Compiler” on page 15-2 and “Template Makefiles and Make Options” on page 9-38 . Set Up Rapid Simulation Input Data • “About Rapid Simulation Data Setup” on page 12-9 • “Create a MAT-File That Includes a Model Parameter Structure” on page 12-10 • “Create a MAT-File for a From File Block” on page 12-14 • “Create a MAT-File for an Inport Block” on page 12-15 About Rapid Simulation Data Setup The format and setup of input data for a rapid simulation depends on your requirements. If the Input Data Source Is... Then... The model’s global parameter vector (model_P) Use the rsimgetrtp function to get the vector content and then save it to a MAT-file. The model’s global parameter vector and you want a mapping between the vector and tunable parameters In the Configuration Parameters dialog box, on the Optimization > Signals and Parameters pane, enable the Inline Parameters option. Call the rsimgetrtp function to get the global parameter structure and then save it to a MAT-file. Provided by a From File block Create a MAT-file that a From File block can read. Provided by an Inport block Create a MAT-file that adheres to one of the three data file formats that the Inport block can read. Provided by a From Workspace block Create structure variables in the MATLAB workspace. 12-9 12 Desktops The RSim target requires that MAT-files used as input for From File and Inport blocks contain data. The grt target inserts MAT-file data directly into the generated code, which is then compiled and linked as an executable. In contrast, RSim allows you to replace data sets for each successive simulation. A MAT-file containing From File or Inport block data must be present if a From File block or Inport block exists in your model. Create a MAT-File That Includes a Model Parameter Structure To create a MAT-file that includes a model global parameter structure (model_P), 1 Get the structure by calling the function rsimgetrtp. 2 Save the parameter structure to a MAT-file. If you want to run simulations over varying data sets, consider converting the parameter structure to a cell array and saving the parameter variations to a single MAT-file. Get the Parameter Structure for a Model. Get the global parameter structure (model_P) for a model by calling the function rsimgetrtp. param_struct = rsimgetrtp('model') Argument Description model The model for which you are running the rapid simulations. The rsimgetrtp function forces an update diagram action for the specified model and returns a structure that contains the following fields. 12-10 Rapid Simulations Field Description modelChecksum A four-element vector that encodes the structure of the model. The Simulink Coder software uses the checksum to check whether the structure of the model has changed since the RSim executable was generated. If you delete or add a block, and then generate a new model_P vector, the new checksum no longer matches the original checksum. The RSim executable detects this incompatibility in parameter vectors and exits to avoid returning incorrect simulation results. If the model structure changes, you must regenerate the code for the model. parameters A structure that contains the model’s global parameters. The parameter structure contains the following information. Field Description dataTypeName The name of the parameter data type, for example, double dataTypeID Internal data type identifier used by the Simulink Coder software complex The value 0 if real; 1 if complex dtTransIdx Internal data index used by Simulink Coder software values A vector of the parameter values associated with this structure map If you select the Inline parameters option, this field contains the mapping information that correlates the ’values’ to the tunable parameters of the model. This mapping information, in conjunction with rsimsetrtpparam, is useful for creating subsequent rtP structures without compiling the block diagram. If you select the Inline parameters option for the model, then tunable parameter information is also available in the parameters field. 12-11 12 Desktops The Simulink Coder software reports a tunable fixed-point parameter according to its stored value. For example, an sfix(16) parameter value of 1.4 with a scaling of 2^-8 has a value of 358 as an int16. In the following example, rsimgetrtp returns the parameter structure for the example model rtwdemo_rsimtf to param_struct. param_struct = rsimgetrtp('rtwdemo_rsimtf') param_struct = modelChecksum: [1.7165e+009 3.0726e+009 2.6061e+009 2.3064e+009] parameters: [1x1 struct] Save the Parameter Structure to a MAT-File. After you issue a call to rsimgetrtp, save the return value of the function call to a MAT-file. Using a command-line option, you can then specify that MAT-file as input for rapid simulations. The following example saves the parameter structure returned for rtwdemo_rsimtf to the MAT-file myrsimdemo.mat. save myrsimdemo.mat param_struct; For information on using command-line options to specify required files, see “Run Rapid Simulations” on page 12-20. Convert the Parameter Structure for Running Simulations on Varying Data Sets. If you need to use rapid simulations to test changes to specific parameters, you can convert the model parameter structure to a cell array. You can then access a specific parameter by using the @ operator to specify the index for a specific parameter in the file. To convert the structure to a cell array: 1 Save the parameters vector of the structure returned by rsimgetrtp to a temporary variable. The following example saves the parameter vector to temporary variable p. param_struct = rsimgetrtp('rtwdemo_rsimtf'); p = param_struct.parameters; 12-12 Rapid Simulations 2 Convert the structure to a cell array. param_struct.parameters = []; 3 Assign the saved contents of the temporary variable to the original structure name as an element of the cell array. param_struct.parameters{1} = p; param_struct.parameters{1} ans = dataTypeName: dataTypeId: complex: dtTransIdx: values: map: [] 'double' 0 0 0 [-140 -4900 0 4900] 4 Make a copy of the cell array to preserve the original parameter values. param_struct.parameters{2} = param_struct.parameters{1}; param_struct.parameters{2} ans = dataTypeName: dataTypeId: complex: dtTransIdx: values: map: [] 'double' 0 0 0 [-140 -4900 0 4900] For a subsequent data set, increment the array index. 5 Modify any combination of the parameter values. param_struct.parameters{2}.values=[-150 -5000 0 4950]; 6 Repeat steps 4 and 5 for each parameter data set that you want to use as input to a rapid simulation of the model. 12-13 12 Desktops 7 Save the cell array representing the parameter structure to a MAT-file. save rtwdemo_rsimtf.mat param_struct; For more information on how to specify each data set when you run the simulations, see“Change Block Parameters for an RSim Simulation” on page 12-30. Create a MAT-File for a From File Block You can use a MAT-file as the input data source for a From File block. The format of the data in the MAT-file must match the data format expected by that block. To create a MAT-file for a From File block: 1 For array format data, in the workspace create a matrix that consists of two or more rows. The first row must contain monotonically increasing time points. Other rows contain data points that correspond to the time point in that column. The time and data points must be data of type double. For example: t=[0:0.1:2*pi]'; Ina1=[2*sin(t) 2*cos(t)]; Ina2=sin(2*t); Ina3=[0.5*sin(3*t) 0.5*cos(3*t)]; var_matrix=[t Ina1 Ina2 Ina3]'; For other supported data types, such as int16 or fixed-point, the time data points must be of type double, just as for array format data. However, the sample data can be of any dimension. For more information on setting up the input data, see the description of the From File block in the Simulink documentation. 2 Save the matrix to a MAT-file. The following example saves the matrix var_matrix to the MAT-file myrsimdemo.mat in Version 7.3 format. save '-v7.3' myrsimdemo.mat var_matrix; 12-14 Rapid Simulations Using a command-line option, you can then specify that MAT-file as input for rapid simulations. Create a MAT-File for an Inport Block You can use a MAT-file as the input data source for an Inport block. The format of the data in the MAT-file must adhere to one of the three column-based formats listed in the following table. The table lists the formats in order from least flexible to most flexible. Format Description Single time/data matrix • Least flexible. • One variable. • Two or more columns. Number of columns must equal the sum of the dimensions of all root Inport blocks plus 1. First column must contain monotonically increasing time points. Other columns contain data points that correspond to the time point in a given row. • Data of type double. For an example, see Single time/data matrix in the following procedure, step 4. For more information, see “Import Data Arrays” in the Simulink documentation. Format Description Signal-and-time structure • More flexible than the single time/data matrix format. • One variable. • Must contain two top-level fields: time and signals. The time field contains a column vector of the simulation times. The signals field contains an array of substructures, each of which corresponds to an Inport block. The substructure index corresponds to the Inport block number. Each signals substructure must contain a field named values. The values field must contain an array of inputs for the corresponding Inport block, where each input corresponds to a time point specified by the time field. 12-15 12 Desktops Format Description • If the time field is set to an empty value, clear the check box for the Inport block Interpolate data parameter. • No data type limitations, but must match Inport block settings. For an example, see Signal-and-time structure in the following procedure, step 4. For more information on this format, see “Import Data Structures” in the Simulink documentation. Format Description Per-port structure • Most flexible • Multiple variables. Number of variables must equal the number of Inport blocks. • Consists of a separate structure-with-time or structure-without-time for each Inport block. Each Inport block data structure has only one signals field. To use this format, in the Input text field, enter the names of the structures as a comma-separated list, in1, in2,..., inN, where in1 is the data for your model’s first port, in2 for the second port, and so on. • Each variable can have a different time vector. • If the time field is set to an empty value, clear the check box for the Inport block Interpolate data parameter. • No data type limitations, but must match Inport block settings. • To save multiple variables to the same data file, you must save them in the order expected by the model, using the -append option. For an example, see Per-port structure in the following procedure, step 4. For more information, see “Import Data Structures” in the Simulink documentation. The supported formats and the following procedure are illustrated in rtwdemo_rsim_i. To create a MAT-file for an Inport block: 12-16 Rapid Simulations 1 Choose one of the preceding data file formats. 2 Update Inport block parameter settings and specifications to match specifications of the data to be supplied by the MAT-file. By default, the Inport block inherits parameter settings from downstream blocks. To import data from an external MAT-file, explicitly set the following parameters to match the source data in the MAT-file. • Main > Interpolate data • Signal Attributes > Port dimensions • Signal Attributes > Data type • Signal Attributes > Signal type If you choose to use a structure format for workspace variables and the time field is empty, you must clear Interpolate data or modify the field so that it is set to a nonempty value. Interpolation requires time data. For descriptions of the preceding block parameters, see the description of the Inport block in the Simulink documentation. 3 Build an RSim executable for the model. The Simulink Coder build process creates and calculates a structural checksum for the model and embeds it in the generated executable. The RSim target uses the checksum to verify that data being passed into the model is consistent with what the model executable expects. 4 Create the MAT-file that provides the source data for the rapid simulations. You can create the MAT-file from a workspace variable. Using the specifications in the preceding format comparison table, create the workspace variables for your simulations. An example of each format follows: Single time/data matrix t=[0:0.1:2*pi]'; Ina1=[2*sin(t) 2*cos(t)]; Ina2=sin(2*t); Ina3=[0.5*sin(3*t) 0.5*cos(3*t)]; 12-17 12 Desktops var_matrix=[t Ina1 Ina2 Ina3]; Signal-and-time structure t=[0:0.1:2*pi]'; var_single_struct.time=t; var_single_struct.signals(1).values(:,1)=2*sin(t); var_single_struct.signals(1).values(:,2)=2*cos(t); var_single_struct.signals(2).values=sin(2*t); var_single_struct.signals(3).values(:,1)=0.5*sin(3*t); var_single_struct.signals(3).values(:,2)=0.5*cos(3*t); v=[var_single_struct.signals(1).values... var_single_struct.signals(2).values... var_single_struct.signals(3).values]; Per-port structure t=[0:0.1:2*pi]'; Inb1.time=t; Inb1.signals.values(:,1)=2*sin(t); Inb1.signals.values(:,2)=2*cos(t); t=[0:0.2:2*pi]'; Inb2.time=t; Inb2.signals.values(:,1)=sin(2*t); t=[0:0.1:2*pi]'; Inb3.time=t; Inb3.signals.values(:,1)=0.5*sin(3*t); Inb3.signals.values(:,2)=0.5*cos(3*t); 5 Save the workspace variables to a MAT-file. Single time/data matrix The following example saves the workspace variable var_matrix to the MAT-file rsim_i_matrix.mat. save rsim_i_matrix.mat var_matrix; Signal-and-time structure The following example saves the workspace structure variable var_single_struct to the MAT-file rsim_i_single_struct.mat. 12-18 Rapid Simulations save rsim_i_single_struct.mat var_single_struct; Per-port structure To order data when saving per-port structure variables to a single MAT-file, use the save command’s -append option. Be sure to append the data in the order that the model expects it. The following example saves the workspace variables Inb1, Inb2, and Inb3 to MAT-file rsim_i_multi_struct.mat. save rsim_i_multi_struct.mat Inb1; save rsim_i_multi_struct.mat Inb2 -append; save rsim_i_multi_struct.mat Inb3 -append; The save command does not preserve the order in which you specify your workspace variables in the command line when saving data to a MAT-file. For example, if you specify the variables v1, v2, and v3, in that order, the order of the variables in the MAT-file could be v2 v1 v3. Using a command-line option, you can then specify the MAT-files as input for rapid simulations. Scripts for Batch and Monte Carlo Simulations The RSim target is for batch simulations in which parameters and input signals vary for multiple simulations. New output file names allow you to run new simulations without overwriting prior simulation results. You can set up a series of simulations to run by creating a .bat file for use on a Microsoft Windows platform. Create a file for the Windows platform with any text editor and execute it by typing the file name, for example, mybatch, where the name of the text file is mybatch.bat. rtwdemo_rsimtf -f rtwdemo_rsimtf.mat=run1.mat -o results1.mat -tf 10.0 rtwdemo_rsimtf -f rtwdemo_rsimtf.mat=run2.mat -o results2.mat -tf 10.0 rtwdemo_rsimtf -f rtwdemo_rsimtf.mat=run3.mat -o results3.mat -tf 10.0 rtwdemo_rsimtf -f rtwdemo_rsimtf.mat=run4.mat -o results4.mat -tf 10.0 12-19 12 Desktops In this case, batch simulations run using four sets of input data in files run1.mat, run2.mat, and so on. The RSim executable saves the data to the files specified with the -o option. The variable names containing simulation results in each of the files are identical. Therefore, loading consecutive sets of data without renaming the data once it is in the MATLAB workspace results in overwriting the prior workspace variable with new data. To avoid overwriting, you can copy the result to a new MATLAB variable before loading the next set of data. You can also write MATLAB scripts to create new signals and new parameter structures, as well as to save data and perform batch runs using the bang command (!). For details on running simulations and available command-line options, see “Run Rapid Simulations” on page 12-20. For an example of a rapid simulation batch script, see the example rtwdemo_rsim_batch_script. Run Rapid Simulations • “” on page 12-20 • “Requirements for Running Rapid Simulations” on page 12-22 • “Set a Clock Time Limit for a Rapid Simulation” on page 12-23 • “Override a Model Simulation Stop Time” on page 12-23 • “Read the Parameter Vector into a Rapid Simulation” on page 12-24 • “Specify New Signal Data File for a From File Block” on page 12-24 • “Specify Signal Data File for an Inport Block” on page 12-27 • “Change Block Parameters for an RSim Simulation” on page 12-30 • “Specify a New Output File Name for a Simulation” on page 12-32 • “Specify New Output File Names for To File Blocks” on page 12-33 Using the RSim target, you can build a model once and run multiple simulations to study effects of varying parameter settings and input signals. You can run a simulation directly from your operating system command line, 12-20 Rapid Simulations redirect the command from the MATLAB command line by using the bang (!) character, or execute commands from a script. Operating System Command Line rtwdemo_rsimtf MATLAB Command Line !rtwdemo_rsimtf The following table lists ways you can use RSim target command-line options to control a simulation. To... Use... Read input data for a From File block from a MAT-file other than the MAT-file used for the previous simulation model -f oldfilename.mat=newfilename.mat Print a summary of the options for RSim executable targets executable filename -h Read input data for an Inport block from a MAT-file model -i filename.mat Time out after n clock time seconds, where n is a positive integer value model -L n Write MAT-file logging data to file model -o filename.mat filename.mat Read a parameter vector from file model -p filename.mat filename.mat Override the default TCP port (17725) for External mode model -port TCPport Write MAT-file logging data to a MAT-file other than the MAT-file used for the previous simulation model -t oldfilename.mat=newfilename.mat Run the simulation until the time value stoptime is reached model -tf stoptime 12-21 12 Desktops To... Use... Run in verbose mode model -v Wait for the Simulink engine to start the model in External mode model -w The following sections use the rtwdemo_rsimtf example model in examples to illustrate some of these command-line options. In each case, the example assumes you have already done the following: • Created or changed to a working folder. • Opened the example model. • Copied the data file matlabroot/toolbox/rtw/rtwdemos/rsimdemos/rsim_tfdata.mat to your working folder. You can perform this operation using the command: copyfile(fullfile(matlabroot,'toolbox','rtw','rtwdemos',... 'rsimdemos','rsim_tfdata.mat'),pwd); Requirements for Running Rapid Simulations • You can run the RSim executable on any computer configured to run MATLAB and for which the MATLAB and Simulink installation folder is accessible to the RSim.exe. To obtain that access, your PATH environment variable must include /bin and /bin/($ARCH), where ($ARCH) represents your operating system architecture. For example, for a personal computer running on a Windows platform, ($ARCH) is “win32”, whereas for a Linux machine, ($ARCH) is “glnx86”. • On GNU Linux platforms, to run an RSim executable, define the LD_LIBRARY_PATH environment variable to provide the path to the MATLAB installation folder, as follows: % setenv LD_LIBRARY_PATH /matlab/sys/os/glnx86:$LD_LIBRARY_PATH • On the Apple Macintosh OS X platform, to run RSim target executables, you must define the environment variable DYLD_LIBRARY_PATH to include the folders bin/mac and sys/os/mac under the MATLAB installation 12-22 Rapid Simulations folder. For example, if your MATLAB installation is under /MATLAB, add /MATLAB/bin/mac and /MATLAB/sys/os/mac to the definition for DYLD_LIBRARY_PATH. Set a Clock Time Limit for a Rapid Simulation If a model experiences frequent zero crossings and the model’s minor step size is small, consider setting a time limit for a rapid simulation. To set a time limit, specify the -L option with a positive integer value. The simulation aborts after running for the specified amount of clock time (not simulation time). For example, !rtwdemo_rsimtf -L 20 Based on your clock, after the executable runs for 20 seconds, the program is terminate. You see one of the following messages: On a Microsoft Windows Platform Exiting program, time limit exceeded Logging available data ... On The Open Group UNIX Platform ** Received SIGALRM (Alarm) signal @ Fri Jul 25 15:43:23 2003 ** Exiting model 'vdp' @ Fri Jul 25 15:43:23 2003 You do not need to do anything to your model or to its Simulink Coder configuration to use this option. Override a Model Simulation Stop Time By default, a rapid simulation runs until the simulation time reaches the time specified the Configuration Parameters dialog box, on the Solver pane. You can override the model simulation stop time by using the -tf option. For example, the following simulation runs until the time reaches 6.0 seconds. !rtwdemo_rsimtf -tf 6.0 The RSim target stops and logs output data using MAT-file data logging rules. 12-23 12 Desktops If the model includes a From File block, the end of the simulation is regulated by the stop time setting specified in the Configuration Parameters dialog box, on the Solver pane, or with the RSim target option -tf. The values in the block’s time vector are ignored. However, if the simulation time exceeds the endpoints of the time and signal matrix (if the final time is greater than the final time value of the data matrix), the signal data is extrapolated to the final time value. Read the Parameter Vector into a Rapid Simulation To read the model parameter vector into a rapid simulation, you must first create a MAT-file that includes the parameter structure as described in “Create a MAT-File That Includes a Model Parameter Structure” on page 12-10. You can then specify the MAT-file in the command line with the -p option. For example: 1 Build an RSim executable for the example model rtwdemo_rsimtf. 2 Modify parameters in your model and save the parameter structure. param_struct = rsimgetrtp('rtwdemo_rsimtf'); save myrsimdata.mat param_struct 3 Run the executable with the new parameter set. !rtwdemo_rsimtf -p myrsimdata.mat ** Starting model 'rtwdemo_rsimtf' @ Tue Dec 27 12:30:16 2005 ** created rtwdemo_rsimtf.mat ** 4 Load workspace variables and plot the simulation results by entering the following commands: load myrsimdata.mat plot(rt_yout) Specify New Signal Data File for a From File Block If your model’s input data source is a From File block, you can feed the block with input data during simulation from a single MAT-file or you can change 12-24 Rapid Simulations the MAT-file from one simulation to the next. Each MAT-file must adhere to the format described in “Create a MAT-File for a From File Block” on page 12-14. To change the MAT-file after an initial simulation, you specify the executable with the -f option and an oldfile.mat=newfile.mat parameter, as shown in the following example. 1 Set some parameters in the MATLAB workspace. For example: w = 100; theta = 0.5; 2 Build an RSim executable for the example model rtwdemo_rsimtf. 3 Run the executable. !rtwdemo_rsimtf The RSim executable runs a set of simulations and creates output MAT-files containing the specific simulation result. 4 Load the workspace variables and plot the simulation results by entering the following commands: load rtwdemo_rsimtf.mat plot(rt_yout) The resulting plot shows simulation results based on default input data. 12-25 12 Desktops 5 Create a new data file, newfrom.mat, that includes the following data: t=[0:.001:1]; u=sin(100*t.*t); tu=[t;u]; save newfrom.mat tu; 6 Run a rapid simulation with the new data by using the -f option to replace the original file, rsim_tfdata.mat, with newfrom.mat. !rtwdemo_rsimtf -f rsim_tfdata.mat=newfrom.mat 7 Load the data and plot the new results by entering the following commands: load rtwdemo_rsimtf.mat plot(rt_yout) The next figure shows the resulting plot. 12-26 Rapid Simulations From File blocks require input data of type double. If you need to import signal data of a data type other than double, use an Inport block (see “Create a MAT-File for an Inport Block” on page 12-15) or a From Workspace block with the data specified as a structure. Workspace data must be in the format: variable.time variable.signals.values If you have more than one signal, use the following format: variable.time variable.signals(1).values variable.signals(2).values Specify Signal Data File for an Inport Block If your model’s input data source is an Inport block, you can feed the block with input data during simulation from a single MAT-file or you can change 12-27 12 Desktops the MAT-file from one simulation to the next. Each MAT-file must adhere to one of the three formats described in “Create a MAT-File for an Inport Block” on page 12-15. To specify the MAT-file after a simulation, you specify the executable with the -i option and the name of the MAT-file that contains the input data. For example: 1 Open the model rtwdemo_rsim_i. 2 Check the Inport block parameter settings. The following Inport block data parameter settings and specifications that you specify for the workspace variables must match settings in the MAT-file, as indicated in “Configure Inports to Provide Simulation Source Data” on page 12-6: • Main > Interpolate data • Signal Attributes > Port dimensions • Signal Attributes > Data type • Signal Attributes > Signal type 3 Build the model. 4 Set up the input signals. For example: t=[0:0.01:2*pi]'; s1=[2*sin(t) 2*cos(t)]; s2=sin(2*t); s3=[0.5*sin(3*t) 0.5*cos(3*t)]; plot(t, [s1 s2 s3]) 12-28 Rapid Simulations 5 Prepare the MAT-file by using one of the three available file formats described in “Create a MAT-File for an Inport Block” on page 12-15. The following example defines a signal-and-time structure in the workspace and names it var_single_struct. t=[0:0.1:2*pi]'; var_single_struct.time=t; var_single_struct.signals(1).values(:,1)=2*sin(t); var_single_struct.signals(1).values(:,2)=2*cos(t); var_single_struct.signals(2).values=sin(2*t); var_single_struct.signals(3).values(:,1)=0.5*sin(3*t); var_single_struct.signals(3).values(:,2)=0.5*cos(3*t); v=[var_single_struct.signals(1).values... var_single_struct.signals(2).values... var_single_struct.signals(3).values]; 6 Save the workspace variable var_single_struct to MAT-file rsim_i_single_struct. save rsim_i_single_struct.mat var_single_struct; 12-29 12 Desktops 7 Run a rapid simulation with the input data by using the -i option. Load and plot the results. !rtwdemo_rsim_i -i rsim_i_single_struct.mat ** Starting model 'rtwdemo_rsim_i' @ Tue Dec 27 14:01:20 2005 *** rsim_i_single_struct.mat is loaded! *** ** created rtwdemo_rsim_i.mat ** ** Execution time = 0.2683734753333333sload rsim_i_single_struct.mat; 8 Load and plot the results. load rtwdemo_rsim_i.mat plot(rt_tout, rt_yout); Change Block Parameters for an RSim Simulation As described in “Create a MAT-File That Includes a Model Parameter Structure” on page 12-10, after you alter one or more parameters in a 12-30 Rapid Simulations Simulink block diagram, you can extract the parameter vector, model_P, for the entire model. You can then save the parameter vector, along with a model checksum, to a MAT-file. This MAT-file can be read directly by the standalone RSim executable, allowing you to replace the entire parameter vector or individual parameter values, for running studies of variations of parameter values representing coefficients, new data for input signals, and so on. The RSim target allows you to alter any model parameter, including parameters that include side-effects functions. An example of a side-effects function is a simple Gain block that includes the following parameter entry in a dialog box: gain value: 2 * a The Simulink Coder code generator evaluates side-effects functions before generating code. The generated code for this example retains only one memory location entry, and the dependence on parameter a is no longer visible in the generated code. The RSim target overcomes the problem of handling side-effects functions by replacing the entire parameter structure, model_P. You must create this new structure by using the rsimgetrtp function and then saving it in a MAT-file, as described in “Create a MAT-File That Includes a Model Parameter Structure” on page 12-10. RSim can read the MAT-file and replace the entire model_P structure whenever you change one or more parameters, without recompiling the entire model. For example, assume that you changed one or more parameters in your model, generated the new model_P vector, and saved model_P to a new MAT-file called mymatfile.mat. To run the same rtwdemo_rsimtf model and use these new parameter values, use the -p option, as shown in the following example: !rtwdemo_rsimtf -p mymatfile.mat load rtwdemo_rsimtf plot(rt_yout) If you have converted the parameter structure to a cell array for running simulations on varying data sets, as described in “Convert the Parameter Structure for Running Simulations on Varying Data Sets” on page 12-12, you must add an @n suffix to the MAT-file specification. n is the element of the cell array that contains the specific input that you want to use for the simulation. 12-31 12 Desktops The following example converts param_struct to a cell array, changes parameter values, saves the changes to MAT-file mymatfile.mat, and then runs the executable using the parameter values in the second element of the cell array as input. param_struct = rsimgetrtp('rtwdemo_rsimtf'); p = param_struct.parameters; param_struct.parameters = []; param_struct.parameters{1} = p; param_struct.parameters{1} ans = dataTypeName: 'double' dataTypeId: 0 complex: 0 dtTransIdx: 0 values: [-140 -4900 0 4900] param_struct.parameters{2} = param_struct.parameters{1}; param_struct.parameters{2}.values=[-150 -5000 0 4950]; save mymatfile.mat param_struct; !rtwdemo_rsimtf -p mymatfile.mat@2 -o rsim2.mat Specify a New Output File Name for a Simulation If you have specified any of the Save to Workspace options — Time, States, Outputs, or Final States — in the Configuration Parameters dialog box, on the Data Import/Export pane, the default is to save simulation logging results to the file model.mat. For example, the example model rtwdemo_rsimtf normally saves data to rtwdemo_rsimtf.mat, as follows: !rtwdemo_rsimtf created rtwdemo_rsimtf.mat You can specify a new output file name for data logging by using the -o option when you run an executable. !rtwdemo_rsimtf -o rsim1.mat In this case, the set of parameters provided at the time of code generation, including any From File block data, is run. 12-32 Rapid Simulations Specify New Output File Names for To File Blocks In much the same way as you can specify a new system output file name, you can also provide new output file names for data saved from one or more To File blocks. To do this, specify the original file name at the time of code generation with a new name, as shown in the following example: !rtwdemo_rsimtf -t rtwdemo_rsimtf_data.mat=mynewrsimdata.mat In this case, assume that the original model wrote data to the output file rtwdemo_rsimtf_data.mat. Specifying a new file name forces RSim to write to the file mynewrsimdata.mat. With this technique, you can avoid overwriting an existing simulation run. Rapid Simulation Target Limitations The RSim target has the following limitations: • Does not support algebraic loops. • Does not support Interpreted MATLAB Function blocks. • Does not support noninlined MATLAB language or Fortran S-functions. • If an RSim build includes referenced models (by using Model blocks), set up these models to use fixed-step solvers to generate code for them. The top model, however, can use a variable-step solver as long as all blocks in the referenced models are discrete. • In certain cases, changing block parameters can result in structural changes to your model that change the model checksum. An example of such a change is changing the number of delays in a DSP simulation. In such cases, you must regenerate the code for the model. • Variable-step solver support for RSim is not available on Microsoft Windows platforms when you use the Watcom C/C++ compiler. 12-33 12 Desktops Generated S-Function Block S-functions are an important class of target for which the Simulink Coder product can generate code. The ability to encapsulate a subsystem into an S-function allows you to increase its execution efficiency and facilitate code reuse. The following sections describe the properties of S-function targets and illustrate how to generate them. For more details on the structure of S-functions, see “Host-Specific Code”. In this section... “About Object Libraries” on page 12-34 “Create S-Function Blocks from a Subsystem” on page 12-37 “Tunable Parameters in Generated S-Functions” on page 12-42 “System Target File and Template Makefiles” on page 12-44 “Checksums and the S-Function Target” on page 12-45 “S-Function Target Limitations” on page 12-45 About Object Libraries • “About the S-Function Target” on page 12-34 • “Required Files for S-Function Deployment” on page 12-36 • “Sample Time Propagation in Generated S-Functions” on page 12-37 • “Choose a Solver Type” on page 12-37 About the S-Function Target Using the S-function target, you can build an S-function component and use it as an S-Function block in another model. The S-function code format used by the S-function target generates code that conforms to the Simulink C MEX S-function application programming interface (API). Applications of this format include 12-34 Generated S-Function Block • Conversion of a model to a component. You can generate an S-Function block for a model, m1. Then, you can place the generated S-Function block in another model, m2. Regenerating code for m2 does not require regenerating code for m1. • Conversion of a subsystem to a component. By extracting a subsystem to a separate model and generating an S-Function block from that model, you can create a reusable component from the subsystem. See “Create S-Function Blocks from a Subsystem” on page 12-37 for an example of this procedure. • Speeding up simulation. In many cases, an S-function generated from a model performs more efficiently than the original model. • Code reuse. You can incorporate multiple instances of one model inside another without replicating the code for each instance. Each instance will continue to maintain its own unique data. The S-function target generates noninlined S-functions. Within the same release, you can generate an executable from a model that contains generated S-functions by using the generic real-time or real-time malloc targets. This is not supported when incorporating a generated S-function from one release into a model that you build with a different release. You can place a generated S-Function block into another model from which you can generate another S-function. This allows any level of nested S-functions. For limitations related to nesting, see “Limitations on Nesting S-Functions” on page 12-50. 12-35 12 Desktops Note While the S-function target provides a means to deploy an application component for reuse while shielding its internal logic from inspection and modification, the preferred solutions for protecting intellectual property in distributed components are: • The protected model, a referenced model from which all block and line information has been eliminated using the Model Protection facility. For more information, see “Protected Model” in the Simulink documentation. • The Embedded Coder shared library system target file, used to generate a shared library for a model or subsystem for use in a system simulation external to Simulink. For more information see “Shared Object Libraries” in the Embedded Coder documentation. Required Files for S-Function Deployment To deploy your generated S-Function block for inclusion in other models for simulation, you need only provide the binary MEX-file object that was generated in the current working folder when the S-Function block was created: subsys_sf.mexext where subsys is the subsystem name and mexext is a platform-dependent MEX-file extension (see mexext). For example, SourceSubsys_sf.mexw32. To deploy your generated S-Function block for inclusion in other models for code generation, you must provide all of the files that were generated in the current working folder when the S-Function block was created: • subsys_sf.c or .cpp, where subsys is the subsystem name (for example, SourceSubsys_sf.c) • subsys_sf.h • subsys_sf.mexext, where mexext is a platform-dependent MEX-file extension (see mexext) • Subfolder subsys_sfcn_rtw and its contents 12-36 Generated S-Function Block Sample Time Propagation in Generated S-Functions A generated S-Function block can inherit its sample time from the model in which it is placed if certain criteria are met. Conditions that govern sample time propagation for both Model blocks and generated S-Function blocks are described in “Inherit Sample Times” in the Simulink documentation and “Inherited Sample Time for Referenced Models” on page 3-29 in the Simulink Coder documentation. To generate an S-Function block that meets the criteria for inheriting sample time, you must constrain the solver for the model from which the S-Function block is generated. On the Solver configuration parameters dialog pane, set Type to Fixed-step and Periodic sample time constraint to Ensure sample time independent. If the model is unable to inherit sample times, this setting causes the Simulink software to display an error message when building the model. See “Periodic sample time constraint” in the Simulink documentation for more information about this option. Choose a Solver Type If the model containing the subsystem from which you generate an S-function uses a variable-step solver, the generated S-function contains zero-crossing functions and will work properly only in models that use variable-step solvers. If the model containing the subsystem from which you generate an S-function uses a fixed-step solver, the generated S-function contains no zero-crossing functions and the generated S-function will work properly in models that use variable-step or fixed-step solvers. Create S-Function Blocks from a Subsystem This section illustrates how to extract a subsystem from a model and generate a reusable S-function component from it. The next figure shows SourceModel, a simple model that inputs signals to a subsystem. The subsequent figure shows the subsystem, SourceSubsys. The signals, which have different widths and sample times, are • A Step block with sample time 1 • A Sine Wave block with sample time 0.5 12-37 12 Desktops • A Constant block whose value is the vector [-2 3] SourceModel SourceSubsys The objective is to extract SourceSubsys from the model and build an S-Function block from it, using the S-function target. The S-Function block must perform identically to the subsystem from which it was generated. In this model, SourceSubsys inherits sample times and signal widths from its input signals. However, S-Function blocks created from a model using the S-function target will have all signal attributes (such as signal widths or sample times) hard-wired. (The sole exception to this rule concerns sample times, as described in “Sample Time Propagation in Generated S-Functions” on page 12-37.) 12-38 Generated S-Function Block In this example, you want the S-Function block to retain the properties of SourceSubsys as it exists in SourceModel. Therefore, before you build the subsystem as a separate S-function component, you must set the inport sample times and widths explicitly. In addition, the solver parameters of the S-function component must be the same as those of the original model. The generated S-function component will operate identically to the original subsystem (see “Choose a Solver Type” on page 12-37 for an exception to this rule). To build SourceSubsys as an S-function component, 1 Create a new model and copy/paste the SourceSubsys block into the empty window. 2 Set the signal widths and sample times of inports inside SourceSubsys such that they match those of the signals in the original model. Inport 1, Filter, has a width of 1 and a sample time of 1. Inport 2, Xferfcn, has a width of 1 and a sample time of 0.5. Inport 3, offsets, has a width of 2 and a sample time of 0.5. 3 The generated S-Function block should have three inports and one outport. Connect inports and an outport to SourceSubsys, as shown in the next figure. The signal widths and sample times are propagated to these ports. 12-39 12 Desktops 4 Set the solver type, mode, and other solver parameters such that they are identical to those of the source model. This is easiest to do if you use Model Explorer. 5 In the Configuration Parameters dialog box, go to the Code Generation pane. 6 Click Browse to open the System Target File Browser. 7 In the System Target File Browser, select the S-function target, rtwsfcn.tlc, and click OK. The Code Generation pane appears as follows. 8 Select the S-Function Target pane. Make sure that Create new model is selected, as shown in the next figure: 12-40 Generated S-Function Block When this option is selected, the build process creates a new model after it builds the S-function component. The new model contains an S-Function block, linked to the S-function component. Click Apply. 9 Save the new model containing your subsystem, for example as SourceSubsys. 10 Build the model. 11 The Simulink Coder build process builds the S-function component in the working folder. After the build, a new model window is displayed. Optionally you can save the generated model, for example as SourceSubsys_Sfunction. 12 You can now copy the Simulink Coder S-Function block from the new model and use it in other models or in a library. Note For a list of files required to deploy your S-Function block for simulation or code generation, see “Required Files for S-Function Deployment” on page 12-36. The next figure shows the S-Function block plugged into the original model. Given identical input signals, the S-Function block will perform identically to the original subsystem. 12-41 12 Desktops Generated S-Function Configured Like SourceModel The speed at which the S-Function block executes is typically faster than the original model. This difference in speed is more pronounced for larger and more complicated models. By using generated S-functions, you can increase the efficiency of your modeling process. Tunable Parameters in Generated S-Functions You can use tunable parameters in generated S-functions in two ways: • Use the Generate S-function feature (see “Automate S-Function Generation” on page 14-23). or • Use the Model Parameter Configuration dialog box (see “Parameters” on page 7-10) to declare desired block parameters tunable. Block parameters that are declared tunable with the auto storage class in the source model become tunable parameters of the generated S-function. These parameters do not become part of a generated model_P (formerly rtP) parameter data structure, as they would in code generated from other targets. Instead, the generated code accesses these parameters by using MEX API calls such as mxGetPr or mxGetData. Your code should access these parameters in the same way. For more information on MEX API calls, see “About Writing C S-Functions” and “Application Programming Interfaces to MATLAB”. 12-42 Generated S-Function Block S-Function blocks created by using the S-function target are automatically masked. The mask displays each tunable parameter in an edit field. By default, the edit field displays the parameter by variable name, as in the following example. You can choose to display the value of the parameter rather than its variable name by selecting Use value for tunable parameters on the Code Generation > S-Function Target pane of the Configuration Parameters dialog box. When this option is chosen, the value of the variable (at code generation time) is displayed in the edit field, as in the following example. 12-43 12 Desktops System Target File and Template Makefiles • “About System Target File and Template Makefiles” on page 12-44 • “System Target File” on page 12-44 • “Template Makefiles” on page 12-44 About System Target File and Template Makefiles This section lists the target file and template makefiles that are provided for use with the S-function target. System Target File • rtwsfcn.tlc Template Makefiles • rtwsfcn_lcc.tmf — Lcc compiler • rtwsfcn_unix.tmf — The Open Group UNIX host 12-44 Generated S-Function Block • rtwsfcn_vc.tmf — Microsoft Visual C++ compiler • rtwsfcn_watc.tmf — Watcom C compiler Checksums and the S-Function Target The Simulink Coder software creates a checksum for a Simulink model and uses the checksum during the build process for code reuse, model reference, and External mode features. The Simulink Coder software calculates a model’s checksum by 1 Calculating a checksum for each subsystem in the model. A subsystem’s checksum is the combination of properties (data type, complexity, sample time, port dimensions, and so forth) of the subsystem’s blocks. 2 Combining the subsystem checksums and other model-level information. An S-function can add additional information, not captured during the block property analysis, to a checksum by calling the function ssSetChecksumVal. For the S-Function target, the value that gets added to the checksum is the checksum of the model or subsystem from which the S-function is generated. The Simulink Coder software applies the subsystem and model checksums as follows: • Code reuse — If two subsystems in a model have the same checksum, the Simulink Coder build process generates code for one function only. • Model reference — If the current model checksum matches the checksum when the model was built, the Simulink Coder build process does not rebuild submodels. • External mode — If the current model checksum does not match the checksum of the code that is running on the target, the Simulink Coder build process generates an error. S-Function Target Limitations • “Limitations on Using Tunable Variables in Expressions” on page 12-46 12-45 12 Desktops • “Run-Time Parameters and S-Function Compatibility Diagnostics” on page 12-46 • “Limitations on Using Goto and From Block” on page 12-47 • “Limitations on Building and Updating S-Functions” on page 12-48 • “Unsupported Blocks” on page 12-49 • “SimState Not Supported for Code Generation” on page 12-49 • “Profiling Code Performance Not Supported” on page 12-50 • “Limitations on Nesting S-Functions” on page 12-50 • “Limitations on User-Defined Data Types” on page 12-50 • “Limitation on Right-Click Generation of an S-Function Target” on page 12-50 • “Limitation on S-Functions with Bus I/O Signals” on page 12-51 • “Limitation on Subsystems with Function-Call I/O Signals” on page 12-51 Limitations on Using Tunable Variables in Expressions Certain limitations apply to the use of tunable variables in expressions. When Simulink Coder software encounters an unsupported expression during code generation, a warning appears and the equivalent numeric value is generated in the code. For a list of the limitations, see “Tunable Expression Limitations” on page 15-131. Run-Time Parameters and S-Function Compatibility Diagnostics If you set the S-function upgrades needed option on the Diagnostics > Compatibility pane of the Configuration Parameters dialog box to warning or error, the Simulink Coder software instructs you to upgrade S-functions that you create with the Generate S-function feature. This is because the S-function target does not register run-time parameters. Run-time parameters are only supported for inlined S-Functions and the generated S-Function supports features that prevent it from being inlined (for example, it can call or contain other noninlined S-functions). You can work around this limitation by setting the S-function upgrades needed option to none. Alternatively, if you have an Embedded Coder 12-46 Generated S-Function Block license, select the Create Embedded Coder SIL block check box on the Generate S-function for Subsystem dialog box and create a SIL block (containing the ERT S-function). In this case, you do not receive the upgrade messages. However, you cannot include SIL blocks inside other generated S-functions recursively. Limitations on Using Goto and From Block When using the S-function target, the Simulink Coder code generator restricts I/O to correspond to the root model’s Inport and Outport blocks (or the Inport and Outport blocks of the Subsystem block from which the S-function target was generated). No code is generated for Goto or From blocks. To work around this restriction, create your model and subsystem with the required Inport and Outport blocks, instead of using Goto and From blocks to pass data between the root model and subsystem. In the model that incorporates the generated S-function, you would then add Goto and From blocks. Example Before Work Around • Root model with a From block and subsystem, Subsystem1 • Subsystem1 with a Goto block, which has global visibility and passes its input to the From block in the root model 12-47 12 Desktops • Subsystem1 replaced with an S-function generated with the S-Function target — a warning results when you run the model because the generated S-function does not implement the Goto block Example After Work Around An Outport block replaces the GoTo block in Subsystem1. When you plug the generated S-function into the root model, its output connects directly to the To Workspace block. Limitations on Building and Updating S-Functions The following limitations apply to building and updating S-functions using the Simulink Coder S-function target: • You cannot build models that contain Model blocks using the Simulink Coder S-function target. This also means that you cannot build a subsystem module by right-clicking (or by using Code > C/C++ Code > Build Selected Subsystem) if the subsystem contains Model blocks. This restriction applies only to S-functions generated using the S-function target, not to ERT S-functions. 12-48 Generated S-Function Block • If you modify the model that generated an S-Function block, the Simulink Coder build process does not automatically rebuild models containing the generated S-Function block. This is in contrast to the practice of automatically rebuilding models referenced by Model blocks when they are modified (depending on the Model Reference Rebuild configuration setting). • Handwritten S-functions without corresponding TLC files must contain exception-free code. For more information on exception-free code, see “Exception Free Code” in the Simulink documentation. Unsupported Blocks The S-function format does not support the following built-in blocks: • Interpreted MATLAB Function block • S-Function blocks containing any of the following: - MATLAB language S-functions (unless you supply a TLC file for C code generation) - Fortran S-functions (unless you supply a TLC file for C code generation) C/C++ MEX S-functions that call into the MATLAB environment • Scope block • To Workspace block The S-function format does not support blocks from the embeddedtargetslib block library in the Embedded Coder product. SimState Not Supported for Code Generation You can use SimState within C-MEX and Level-2 MATLAB language S-functions to save and restore the simulation state (see “S-Function Compliance with the SimState” in the Simulink documentation). However, SimState is not supported for code generation, including with the Simulink Coder S-function target. 12-49 12 Desktops Profiling Code Performance Not Supported Profiling the performance of generated code using the Target Language Compiler (TLC) hook function interface described by the example model rtwdemo_profile is not supported for the S-function target. Limitations on Nesting S-Functions The following limitations apply to nesting a generated S-Function block in a model or subsystem from which you generate another S-function: • The software does not support nonvirtual bus input and output signals for a nested S-function. • You should avoid nesting an S-function in a model or subsystem having the same name as the S-function (possibly several levels apart). In such situations, the S-function can be called recursively. The software currently does not detect such loops in S-function dependency, which can result in aborting or hanging your MATLAB session. To prevent this from happening, be sure to name the subsystem or model to be generated as an S-function target uniquely, to avoid duplicating any existing MEX filenames on the MATLAB path. Limitations on User-Defined Data Types The Simulink Coder S-function target does not support the HeaderFile property that can be specified on user-defined data types, including those based on Simulink.AliasType, Simulink.Bus, and Simulink.NumericType objects. If a user-defined data type in your model uses the HeaderFile property to specify an associated header file, Simulink Coder S-function target code generation disregards the value and does not generate a corresponding include statement. Limitation on Right-Click Generation of an S-Function Target If you generate an S-function target by right-clicking a Function-Call Subsystem block, the original subsystem and the generated S-function might not be consistent. An inconsistency occurs when the States when enabling parameter of the Trigger Port block inside the Function-Call Subsystem block is set to inherit. You must set the States when enabling parameter to reset or held, otherwise Simulink reports an error. 12-50 Generated S-Function Block Limitation on S-Functions with Bus I/O Signals If an S-function generated using the S-function target has bus input or output signals, the generated bus data structures might include padding to align fields of the bus elements with the Simulink representation used during simulation. However, if you insert the S-function in a model and generate code using a model target such as grt.tlc, the bus structure alignment generated for the model build might be incompatible with the padding generated for the S-function and might affect the numerical results of code execution. To make the structure alignment consistent between model simulation and execution of the model code, for each Simulink.Bus object, you can modify the HeaderFile property to remove the unpadded bus structure header file. This will cause the bus typedefs generated for the S-function to be reused in the model code. Limitation on Subsystems with Function-Call I/O Signals The S-function target does not support creating an S-Function block from a subsystem that has a function-call trigger input or a function-call output. 12-51 12 12-52 Desktops 13 Real-Time Systems • “Real-Time System Rapid Prototyping” on page 13-2 • “Hardware-In-the-Loop (HIL) Simulation” on page 13-5 13 Real-Time Systems Real-Time System Rapid Prototyping In this section... “About Real-Time Rapid Prototyping” on page 13-2 “Goals of Real-Time Rapid Prototyping” on page 13-3 “Refine Code With Real-Time Rapid Prototyping” on page 13-3 About Real-Time Rapid Prototyping Real-time rapid prototyping requires the use of a real-time simulator, potentially connected to system hardware (for example, physical plant or vehicle) being controlled. You generate, deploy, and tune code as it runs on the real-time simulator or embedded microprocessor. This design step is crucial for verifying whether a component can adequately control the system, and allows you to assess, interact with, and optimize code. The following figure shows a typical approach for real-time rapid prototyping. System model Environment model Host Code generation Algorithm model Real-time simulator Tuning and logging Harness Actual environment (plants) 13-2 Real-Time System Rapid Prototyping Goals of Real-Time Rapid Prototyping Assuming that you have documented functional requirements, refined concept models, system hardware for the physical plant or vehicle being controlled, and access to target products you intend to use (for example, for example, the xPC Target or Real-Time Windows Target product), you can use real-time prototyping to: • Refine component and environment model designs by rapidly iterating between algorithm design and prototyping • Validate whether a component can adequately control the physical system in real time • Evaluate system performance before laying out hardware, coding production software, or committing to a fixed design • Test hardware Refine Code With Real-Time Rapid Prototyping To perform real-time rapid prototyping: 1 Create or acquire a real-time system that runs in real time on rapid prototyping hardware. The xPC Target product facilitates real-time rapid prototyping. This product provides a real-time operating system that makes PCs run in real time. It also provides device driver blocks for numerous hardware I/O cards. You can then create a rapid prototyping system using inexpensive commercial-off-the-shelf (COTS) hardware. In addition, third-party vendors offer products based on the xPC Target product or other code generation technology that you can integrate into a development environment. 2 Use Simulink Coder system target files to generate code that you can deploy onto a real-time simulator. See the following information. 13-3 13 Real-Time Systems Engineering Tasks Related Product Information Generate code for real-time rapid prototyping “Targets and Code Formats” on page 9-29 in the Simulink Coder documentation Examples rtwdemo_counter rtwdemo_async Embedded Coder “What Are the Standards and Guidelines?” in the Embedded Coder documentation Generate code for rapid prototyping in hard real time, using PCs xPC Target Generate code for rapid prototyping in soft real time, using PCs Real-Time Windows Target help xpcdemos “Setting Configuration Parameters” in the xPC Target documentation rtvdp (and others) “Code Generation Pane: Real-Time Windows Target” in the Real-Time Windows Target documentation 3 Monitor signals, tune parameters, and log data. 13-4 Hardware-In-the-Loop (HIL) Simulation Hardware-In-the-Loop (HIL) Simulation In this section... “About Hardware-In-the-Loop Simulation” on page 13-5 “Set Up and Run HIL Simulations” on page 13-6 About Hardware-In-the-Loop Simulation Hardware-in-the-loop (HIL) simulation tests and verifies an embedded system or control unit in the context of a software test platform. Examples of test platforms include real-time target systems and instruction set simulators (IISs). You use Simulink software to develop and verify a model that represents the test environment. Using the Simulink Coder product, you then generate, build, and download an executable for the model to the HIL simulation platform. After you set up the environment, you can run the executable to validate the embedded system or control unit in real time. During HIL simulation, you gradually replace parts of a system environment with hardware components as you refine and fabricate the components. HIL simulation offers an efficient design process that eliminates costly iterations of part fabrication. The code that you build for the system simulator provides real-time system capabilities. For example, the code can include VxWorks from Wind River or another real-time operating system (RTOS). The following figure shows a typical HIL setup. 13-5 13 Real-Time Systems Simulink Environment model Embedded system Code generation Code generation Algorithm model Harness Real-time simulator The HIL platform available from MathWorks is the xPC Target product. Several third-party products are also available for use as HIL platforms. The xPC Target product offers hard real-time performance for any PC with Intel® or AMD® 32-bit processors functioning as your real-time target. The xPC Target product enables you to add I/O interface blocks to your models and automatically generate code with code generation technology. The xPC Target product can download the code to a second PC running the xPC Target real-time kernel. System integrator solutions that are based on xPC Target are also available. Set Up and Run HIL Simulations To set up and run HIL simulations iterate through the following steps: 1 Develop a model that represents the environment or system under development. For more information, see: • “Targets and Code Formats” on page 9-29 2 Generate an executable for the environment model. 3 Download the executable for the environment model to the HIL simulation platform. 4 Replace software representing a system component with corresponding hardware. 5 Test the hardware in the context of the HIL system. 13-6 Hardware-In-the-Loop (HIL) Simulation 6 Repeat steps 4 and 5 until you can simulate the system after including all components that require testing. 13-7 13 13-8 Real-Time Systems 14 External Code Integration • “Integration Options” on page 14-2 • “Reuse Algorithmic Components in Generated Code” on page 14-5 • “Deploy Algorithm Code Within a Target Environment” on page 14-14 • “Export Generated Algorithm Code for Embedded Applications” on page 14-18 • “Export Algorithm Executables for System Simulation” on page 14-21 • “Modify External Code for Language Compatibility” on page 14-22 • “Automate S-Function Generation” on page 14-23 • “Integrate External Code Using Legacy Code Tool” on page 14-28 • “Configure Model for External Code Integration” on page 14-33 • “Insert Custom Code Blocks” on page 14-36 • “Insert S-Function Code” on page 14-46 14 External Code Integration Integration Options In this section... “About Integration Options” on page 14-2 “Types of External Code Integration” on page 14-2 About Integration Options The Simulink Coder product includes a variety of approaches for integrating legacy or custom code with generated code. Legacy code is existing handwritten code or code for environments that must be integrated with code generated by the Simulink Coder software. Custom code is legacy code or any other user-specified lines of code that must be included in the Simulink Coder build process. Collectively, legacy and custom code are called external code. There are two ways that you can achieve external code integration. You can import existing external code into code generated by code generation technology or you can export generated code into an existing external code base. For example, you might want to use generated code as a plug-in function. Types of External Code Integration Based on application goals, external code integration can be characterized as follows: • Import external code into generated code - Reuse of an algorithmic component in generated code Deploy an application with algorithm code within the target environment Generate target optimizations within algorithm code • Export generated code into external code - Export generated algorithm code for an embedded application Export an algorithm executable for system simulation Use the following flow diagram to prepare for integration and choose integration paths that best map to your application components. As the 14-2 Integration Options diagram shows, before you make integration decisions, assess your application architecture and partition it as much as possible. Working with smaller units makes it easier to map algorithms to modeling components and decide how to integrate the components. For each component, use the highlighted area of the flow diagram to identify the most applicable type of integration. Then, see the information provided for the corresponding type. 14-3 14 External Code Integration Assess application partitioning Map algorithms to modeling components For each component, decide... Integrate existing external code with generated code ? Yes Hardware independent, all C or C++ Example: lookup table ? Yes Reuse algorithmic component in generated code Yes Deploy with algorithm code within target environment No No Hardware specific, external to algorithm Example: device driver ? No Hardware specific, generated model code set up to run in real time Example: connection to timer interrupt or RTOS ? No Hardware specific, inside algorithm Example: optimized instructions ? Integrate generated code with existing external code ? No Use component as is 14-4 Yes Plug subsystem code into existing code base Example: specialized algorithm inserted into larger application ? No Plug object code into larger model Example: intellectual property protection ? Yes Yes Generate target optimizations within algorithm code Yes Export generated algorithm code for embedded application Yes Export algorithm executable for system simulation Reuse Algorithmic Components in Generated Code Reuse Algorithmic Components in Generated Code In this section... “Reusable Algorithmic Components” on page 14-5 “Integrate External MATLAB Code” on page 14-5 “Integrate External C or C++ Code” on page 14-8 “Integrate Fortran Code” on page 14-11 “Integration Considerations for Reusable Algorithmic Components” on page 14-11 Reusable Algorithmic Components You have several options for integrating reusable algorithmic components with the generated code. Such components are hardware-independent and can be verified with Simulink simulation. Examples of such components include: • Lookup tables • Math utilities • Digital filters • Special integrators • Proportional–integral–derivative (PID) control modules Some integration options allow you to integrate external code for a reusable component directly, while other options convert external code to modeling elements. To take full advantage of Model-Based Design, convert code to modeling elements which you can then use in the Simulink or Stateflow simulation environment. Doing so enables you to simulate and generate code for an integrated component and, for example, use software-in-the-loop (SIL) or processor-in-the-loop (PIL) testing to verify whether algorithm behavior is the same in both environments. Integrate External MATLAB Code The following diagram identifies common characteristics or requirements for reusable algorithmic components written in MATLAB code and recommends 14-5 14 External Code Integration solutions in each case. The table that follows the diagram provides more detail. Collectively, the diagram and table help you choose the best solution for your application and find more related information. MATLAB external code j Must model continuous state dynamics ? No Complies with MATLAB for code gen subset ? Yes k Yes Refactor code No Can refactor code to comply with MATLAB for code gen subset ? No Yes Embed code in MATLAB Function block No l Optimize for runtime performance or prepare to deploy in embedded system ? Yes m Yes Generate C source code, executable, or library file with MATLAB Coder No C/C++ programming experience and MATLAB code includes C or C++ constructs ? Yes Convert code to C or C++ by hand and use a C/C++ external code option No n Sections of MATLAB code map to built-in blocks ? Yes Identify applicable built-in blocks 14-6 Embed MATLAB code in model ? No Write MATLAB S-function and TLC file by hand Add S-function or blocks to model If necessary, add support files to and control model code generation andl builds Reuse Algorithmic Components in Generated Code If... Then... For More Information, See... The algorithm must model continuous state dynamics Write a MATLAB S-function and, for generating code, a corresponding TLC file for the algorithm and add the S-function to your model • “MATLAB S-Functions” 2 You want to embed MATLAB code directly in the model Add a MATLAB Function block to the model and embed the MATLAB code in that block MATLAB Function 3 You need to optimize runtime performance or prepare to deploy the code in an embedded system Use MATLAB Coder software to generate a C source code, executable, or library file “Getting Started with MATLAB Coder” 4 You have C or C++ programming experience and the external MATLAB code is compact and primarily uses C or C++ constructs Convert the MATLAB code to C or C++ code manually and choose an option for integrating the C or C++ code “Integrate External C or C++ Code” on page 14-8 5 Sections of the external MATLAB code map to built-in blocks Develop the algorithm in the context of a model, using the applicable built in blocks • “Modeling Basics” and “Component-Based Modeling” 1 • “Inline MATLAB File S-Functions” • “Supported Products and Block Usage” on page 1-92 To embed external MATLAB code in a MATLAB Function block or generate C or C++ code from MATLAB code with the MATLAB Coder software, the MATLAB code must use functions suitable for code generation. 14-7 14 External Code Integration Integrate External C or C++ Code The following diagram identifies common characteristics or requirements for reusable algorithmic components written in C or C++ code and recommends solutions in each case. The table that follows the diagram provides more detail. Collectively, the diagram and table will help you choose the best solution for your application and find more related information. C or C++ external code j Simulation environment ? Simulink lFull Use Stateflow Custom Code Interface Stateflow kMATLAB for code gen mModerate Level of flexibility and control ? Basic Call C code with coder.ceval function embedded in MATLAB Function block Generate S-function and TLC files with Legacy Code Tool n Generate S-function and TLC files with S-Function Builder (C only) Write or modify S-function and TLC files by hand Add S-function or blocks to model If necessary, add support files to and control model code generation andl builds 14-8 Fine tune generated files ? Yes No Reuse Algorithmic Components in Generated Code 1 2 3 4 5 If... Then... For More Information, See... The external code will simulate in a Stateflow environment Use the Stateflow custom code interface • sf_custom Performance is not an issue and you want to quickly embed a call to external C or C++ code in a model Call the C or C++ code with the coder.ceval function from a MATLAB Function block • coder.ceval function description You want maximum flexibility and the ability to control what code is generated; the application requires function overloading or you need to format data definitions such that they are compatible with a function Write an S-function and TLC file manually • “C S-Function Examples” and “C++ S-Function Examples” You want ease of use with moderate flexibility to control what code gets generated,typically for discrete applications; you have C or C++ programming experience, but prefer to generate the files that add the code to a model; optimizing generated code is essential Use the Legacy Code Tool to generate the S-function and TLC files; optionally, you can fine-tune the generated files manually to better meet application needs • rtwdemo_lct_lut_script You want ease of use with basic flexibility to control what code gets generated, typically Use the S-Function Builder to generate the S-function and TLC files; optionally, you can “Build S-Functions Automatically” in the Simulink documentation • “Calling Custom C Code Functions” in the Stateflow documentation • MATLAB Function block • “S-Function Basics” • “Insert S-Function Code” on page 14-46 • “Integrate C Functions Using Legacy Code Tool” in the Simulink documentation • “Integrate External Code Using Legacy Code Tool” on page 14-28 14-9 14 External Code Integration If... Then... for mixed discrete and continuous-time applications; programming experience is limited or the external code requires a Fixed-Point block interface fine tune the generated files manually to better meet application needs For More Information, See... If you must control how code generation technology declares, stores, and represents data in generated code, you can do so by designing (creating) and applying custom storage classes (CSCs) if you have an Embedded Coder license. For information on CSCs see the examples rtwdemo_cscpredef, rtwdemo_importstruct, and rtwdemo_advsc and “Custom Storage Classes” in the Embedded Coder documentation. 14-10 Reuse Algorithmic Components in Generated Code Integrate Fortran Code The following diagram shows that to integrate external Fortran code as reusable algorithmic components you must integrate the code by writing an S-function and corresponding TLC file. Fortran external code Write or modify S-function and TLC files by hand Add S-function to model If necessary, add support files to and control model code generation andl builds For information, see “Fortran S-Function Examples” and “Fortran S-Functions” Integration Considerations for Reusable Algorithmic Components Note Solutions marked with EC only require an Embedded Coder license. 14-11 14 14-12 External Code Integration If... Consider... For More Information, See... Generated code must use math functions and operators that are consistent with imported external code EC only—Using the code replacement library (CRL) API, Code Replacement Tool, and Code Replacement Viewer to create, examine, validate, and register function and operator replacement tables • rtwdemo_crl_script Generated code must share data with imported external code Using data creation and management technologies, such as Simulink data objects, alias and numeric data types, and data type replacement to match data type, formatting, and storage that is consistent with that used by the imported external code • “Data Types” Style and format of identifiers in generated code must be consistent with style and format applied in imported external code In the Configuration Parameters dialog box, on the Symbols pane, configure identifier naming for the generated code • rtwdemo_symbols • “Introduction to Code Replacement Libraries” in the Embedded Coder documentation • “Data Representation” • rtwdemo_namerules • “Configure Generated Identifiers” on page 9-73 and “Configure Generated Identifiers in Embedded System Code” in the Embedded Coder documentation Reuse Algorithmic Components in Generated Code If... Consider... For More Information, See... Use of comments in generated code must match the use of comments in imported external code In the Configuration Parameters dialog box, on the Comments pane, configure comments for the generated code • rtwdemo_comments Style of code, such as style and usage of parentheses, must be match the style used in imported external code EC only—In the Configuration Parameters dialog box, on the Code Style pane, configure the style for the generated code • rtwdemo_parentheses • “Configure Code Comments” on page 9-72 and “Configure Code Comments in Embedded System Code” in the Embedded Coder documentation • “Control Code Style” in the Embedded Coder documentation 14-13 14 External Code Integration Deploy Algorithm Code Within a Target Environment Code generation technology can generate a single set of application source files from an algorithm model and integrated external C or C++ code that supports the target environment hardware. For example, you might have a working device driver that you want to integrate with algorithmic code that has to read data from and write data to the I/O device the driver supports. Typically, a deployed model algorithm calls out to the external code. The following diagram identifies common characteristics or requirements for a target environment in which generated algorithm code might be deployed and recommends solutions. The table that follows the diagram provides more detail. Collectively, the diagram and table help you choose the best solution for your application and find more related information. 14-14 Deploy Algorithm Code Within a Target Environment External code j Embed call to hardware-specific code within generated algorithm code ? Yes Use Legacy Code Tool k Insert external code into entry-point functions generated for model ? l m Control organization and format of generated code files ? No Yes Level of control over placement of generated code ? Moderate Use Custom Code Configuration Parameter dialog boxto insert code n Use Custom Code blocks to insert code o Yes Use custom storage classes Yes Use memory sections Yes Generate and customize ERT target main program module No Insert comments or pragmas to identify sections of memory ? p Use custom file processing No Control data declaration, storage, and representation ? High Yes No Set up generated algorithmic code to run in real time ? No Done - no more choices 14-15 14 External Code Integration Note Solutions marked with EC only require an Embedded Coder license. 1 If You Need To... Then... For More Information, See... Embed a call to hardware-specific code, such as a device driver, within generated algorithm code Use the Legacy Code Tool • “Integrate Device Drivers” on page 24-135 • “Integrate C Functions Using Legacy Code Tool” in the Simulink documentation • “Integrate External Code Using Legacy Code Tool” on page 14-28 2 3 14-16 Insert target-specific C or C++ code into entry-point functions that Simulink Coder generates for a model with a high level of control over code placement; for example, inserting startup, initialization, or termination code Use Custom Code blocks Insert application-specific C or C++ code—near the top of the generated source code or header file or inside the model initialization or termination function—or files for the build process—source, header, library—for the external code Configure files and data for the external code environment by entering code and file specifications for parameters on the Code Generation > Interface pane of the Configuration Parameters dialog box • rtwdemo_slcustcode • “Insert Custom Code Blocks” on page 14-36 • Integrating the Generated Code into the External Environment • “Configure Model for External Code Integration” on page 14-33 Deploy Algorithm Code Within a Target Environment 4 5 6 If You Need To... Then... For More Information, See... Control the organization and format of code files generated for a model—for example, placement of code in sections, inclusion of banners, calls to generated entry-point functions, generation of a main program module EC only—Use the custom file processing components—code generation template (CGT) files, code template API, and custom file processing (CFP) templates (the API and CFP templates require TLC programming knowledge • rtwdemo_codetemplate Control how the Simulink Coder product declares, stores, and represents signals, tunable parameters, block states, and data objects in generated code EC only— Design (create) and apply custom storage classes Insert comments or EC only— Use the memory section capability pragmas in generated code to identify memory for custom storage classes or model- or subsystem-level functions and internal data 7 Set up generated algorithmic code to run in real time—within the context of a real-time operating system (RTOS) or on hardware that is not running an operating system (bare board) • “Customize Code Organization and Format” in the Embedded Coder documentation • rtwdemo_cscpredef • rtwdemo_importstruct • rtwdemo_advsc • “Custom Storage Classes” in the Embedded Coder documentation EC only—Generate and customize an ERT target main (harness) program module (ert_main.c or ert_main.cpp) for the model • rtwdemo_memsec • “About Memory Sections” • “Deployment” • “Standalone Programs (No Operating System)” 14-17 14 External Code Integration Export Generated Algorithm Code for Embedded Applications You have multiple options for configuring and preparing a model or subsystem so that you can plug its generated source code into an existing external code base. Scan the first column of the following table to identify tasks that apply to the algorithm code you want to export. For each task that applies, the information in the corresponding row describes how to achieve the goal, using code generation technology. Note Solutions marked with EC only require an Embedded Coder license. If You Need To... Then... For More Information, See... Insert C or C++ code into specific entry-point functions that Simulink Coder generates for interfacing with the external code Use Custom Code blocks • rtwdemo_slcustcode Pass composite data Represent the data in the model as a vector or bus • “Insert Custom Code Blocks” on page 14-36 • rtwdemo_scalarrep • rtwdemo_slbus • “Composite Signals” • “Optimize Code Generated for Vector Assignments” on page 19-6 and“Buses” Read from or write to a specific region or area of memory 14-18 EC only— Set up a Data Store Memory block in the model to represent the area of memory and define the area with the built-in advanced custom storage class (CSC) GetSet • “Increase Code Efficiency With GetSet CSC” • “GetSet Custom Storage Classes” in the Embedded Coder documentation Export Generated Algorithm Code for Embedded Applications If You Need To... Then... For More Information, See... Generate a C++ class interface—encapsulated model data (properties) and model entry-point functions (methods)—to the model code EC only— Configure and generate the C++ encapsulation interface in the Configuration Parameters dialog box or programmatically in the MATLAB command window or with a script • “Simple Use of C++ Encapsulation Control” Control how Embedded Coder generates function prototypes — arguments, argument order, and data types—for a model (for example, so the prototypes match the external code) EC only— Configure function prototypes for the model by clicking the Configure Model Functions button on the Code Generation > Interface pane of the Configuration Parameters dialog box and entering data in the Model Interface dialog box; alternatively, configure the function prototypes programmatically in the MATLAB command window or with a script • “Sample Procedure for Configuring Function Prototypes” Insert application-specific C or C++ code—near the top of the generated source code or header file or inside the model initialization or termination function—or files for the build process—source, header, Configure files and data for the external code environment by entering code and file specifications for parameters on the Code Generation > Interface pane of the Configuration Parameters dialog box • Integrating the Generated Code into the External Environment • “C++ Encapsulation Interface Control” in the Embedded Coder documentation • “Function Prototype Control” in the Embedded Coder documentation • “Configure Model for External Code Integration” on page 14-33 14-19 14 External Code Integration If You Need To... Then... For More Information, See... EC only— Review and adjust for exported subsystem requirements, configure the parent model to use an ERT target, and right-click build the subsystem block using the C/C++ Code > Export Functions menu item • “Techniques for Exporting Function-Call Subsystems” library—for the external code Generate code, which is to be integrated with an existing C code base, for a function-call or virtual subsystem 14-20 • rtwdemo_export_functions • “Export Function-Call Subsystems” in the Embedded Coder documentation Export Algorithm Executables for System Simulation Export Algorithm Executables for System Simulation If you have an Embedded Coder license, you can use an ERT shared library target (shrlib.tlc) to build a Windows dynamic link library (.dll) or a UNIX shared object (.so) file from a model. An application, which runs on a Windows or a UNIX system, can then load the shared library file. You can upgrade a shared library without having to recompile applications that use it. Uses of shared library files include: • Adding a software component to an application for system simulation • Reusing off-the-shelf software modules among applications on a host system • Hiding source code (intellectual property) for software shared with a vendor For an example, see rtwdemo_shrlib. For more information, see “Shared Object Libraries” in the Embedded Coder documentation. 14-21 14 External Code Integration Modify External Code for Language Compatibility If you need to integrate external C code with generated C++ code or vice versa, you must modify your external code to be language compatible with the generated code. Options for making the code language compatible include: • Writing or rewriting the legacy or custom code in the same language as the generated code. • If the generated code is in C++ and your legacy or custom code is in C, for each C function, create a header file that prototypes the function, using the following format: #ifdef __cplusplus extern "C" { #endif int my_c_function_wrapper(); #ifdef __cplusplus } #endif The prototype serves as a function wrapper. If your compiler supports C++ code, the value __cplusplus is defined. The linkage specification extern "C" specifies C linkage with no name mangling. • If the generated code is in C and your legacy or custom code is in C++, include an extern "C" linkage specification in each .cpp file. For example, the following shows a portion of C++ code in the file my_func.cpp: extern "C" { int my_cpp_function() { ... } } 14-22 Automate S-Function Generation Automate S-Function Generation The Generate S-function feature automates the process of generating an S-function from a subsystem. In addition, the Generate S-function feature presents a display of parameters used within the subsystem, and lets you declare selected parameters tunable. As an example, consider SourceSubsys, the same subsystem illustrated in the example “Create S-Function Blocks from a Subsystem” on page 12-37. The objective is to automatically extract SourceSubsys from the model and build an S-Function block from it, as in the previous example. In addition, the workspace variable K , which is the gain factor of the Gain block within SourceSubsys (as shown in the Gain block parameter dialog box below), is declared and generated as a tunable variable. To auto-generate an S-function from SourceSubsys with tunable parameter K, 1 With the SourceSubsys model open, click the subsystem to select it. 2 From the Code menu, select C/C++ Code > Generate S-Function. This menu item is enabled when a subsystem is selected in the current model. 14-23 14 External Code Integration Alternatively, you can right-click the subsystem and select C/C++ Code > Generate S-Function from the subsystem block’s context menu. 3 The Generate S-Function window is displayed (see the next figure). This window shows all variables (or data objects) that are referenced as block parameters in the subsystem, and lets you declare them as tunable. The upper pane of the window displays three columns: • Variable Name: name of the parameter. • Class: If the parameter is a workspace variable, its data type is shown. If the parameter is a data object, its name and class is shown • Tunable: Lets you select tunable parameters. To declare a parameter tunable, select the check box. In the next figure, the parameter K is declared tunable. When you select a parameter in the upper pane, the lower pane shows all the blocks that reference the parameter, and the parent system of each such block. Generate S-Function Window 14-24 Automate S-Function Generation 4 If you have installed the Embedded Coder product, and if the subsystem does not have a continuous sample time, the Create Software In the Loop (SIL) block check box is available, as shown above. Otherwise, it is appears dimmed. When Create Software In the Loop (SIL) block is selected, the build process generates a wrapper S-function by using the Embedded Coder product. See “Generate S-Function Wrappers” in the Embedded Coder documentation for more information. 5 After selecting tunable parameters, click the Build button. This initiates code generation and compilation of the S-function, using the S-function target. The Create New Model option is automatically enabled. 6 The build process displays status messages in the MATLAB Command Window. When the build completes, the tunable parameters window closes, and a new untitled model window opens. 7 The model window contains an S-Function block with the same name as the subsystem from which the block was generated (in this example, SourceSubsys). Optionally, you can save the generated model containing the generated block. 14-25 14 External Code Integration 8 The generated code for the S-Function block is stored in the current working folder. The following files are written to the top level folder: • subsys_sf.c or .cpp, where subsys is the subsystem name (for example, SourceSubsys_sf.c) • subsys_sf.h • subsys_sf.mexext, where mexext is a platform-dependent MEX-file extension (for example, SourceSubsys_sf.mexw32) The source code for the S-function is written to the subfolder subsys_sfcn_rtw. The top-level .c or .cpp file is a stub file that simply contains an include directive that you can use to interface other C/C++ code to the generated code. Note For a list of files required to deploy your S-Function block for simulation or code generation, see “Required Files for S-Function Deployment” on page 12-36. 9 The generated S-Function block has inports and outports whose widths and sample times correspond to those of the original model. The following code, from the mdlOutputs routine of the generated S-function code (in SourceSubsys_sf.c), shows how the tunable variable K is referenced by using calls to the MEX API. static void mdlOutputs(SimStruct *S, int_T tid) ... /* Gain: ' /Gain' incorporates: * Sum: ' /Sum' */ rtb_Gain_n[0] = (rtb_Product_p + (*(((const real_T**)ssGetInputPortSignalPtrs(S, 2))[0]))) * (*(real_T *)(mxGetData(K(S)))); rtb_Gain_n[1] = (rtb_Product_p + (*(((const real_T**)ssGetInputPortSignalPtrs(S, 2))[1]))) * (*(real_T *)(mxGetData(K(S)))); 14-26 Automate S-Function Generation Notes • In automatic S-function generation, the Use Value for Tunable Parameters option is always set to its default value (off). • A MEX S-function wrapper must only be used in the MATLAB version in which the wrapper is created. 14-27 14 External Code Integration Integrate External Code Using Legacy Code Tool In this section... “Legacy Code Tool and Code Generation” on page 14-28 “Generate Inlined S-Function Files for Code Generation” on page 14-29 “Apply Code Style Settings to Legacy Functions” on page 14-30 “Address Dependencies on Files in Different Locations” on page 14-31 “Deploy S-Functions for Simulation and Code Generation” on page 14-32 Legacy Code Tool and Code Generation You can use the Simulink Legacy Code Tool to automatically generate fully inlined C MEX S-functions for legacy or custom code that is optimized for embedded components, such as device drivers and lookup tables, that call existing C or C++ functions. Note The Legacy Code Tool can interface with C++ functions, but not C++ objects. For a work around so that the tool can interface with C++ objects, see “Legacy Code Tool Limitations” in the Simulink documentation. You can use the tool to: • Compile and build the generated S-function for simulation. • Generate a masked S-Function block that is configured to call the existing external code. If you want to include these types of S-functions in models for which you intend to generate code, you must use the tool to generate a TLC block file. The TLC block file specifies how the generated code for a model calls the existing C or C++ function. If the S-function depends on files in folders other than the folder containing the S-function dynamically loadable executable file, and you want to maintain those dependencies for building a model that includes the S-function, use the 14-28 Integrate External Code Using Legacy Code Tool tool to also generate an rtwmakecfg.m file for the S-function. For example, for some applications, such as custom targets, you might want to locate files in a target-specific location. The Simulink Coder build process looks for the generated rtwmakecfg.m file in the same folder as the S-function’s dynamically loadable executable and calls the rtwmakecfg function if the software finds the file. For more information, see “Integrate C Functions Using Legacy Code Tool” in the Simulink documentation. Generate Inlined S-Function Files for Code Generation Depending on your application’s code generation requirements, to generate code for a model that uses the S-function, you can choose to do either of the following: • Generate one .cpp file for the inlined S-function. In the Legacy Code Tool data structure, set the value of the Options.singleCPPMexFile field to true before generating the S-function source file from your existing C function. For example: def.Options.singleCPPMexFile = true; legacy_code('sfcn_cmex_generate', def); • Generate a source file and a TLC block file for the inlined S-function. For example: def.Options.singleCPPMexFile = false; legacy_code('sfcn_cmex_generate', def); legacy_code('sfcn_tlc_generate', def); singleCPPMexFile Limitations You cannot set the singleCPPMexFile field to true if • Options.language='C++' • You use one of the following Simulink objects with the IsAlias property set to true: - Simulink.Bus 14-29 14 External Code Integration - Simulink.AliasType Simulink.NumericType • The Legacy Code Tool function specification includes a void* or void** to represent scalar work data for a state argument • HeaderFiles field of the Legacy Code Tool structure specifies multiple header files Apply Code Style Settings to Legacy Functions To apply the model configuration parameters for code style to a legacy function: 1 Initialize the Legacy Code Tool data structure. For example: def = legacy_code('initialize'); 2 In the data structure, set the value of the Options.singleCPPMexFile field to true. For example: def.Options.singleCPPMexFile = true; To verify the setting, enter: def.Options.singleCPPMexFile singleCPPMexFile Limitations You cannot set the singleCPPMexFile field to true if • Options.language='C++' • You use one of the following Simulink objects with the IsAlias property set to true: - 14-30 Simulink.Bus Simulink.AliasType Simulink.NumericType Integrate External Code Using Legacy Code Tool • The Legacy Code Tool function specification includes a void* or void** to represent scalar work data for a state argument • HeaderFiles field of the Legacy Code Tool structure specifies multiple header files Address Dependencies on Files in Different Locations By default, the Legacy Code Tool assumes that all files on which an S-function depends reside in the same folder as the dynamically loadable executable file for the S-function. If your S-function depends on files that reside elsewhere and you are using the Simulink Coder template makefile build process, you must generate an rtwmakecfg.m file for the S-function. For example, it is likely that you need to generate this file if your Legacy Code Tool data structure defines compilation resources as path names. To generate the rtwmakecfg.m file, call the legacy_code function with 'rtwmakecfg_generate' as the first argument, and the name of the Legacy Code Tool data structure as the second argument. legacy_code('rtwmakecfg_generate', lct_spec); If you use multiple registration files in the same folder and generate an S-function for each file with a single call to legacy_code, the call to legacy_code that specifies 'rtwmakecfg_generate' must be common to all registration files. For more information, see “Handling Multiple Registration Files” in the Simulink documentation For example, if you define defs as an array of Legacy Code Tool structures, you call legacy_code with 'rtwmakecfg_generate' once. defs = [defs1(:);defs2(:);defs3(:)]; legacy_code('rtwmakecfg_generate', defs); For more information, see “Build Support for S-Functions” on page 14-120. 14-31 14 External Code Integration Deploy S-Functions for Simulation and Code Generation You can deploy the S-functions that you generate with the Legacy Code Tool so that other people can use them. To deploy an S-function for simulation and code generation, share the following files: • Registration file • Compiled dynamically loadable executable • TLC block file • rtwmakecfg.m file • All header, source, and include files on which the generated S-function depends Users of the deployed files must be aware that: • Before using the deployed files in a Simulink model, they must add the folder that contains the S-function files to the MATLAB path. • If the Legacy Code Tool data structure registers any required files as absolute paths and the location of the files changes, they must regenerate the rtwmakecfg.m file. 14-32 Configure Model for External Code Integration Configure Model for External Code Integration Configure a model using the Custom Code pane such that the code generator includes external code such as headers, files, and functions. You can also include additional files and paths in the build process. To... Select... Insert custom code near the top of the generated model.c or model.cpp file, outside of any function Source file and enter the custom code to insert. Insert custom code near the top of the generated model.h file Header file and enter the custom code to insert. Insert custom code inside the model’s initialize function in the model.c or model.cpp file Initialize function Insert custom code inside the model’s terminate function in the model.c or model.cpp file. Terminate function and enter the custom code to insert. Also select the Terminate function required parameter on the Interface pane. Add include folders, which contain header files, to the build process Include directories and enter the absolute or relative paths to the folders. If you specify relative paths, the paths must be relative to the folder containing your model files, not relative to the build folder. The order in which you specify the folders is the order in which they are searched for header, source, and library files. 14-33 14 External Code Integration To... Select... Add source files to be compiled and linked Source files and enter the full paths or just the file names for the files. Enter just the file name if the file is in the current MATLAB folder or in one of the include folders. For each additional source that you specify, the build process expands a generic rule in the template makefile for the folder in which the source file is found. For example, if a source file is found in folder inc, the build process adds a rule similar to the following: %.obj: buildir\inc\%.c $(CC) -c -Fo$(@F) $(CFLAGS) $< The build process adds the rules in the order you list the source files. 14-34 Add libraries to be linked Libraries and enter the full paths or just the file names for the libraries. Enter just the file name if the library is located in the current MATLAB folder or in one of the include folders. Use the same custom code settings as those specified for simulation of MATLAB Function blocks, Stateflow charts, and Truth Table blocks Use the same custom code settings as Simulation Target Enable a library model to use custom code settings unique from the parent model to which the library is linked Use local custom code settings (do not inherit from main model) Note This option refers to the Simulation Target pane in the Configuration Parameters dialog box. Note This option is available only for library models that contain MATLAB Function blocks, Stateflow charts, or Truth Table blocks. Configure Model for External Code Integration If you are including a header file, in your custom header file add #ifndef code. This avoids multiple inclusions. For example, in rtwtypes.h the following #include guards are added: #ifndef RTW_HEADER_rtwtypes_h_ #define RTW_HEADER_rtwtypes_h_ ... #endif /* RTW_HEADER_rtwtypes_h_ */ Note Custom code that you include in a configuration set is ignored when building S-function targets, accelerated simulation targets, and model reference simulation targets. For more information about Custom Code pane parameters, see “Code Generation Pane: Custom Code”. 14-35 14 External Code Integration Insert Custom Code Blocks The following sections explain how to use blocks in the Custom Code block library to insert custom code into the code generated for a model. This chapter includes the following topics: In this section... “Custom Code Library” on page 14-36 “Embed Custom Code Directly Into MdlStart Function” on page 14-40 “Custom Code in Subsystems” on page 14-43 “Preserve User Files in Build Folder” on page 14-44 Custom Code Library The Custom Code library contains blocks that enable you to insert your own C or C++ code into specific functions within code generated by the Simulink Coder product for root models and subsystems. These blocks are a superset of code customization capabilities built into the Custom Code Configuration Parameters dialog box, and provide greater flexibility in terms of code placement than the controls on the dialog box. The Custom Code library is part of the Simulink Coder library. You can access the Simulink Coder library by using the Simulink Library Browser. You can access Custom Code blocks by using the Simulink Coder library or by entering the MATLAB command rtwlib and then double-clicking the Custom Code Library block within it. Alternatively, you can enter the command custcode. 14-36 Insert Custom Code Blocks Note If you need to integrate custom C++ code with generated C code or vice versa, see “Modify External Code for Language Compatibility” on page 14-22. All Custom Code blocks except for Model Header and Model Source can be dragged into either root models or atomic subsystems. Model Header and Model Source blocks can only be placed in root models. Note You can use models containing Custom Code blocks as submodels (models referenced by Model blocks). However, when simulation targets for submodels are generated, all Custom Code blocks within them are ignored. On the other hand, when submodel code is generated to create Simulink Coder targets, custom code is included and is compiled in the generated code. The Custom Code library contains ten blocks that insert custom code into the generated model files and functions. You can view the blocks either by • Expanding the Custom Code node (under Simulink Coder library) in the Simulink Library Browser • Right-clicking the Custom Code sublibrary icon in the right pane of the Simulink Library Browser The latter method opens the window shown in the previous section. 14-37 14 External Code Integration The two blocks on the top row contain text fields for inserting custom code at the top and bottom of • model.h — Model Header File block • model.c or model.cpp — Model Source File block Each block contains two fields, in which you type or paste code and comments: • Top of Model Source/Header • Bottom of Model Source/Header The next figure shows the Model Source block dialog box. The eight function blocks in the second and third rows contain text fields to insert custom code sections at the top and bottom of these designated model functions: 14-38 Insert Custom Code Blocks • SystemStart — System Start function block • SystemInitialize — System Initialize function block • SystemTerminate — System Terminate function block • SystemEnable — System Enable function block • SystemDisable — System Disable function block • SystemOutputs — System Outputs function block • SystemUpdate — System Update function block • SystemDerivatives — System Derivatives function block Each of these blocks provides a System Outputs Function Custom Code dialog box that contains three fields: • Declaration code • Execution code • Exit code 14-39 14 External Code Integration Embed Custom Code Directly Into MdlStart Function The following example uses a System Start Function block to introduce code into the MdlStart function. The next figure shows a simple model with the System Start Function block inserted. 14-40 Insert Custom Code Blocks Double-clicking the System Start Function block opens the System Start Function Custom Code dialog box. 14-41 14 External Code Integration The code generator inserts the code entered here into the MdlStart function. You can insert custom code into any or all of the available text fields. 14-42 Insert Custom Code Blocks The code below is the MdlStart function for this example (mymodel). void MdlStart(void) { { { /* user code (Start function Header) */ /* System ' ' */ unsigned int *ptr = 0xFFEE; /* user code (Start function Body) */ /* System ' ' */ /* Initialize hardware */ *ptr = 0; } } MdlInitialize(); } The custom code entered in the System Start Function Custom Code dialog box is embedded directly in the generated code. Each block of custom code is tagged with a comment such as /* user code (Start function Header) */ Custom Code in Subsystems The location of a Custom Code block in your model determines the location of the code it contains. You can use System Custom Code blocks either at root level or within atomic subsystems; the code is local to the subsystem in which you place the blocks. For example, the System Outputs block places code in mdlOutputs when the code block resides in the root model. If the System Outputs block resides in a triggered or enabled subsystem, however, the code is placed in the subsystem’s Outputs function. The ordering for a triggered or enabled system is 1 Output entry 2 Output exit 14-43 14 External Code Integration 3 Update entry 4 Update exit Note If a root model or atomic subsystem does not need to generate a function for which a Custom Code block has been supplied, either the code in the block is not used or an error is generated. There is no diagnostic setting to control this. To eliminate the error, remove the Custom Code block. Preserve User Files in Build Folder Prior to Release 13 (Version 5.0), the Simulink Coder product did not delete any .c or .h files that you might have placed in the build folder when rebuilding targets. From Release 13 onward, all foreign source files are by default deleted during builds, but can be preserved by following the guidelines given below. If you put a .c/.cpp or .h source file in a build folder, and you want to prevent the Simulink Coder product from deleting it during the TLC code generation process, insert the string target specific file in the first line of the .c/.cpp or .h file. For example, /* COMPANY-NAME target specific file * * This file is created for use with the * COMPANY-NAME target. * It is used for ... */ ... Make sure you spell the string “target specific file” as shown in the preceding example, and that the string is in the first line of the source file. Other text can appear before or after this string. In addition to preserving them, flagging user files in this manner prevents postprocessing them to indent them along with generated source files. Auto-indenting occurred in previous releases to build folder files with names having the pattern model_*.c/.cpp (where * could be any string). The 14-44 Insert Custom Code Blocks indenting is harmless, but can cause differences to be detected by source control software that might trigger unnecessary updates. 14-45 14 External Code Integration Insert S-Function Code In this section... “About S-Functions and Code Generation” on page 14-46 “Write Noninlined S-Functions” on page 14-52 “Write Wrapper S-Functions” on page 14-54 “Write Fully Inlined S-Functions” on page 14-64 “Write Fully Inlined S-Functions with mdlRTW Routine” on page 14-65 “Guidelines for Writing Inlined S-Functions” on page 14-91 “Write S-Functions That Support Expression Folding” on page 14-91 “S-Functions That Specify Port Scope and Reusability” on page 14-105 “S-Functions That Specify Sample Time Inheritance Rules” on page 14-111 “S-Functions That Support Code Reuse” on page 14-113 “S-Functions for Multirate Multitasking Environments” on page 14-113 “Build Support for S-Functions” on page 14-120 About S-Functions and Code Generation This chapter describes how to create S-functions that work seamlessly with Simulink Coder code generation. It begins with basic concepts and concludes with an example of how to create a highly optimized direct-index lookup table S-Function block. This chapter assumes that you understand the following concepts: • Level 2 S-functions • Target Language Compiler (TLC) scripting • How the Simulink Coder software generates and builds C/C++ code 14-46 Insert S-Function Code Note When this chapter refers to actions performed by the Target Language Compiler, including parsing, caching, creating buffers, and so on, the name Target Language Compiler is spelled out fully. When referring to code written in the Target Language Compiler syntax, this chapter uses the abbreviation TLC. Note The guidelines presented in this chapter are for Simulink Coder users. Even if you do not currently use the Simulink Coder code generator, you should follow the practices presented in this chapter when writing S-functions, especially if you are creating general-purpose S-functions. Classes of Problems Solved by S-Functions S-functions help solve various kinds of problems you might face when working with the Simulink and Simulink Coder products. These problems include • Extending the set of algorithms (blocks) provided by the Simulink and Simulink Coder products • Interfacing legacy (hand-written) code with the Simulink and Simulink Coder products • Interfacing to hardware through device driver S-functions • Generating highly optimized code for embedded systems • Verifying code generated for a subsystem as part of a Simulink simulation S-functions are written using an application program interface (API) that allows you to implement generic algorithms in the Simulink environment with a great deal of flexibility. This flexibility cannot always be maintained when you use S-functions with the Simulink Coder code generator. For example, it is not possible to access the MATLAB workspace from an S-function that is used with the code generator. However, using the techniques presented in this chapter, you can create S-functions for most applications that work with the Simulink Coder generated code. 14-47 14 External Code Integration Although S-functions provide a generic and flexible solution for implementing complex algorithms in a Simulink model, the underlying API incurs overhead in terms of memory and computation resources. Most often the additional resources are acceptable for real-time rapid prototyping systems. In many cases, though, additional resources are unavailable in real-time embedded applications. You can minimize memory and computational requirements by using the Target Language Compiler technology provided with the Simulink Coder product to inline your S-functions. If you are producing an S-function for existing code, consider using the Simulink Legacy Code Tool. Types of S-Functions The implementation of S-functions changes based on your requirements. This chapter discusses the typical problems that you may face and how to create S-functions for applications that need to work with the Simulink and Simulink Coder products. These are some (informally defined) common situations: 1 “I’m not concerned with efficiency. I just want to write one version of my algorithm and have it work in the Simulink and Simulink Coder products automatically.” 2 “I have a lot of hand-written code that I need to interface. I want to call my function from the Simulink and Simulink Coder products in an efficient manner.” or said another way: “I want to create a block for my blockset that will be distributed throughout my organization. I’d like it to be very maintainable with efficient code. I’d like my algorithm to exist in one place but work with both the Simulink and Simulink Coder products.” 3 “I want to implement a highly optimized algorithm in the Simulink and Simulink Coder products that looks like a built-in block and generates very efficient code.” MathWorks products have adopted terminology for these different requirements. Respectively, the situations described above map to this terminology: 1 Noninlined S-function 14-48 Insert S-Function Code 2 Wrapper S-function 3 Fully inlined S-function Noninlined S-Functions. A noninlined S-function is a C or C++ MEX S-function that is treated identically by the Simulink engine and Simulink Coder generated code. In general, you implement your algorithm once according to the S-function API. The Simulink engine and Simulink Coder generated code call the S-function routines (for example, mdlOutputs) during model execution. Additional memory and computation resources are required for each instance of a noninlined S-Function block. However, this routine of incorporating algorithms into Simulink models and Simulink Coder applications is typical during the prototyping phase of a project where efficiency is not important. The advantage gained by forgoing efficiency is the ability to change model parameters and structures rapidly. Writing a noninlined S-function does not involve any TLC coding. Noninlined S-functions are the default case for the Simulink Coder build process in the sense that once you build a MEX S-function in your model, there is no additional preparation prior to clicking Build in the Code Generation pane of the Configuration Parameters dialog box for your model. Some restrictions exist concerning the names and locations of noninlined S-function files when generating makefiles. See “Write Noninlined S-Functions” on page 14-52. Wrapper S-Functions. A wrapper S-function is ideal for interfacing hand-written code or a large algorithm that is encapsulated within a few procedures. In this situation, usually the procedures reside in modules that are separate from the MEX S-function. The S-function module typically contains a few calls to your procedures. Because the S-function module does not contain any parts of your algorithm, but only calls your code, it is referred to as a wrapper S-function. In addition to the MEX S-function wrapper, you need to create a TLC wrapper that complements your S-function. The TLC wrapper is similar to the S-function wrapper in that it contains calls to your algorithm. 14-49 14 External Code Integration Fully Inlined S-Functions. For S-functions to work in the Simulink environment, some overhead code is generated. When the Simulink Coder software generates code from models that contain S-functions (without sfunction.tlc files), it embeds some of this overhead code in the generated code. If you want to optimize your real-time code and eliminate some of the overhead code, you must inline (or embed) your S-functions. This involves writing a TLC (sfunction.tlc) file that eliminates all overhead code from the generated code. The Target Language Compiler processes sfunction.tlc files to define how to inline your S-function algorithm in the generated code. Note The term inline should not be confused with the C++ inline keyword. In Simulink Coder terminology, inline means to specify a text string in place of the call to the general S-function API routines (for example, mdlOutputs). For example, when a TLC file is used to inline an S-function, the generated code contains the C/ C++ code that would normally appear within the S-function routines and the S-function itself has been removed from the build process. A fully inlined S-function builds your algorithm (block) into Simulink Coder generated code in a manner that is indistinguishable from a built-in block. Typically, a fully inlined S-function requires you to implement your algorithm twice: once for the Simulink model (C/C++ MEX S-function) and once for Simulink Coder code generation (TLC file). The complexity of the TLC file depends on the complexity of your algorithm and the level of efficiency you’re trying to achieve in the generated code. TLC files vary from simple to complex in structure. The Simulink Legacy Code Tool can automate the generation of a fully inlined S-function and a corresponding TLC file based on information that you register in a Legacy Code Tool data structure. For more information, see “Integrate C Functions Using Legacy Code Tool” in the Simulink Writing S-Functions documentation and “Integrate External Code Using Legacy Code Tool” on page 14-28. Basic Files Required for Implementation This section briefly describes what files and functions you need to create noninlined, wrapper, and fully inlined S-functions. 14-50 Insert S-Function Code • Noninlined S-functions require the C or C++ MEX S-function source code (sfunction.c or sfunction.cpp). • Wrapper S-functions that inline a call to your algorithm (your C/C++ function) require an sfunction.tlc file. • Fully inlined S-functions also require an sfunction.tlc file. Fully inlined S-functions produce the optimal code for a parameterized S-function. This is an S-function that operates in a specific mode dependent upon fixed S-function parameters that do not change during model execution. For a given operating mode, the sfunction.tlc file specifies the exact code that is generated to implement the algorithm for that mode. For example, the direct-index lookup table S-function at the end of this chapter contains two operating modes — one for evenly spaced x-data and one for unevenly spaced x-data. Fully inlined S-functions might require the placement of the mdlRTW routine in your S-function MEX-file sfunction.c or sfunction.cpp. The mdlRTW routine lets you place information in model.rtw, the record file that specifies a model, and which the Simulink Coder code generator invokes the Target Language Compiler to process prior to executing sfunction.tlc when generating code. Including a mdlRTW routine is useful when you want to introduce nontunable parameters into your TLC file. Such parameters are generally used to determine which operating mode is active in a given instance of the S-function. Based on this information, the TLC file for the S-function can generate highly efficient, optimal code for that operating mode. Guidelines for Writing S-Functions • Use only C MEX S-functions with the Simulink Coder code generator. You cannot use Level-1 MATLAB language S-functions with Simulink Coder software. • To inline an S-function, use the Legacy Code Tool. The Legacy Code Tool automatically generates fully inlined C MEX S-functions for legacy or custom code. In addition, the tool generates other files for compiling and building the S-function for simulation and generate a masked S-function block configured to call existing external code. For more information, see “Integrate C Functions Using Legacy Code Tool” in the Simulink 14-51 14 External Code Integration documentation and “Integrate External Code Using Legacy Code Tool” on page 14-28. • If you are rapid prototyping, you might not have to inline an S-function.. If you choose not to inline the C MEX S-function, write the S-function, include it directly in the model, and let the Simulink Coder software generate the code. For more information, see “Write Noninlined S-Functions” on page 14-52. Write Noninlined S-Functions • “About Noninlined S-Functions” on page 14-52 • “Guidelines for Writing Noninlined S-Functions” on page 14-52 • “Noninlined S-Function Parameter Type Limitations” on page 14-54 About Noninlined S-Functions Noninlined S-functions are identified by the absence of an sfunction.tlc file for your S-function. The filename varies depending on your platform. For example, on a 32–bit Microsoft Windows system, the file name would be sfunction.mexw32. Type mexext in the MATLAB Command Window to see which extension your system uses. Guidelines for Writing Noninlined S-Functions • The MEX-file cannot call MATLAB functions. • If the MEX-file uses functions in the MATLAB External Interface libraries, include the header file cg_sfun.h instead of mex.h or simulink.c. To handle this case, include the following lines at the end of your S-function: #ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ #include "simulink.c" /* MEX-file interface mechanism */ #else #include "cg_sfun.h" /* Code generation registration function */ #endif • Use only MATLAB API function that the code generator supports, which include: 14-52 Insert S-Function Code mxGetEps mxGetInf mxGetM mxGetN mxGetNaN mxGetPr mxGetScalar mxGetString mxIsEmpty mxIsFinite mxIsInf • MEX library calls are not supported in generated code. To use such calls in MEX-file and not in the generated code, conditionalize the code as follows: #ifdef MATLAB_MEX_FILE #endif • Use only full matrices that contain only real data. • Do not specify a return value for calls to mxGetString . If you do specify a return value, the MEX-file will not compile. Instead, use the function’s second input argument, which returns a pointer to a string. • Make sure that the #define s-function_name statement is correct. The S-function name that you specify must match the S-function’s filename. • Use the data types real_T and int_T instead of double and int, if possible. The data types real_T and int_T are more generic and can be used in multiple environments. • Provide the Simulink Coder build process with the names of all modules used to build the S-function. You can do this by using the Simulink Coder template make file or the set_param function. For example, suppose you build your S-function with the following command: mex sfun_main.c sfun_module1.c sfun_module2.c You can then use the following call to set_param to include all the required modules: set_param(sfun_block, "SFunctionModules","sfun_module1 sfun_module2') 14-53 14 External Code Integration Noninlined S-Function Parameter Type Limitations Parameters to noninlined S-functions can be of the following types only: • Double precision • Characters in scalars, vectors, or 2-D matrices For more flexibility in the type of parameters you can supply to S-functions or the operations in the S-function, inline your S-function and consider using an mdlRTW S-function routine. Use of other functions from the MATLAB matrix.h API or other MATLAB APIs, such as mex.h and mat.h, is not supported. If you call unsupported APIs from an S-function source file, compiler errors occur. See the file matlabroot/rtw/c/src/rt_matrx.h(.c) for details on supported MATLAB API functions. If you use mxGetPr on an empty matrix, the function does not return NULL; rather, it returns a random value. Therefore, you should protect calls to mxGetPr with mxIsEmpty. Write Wrapper S-Functions • “About Wrapper S-Functions” on page 14-54 • “MEX S-Function Wrapper” on page 14-55 • “TLC S-Function Wrapper” on page 14-59 • “The Inlined Code” on page 14-64 About Wrapper S-Functions This section describes how to create S-functions that work seamlessly with the Simulink and Simulink Coder products using the wrapper concept. This section begins by describing how to interface your algorithms in Simulink models by writing MEX S-function wrappers (sfunction.mex). It finishes with a description of how to direct the code generator to insert your algorithm into the generated code by creating a TLC S-function wrapper (sfunction.tlc). 14-54 Insert S-Function Code MEX S-Function Wrapper Creating S-functions using an S-function wrapper allows you to insert C/C++ code algorithms in Simulink models and Simulink Coder generated code with little or no change to your original C/C++ function. A MEX S-function wrapper is an S-function that calls code that resides in another module. A TLC S-function wrapper is a TLC file that specifies how the code generator should call your code (the same code that was called from the C MEX S-function wrapper). Note A MEX S-function wrapper must only be used in the MATLAB version in which the wrapper is created. Suppose you have an algorithm (that is, a C function) called my_alg that resides in the file my_alg.c. You can integrate my_alg into a Simulink model by creating a MEX S-function wrapper (for example, wrapsfcn.c). Once this is done, a Simulink model can call my_alg from an S-Function block. However, the Simulink S-function contains a set of empty functions that the Simulink engine requires for various API-related purposes. For example, although only mdlOutputs calls my_alg, the engine calls mdlTerminate as well, even though this S-function routine performs no action. You can integrate my_alg into generated code (that is, embed the call to my_alg in the generated code) by creating a TLC S-function wrapper (for example, wrapsfcn.tlc). The advantage of creating a TLC S-function wrapper is that the empty function calls can be eliminated and the overhead of executing the mdlOutputs function and then the my_alg function can be eliminated. Wrapper S-functions are useful when you are creating new algorithms that are procedural in nature or when you are integrating legacy code into a Simulink model. However, if you want to create code that is • Interpretive in nature (that is, highly parameterized by operating modes) • Heavily optimized (that is, no extra tests to decide what mode the code is operating in) then you must create a fully inlined TLC file for your S-function. 14-55 14 External Code Integration The next figure shows the wrapper S-function concept. Simulink Coder wrapper.c, the generated code, calls mdlOutputs, which then calls my_alg. Simulink Place the name of your S-function in the S-Function block dialog box. wrapper.mdl wrapsfcn *See note below S-function In Simulink, the S-function calls mdlOutputs, which in turn calls my_alg. wrapsfcn.c ... mdlOutputs(...) { ... my_alg(); } mdlOutputs in wrapsfcn.mex calls external function my_alg. wrapper.c ... MdlOutputs(...) { ... my_alg(); } In the TLC wrapper version of the S-function, mdlOutputs in wrapper.exe calls my_alg. my_alg.c ... real_T my_alg(real_T u) { ... y=f(u); } *The dotted line is the path taken if the S-function does not have a TLC wrapper file. If there is no TLC wrapper file, the generated code calls mdlOutputs. Using an S-function wrapper to import algorithms in your Simulink model means that the S-function serves as an interface that calls your C/C++ algorithms from mdlOutputs. S-function wrappers have the advantage that you can quickly integrate large standalone C /C++ programs into your model without having to make changes to the code. 14-56 Insert S-Function Code The following sample model includes an S-function wrapper. There are two files associated with the wrapsfcn block, the S-function wrapper and the C/C++ code that contains the algorithm. The S-function wrapper code for wrapsfcn.c appears below. The first three statements do the following: 1 Defines the name of the S-function (what you enter in the Simulink S-Function block dialog). 2 Specifies that the S-function is using the level 2 format. 3 Provides access to the SimStruct data structure, which contains pointers to data used during simulation and code generation and defines macros that store data in and retrieve data from the SimStruct. For more information, see “Templates for C S-Functions” in the Simulink documentation. #define S_FUNCTION_NAME wrapsfcn #define S_FUNCTION_LEVEL 2 #include "simstruc.h" extern real_T my_alg(real_T u); /* Declare my_alg as extern */ /* * mdlInitializeSizes - initialize the sizes array */ static void mdlInitializeSizes(SimStruct *S) { ssSetNumSFcnParams( S, 0); /*number of input arguments*/ if (!ssSetNumInputPorts(S, 1)) return; 14-57 14 External Code Integration ssSetInputPortWidth(S, 0, 1); ssSetInputPortDirectFeedThrough(S, 0, 1); if (!ssSetNumOutputPorts(S,1)) return; ssSetOutputPortWidth(S, 0, 1); ssSetNumSampleTimes( S, 1); } /* * mdlInitializeSampleTimes - indicate that this S-function runs * at the rate of the source (driving block) */ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); } /* * mdlOutputs - compute the outputs by calling my_alg, which * resides in another module, my_alg.c */ static void mdlOutputs(SimStruct *S, int_T tid) { InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); real_T *y = ssGetOutputPortRealSignal(S,0); *y = my_alg(*uPtrs[0]); /* Call my_alg in mdlOutputs */ } /* * mdlTerminate - called when the simulation is terminated. */ static void mdlTerminate(SimStruct *S) { } #ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ #include "simulink.c" /* MEX-file interface mechanism */ #else 14-58 Insert S-Function Code #include "cg_sfun.h" /* Code generation registration function */ #endif The S-function routine mdlOutputs contains a function call to my_alg, which is the C function containing the algorithm that the S-function performs. This is the code for my_alg.c: #ifdef MATLAB_MEX_FILE #include "tmwtypes.h" #else #include "rtwtypes.h" #endif real_T my_alg(real_T u) { return(u * 2.0); } See the section “Header Dependencies When Interfacing Legacy/Custom Code with Generated Code” on page 10-6 in the Simulink Coder documentation for more information. The wrapper S-function wrapsfcn calls my_alg, which computes u * 2.0. To build wrapsfcn.mex, use the following command: mex wrapsfcn.c my_alg.c TLC S-Function Wrapper This section describes how to inline the call to my_alg in the mdlOutputs section of the generated code. In the above example, the call to my_alg is embedded in the mdlOutputs section as *y = my_alg(*uPtrs[0]); When you are creating a TLC S-function wrapper, the goal is to embed the same type of call in the generated code. It is instructive to look at how the code generator executes S-functions that are not inlined. A noninlined S-function is identified by the absence of the file sfunction.tlc and the existence of sfunction.mex. When generating 14-59 14 External Code Integration code for a noninlined S-function, the Simulink Coder software generates a call to mdlOutputs through a function pointer that, in this example, then calls my_alg. The wrapper example contains one S-function, wrapsfcn.mex. You must compile and link an additional module, my_alg, with the generated code. To do this, specify set_param('wrapper/S-Function','SFunctionModules','my_alg') Code Overhead for Noninlined S-Functions. The code generated when using grt.tlc as the system target file without wrapsfcn.tlc is #include #include #include "wrapper.h" #include "wrapper.prm" /* Start the model */ void mdlStart(void) { /* (no start code required) */ } /* Compute block outputs */ void mdlOutputs(int_T tid) { /* Sin Block: /Sin */ rtB.Sin = rtP.Sin.Amplitude * sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase); /* Level2 S-Function Block: /S-Function (wrapsfcn) */ { /* Noninlined S-functions create a SimStruct object and * generate a call to S-function routine mdlOutputs */ SimStruct *rts = ssGetSFunction(rtS, 0); sfcnOutputs(rts, tid); } 14-60 Insert S-Function Code /* Outport Block: /Out */ rtY.Out = rtB.S_Function; } /* Perform model update */ void mdlUpdate(int_T tid) { /* (no update code required) */ } /* Terminate function */ void mdlTerminate(void) { /* Level2 S-Function Block: /S-Function (wrapsfcn) */ { /* Noninlined S-functions require a SimStruct object and * the call to S-function routine mdlTerminate */ SimStruct *rts = ssGetSFunction(rtS, 0); sfcnTerminate(rts); } } #include "wrapper.reg" /* [EOF] wrapper.c */ In addition to the overhead outlined above, the wrapper.reg generated file contains the initialization of the SimStruct for the wrapper S-Function block. There is one child SimStruct for each S-Function block in your model. You can significantly reduce this overhead by creating a TLC wrapper for the S-function. How to Inline. The generated code makes the call to your S-function, wrapsfcn.c, in mdlOutputs by using this code: SimStruct *rts = ssGetSFunction(rtS, 0); sfcnOutputs(rts, tid); 14-61 14 External Code Integration This call has computational overhead associated with it. First, the Simulink engine creates a SimStruct data structure for the S-Function block. Second, the code generator constructs a call through a function pointer to execute mdlOutputs, then mdlOutputs calls my_alg. By inlining the call to your C/C++ algorithm, my_alg, you can eliminate both the SimStruct and the extra function call, thereby improving the efficiency and reducing the size of the generated code. Inlining a wrapper S-function requires an sfunction.tlc file for the S-function (see the “Target Language Compiler” for details). The TLC file must contain the function call to my_alg. The following figure shows the relationships between the algorithm, the wrapper S-function, and the sfunction.tlc file. The wrapsfcn.tlc file tells Simulink Coder how to inline the call to my_alg using this statement. wrapsfcn.tlc ... % = my_alg(%); ... wrapper.c ... mdlOutputs { ... y = my_alg(); ... } ... my_alg.c myalg() { } To inline this call, you have to place your function call in an sfunction.tlc file with the same name as the S-function (in this example, wrapsfcn.tlc). This causes the Target Language Compiler to override the default method of placing calls to your S-function in the generated code. This is the wrapsfcn.tlc file that inlines wrapsfcn.c. %% File : wrapsfcn.tlc %% Abstract: %% Example inlined tlc file for S-function wrapsfcn.c %% %implements "wrapsfcn" "C" 14-62 Insert S-Function Code %% Function: BlockTypeSetup ==================================================== %% Abstract: %% Create function prototype in model.h as: %% "extern real_T my_alg(real_T u);" %% %function BlockTypeSetup(block, system) void %openfile buffer extern real_T my_alg(real_T u); /* This line is placed in wrapper.h */ %closefile buffer % %endfunction %% BlockTypeSetup %% Function: Outputs =========================================================== %% Abstract: %% y = my_alg( u ); %% %function Outputs(block, system) Output /* % Block: % */ %assign u = LibBlockInputSignal(0, "", "", 0) %assign y = LibBlockOutputSignal(0, "", "", 0) %% PROVIDE THE CALLING STATEMENT FOR "algorithm" %% The following line is expanded and placed in mdlOutputs within wrapper.c % = my_alg(%); %endfunction %% Outputs The first section of this code inlines the wrapsfcn S-Function block and generates the code in C: %implements "wrapsfcn" "C" The next task is to tell the code generator that the routine my_alg needs to be declared external in the generated wrapper.h file for any wrapsfcn S-Function blocks in the model. You only need to do this once for all wrapsfcn S-Function blocks, so use the BlockTypeSetup function. In this function, you tell the Target Language Compiler to create a buffer and cache the my_alg as extern in the wrapper.h generated header file. 14-63 14 External Code Integration The final step is the inlining of the call to the function my_alg. This is done by the Outputs function. In this function, you access the block’s input and output and place a direct call to my_alg. The call is embedded in wrapper.c. The Inlined Code The code generated when you inline your wrapper S-function is similar to the default generated code. The mdlTerminate function no longer contains a call to an empty function and the mdlOutputs function now directly calls my_alg. void mdlOutputs(int_T tid) { /* Sin Block: /Sin */ rtB.Sin = rtP.Sin.Amplitude * sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase); /* S-Function Block: /S-Function */ rtB.S_Function = my_alg(rtB.Sin); /* Inlined call to my_alg */ /* Outport Block: /Out */ rtY.Out = rtB.S_Function; } In addition, wrapper.reg no longer creates a child SimStruct for the S-function because the generated code is calling my_alg directly. This eliminates over 1 KB of memory usage. Write Fully Inlined S-Functions Continuing the example of the previous section, you could eliminate the call to my_alg entirely by specifying the explicit code (that is, 2.0 * u) in wrapsfcn.tlc. This is referred to as a fully inlined S-function. While this can improve performance, if you are working with a large amount of C/C++ code, this can be a lengthy task. In addition, you now have to maintain your algorithm in two places, the C/C++ S-function itself and the corresponding TLC file. However, the performance gains might outweigh the disadvantages. To inline the algorithm used in this example, in the Outputs section of your wrapsfcn.tlc file, instead of writing % = my_alg(%); 14-64 Insert S-Function Code use % = 2.0 * %; This is the code produced in mdlOutputs: void mdlOutputs(int_T tid) { /* Sin Block: /Sin */ rtB.Sin = rtP.Sin.Amplitude * sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase); /* S-Function Block: /S-Function */ rtB.S_Function = 2.0 * rtB.Sin; /* Explicit embedding of algorithm */ /* Outport Block: /Out */ rtY.Out = rtB.S_Function; } The Target Language Compiler has replaced the call to my_alg with the algorithm itself. Multiport S-Function A more advanced multiport inlined S-function example is sfun_multiport.c and sfun_multiport.tlc. This S-function illustrates how to create a fully inlined TLC file for an S-function that contains multiple ports. You might find that looking at this example helps you to understand fully inlined TLC files. Write Fully Inlined S-Functions with mdlRTW Routine • “About S-Functions and mdlRTW” on page 14-66 • “S-Function RTWdata” on page 14-67 • “Direct-Index Lookup Table Algorithm” on page 14-67 • “Direct-Index Lookup Table Example” on page 14-69 14-65 14 External Code Integration About S-Functions and mdlRTW You can inline more complex S-functions that use the S-function mdlRTW routine. The purpose of the mdlRTW routine is to provide the code generation process with more information about how the S-function is to be inlined, by creating a parameter record of a nontunable parameter for use with a TLC file. The mdlRTW routine does this by placing information in the model.rtw file. The mdlRTW function is described in the text file matlabroot/simulink/src/sfuntmpl_doc.c. As an example of how to use the mdlRTW function, this section discusses the steps you must take to create a direct-index lookup S-function. Lookup tables are collections of ordered data points of a function. Typically, these tables use some interpolation scheme to approximate values of the associated function between known data points. To incorporate the example lookup table algorithm into a Simulink model, the first step is to write an S-function that executes the algorithm in mdlOutputs. To produce the most efficient code, the next step is to create a corresponding TLC file to eliminate computational overhead and improve the performance of the lookup computations. For your convenience, the Simulink product provides support for two general-purpose lookup 1-D and 2-D algorithms. You can use these algorithms as they are or create a custom lookup table S-function to fit your requirements. This section illustrates how to create a 1-D lookup S-function, sfun_directlook.c, and its corresponding inlined sfun_directlook.tlc file (see “Target Language Compiler” for more details). This 1-D direct-index lookup table example illustrates the following concepts that you need to know to create your own custom lookup tables: • Error checking of S-function parameters • Caching of information for the S-function that doesn’t change during model execution • How to use the mdlRTW function to customize Simulink Coder generated code to produce the optimal code for a given set of block parameters • How to generate an inlined TLC file for an S-function in a combination of the fully inlined form and/or the wrapper form 14-66 Insert S-Function Code S-Function RTWdata There is a property of blocks called RTWdata, which can be used by the Target Language Compiler when inlining an S-function. RTWdata is a structure of strings that you can attach to a block. It is saved with the model and placed in the model.rtw file when generating code. For example, this set of MATLAB commands, mydata.field1 = 'information for field1'; mydata.field2 = 'information for field2'; set_param(gcb,'RTWdata',mydata) get_param(gcb,'RTWdata') produces this result: ans = field1: 'information for field1' field2: 'information for field2' Inside the model.rtw file for the associated S-Function block is this information. Block { Type RTWdata { field1 field2 } "S-Function" "information for field1" "information for field2" Note RTWdata is saved in the model file for S-functions that are not linked to a library. However, RTWdata is not persistent for S-Function blocks that are linked to a library. Direct-Index Lookup Table Algorithm The 1-D lookup table block provided in the Simulink library uses interpolation or extrapolation when computing outputs. This extra accuracy might not be required. In this example, you create a lookup table that directly indexes the output vector (y-data vector) based on the current input (x-data) point. 14-67 14 External Code Integration This direct 1-D lookup example computes an approximate solution p(x) to a partially known function f(x) at x=x0, given data point pairs (x,y) in the form of an x-data vector and a y-data vector. For a given data pair (for example, the i’th pair), y_i = f(x_i). It is assumed that the x-data values are monotonically increasing. If x0 is outside the range of the x-data vector, the first or last point is returned. The parameters to the S-function are XData, YData, XEvenlySpaced XData and YData are double vectors of equal length representing the values of the unknown function. XDataEvenlySpaced is a scalar, 0.0 for false and 1.0 for true. If the XData vector is evenly spaced, XDataEvenlySpaced is 1.0 and more efficient code is generated. The following graph shows how the parameters XData=[1:6]and YData=[1,2,7,4,5,9] are handled. For example, if the input (x-value) to the S-Function block is 3, the output (y-value) is 7. 14-68 Insert S-Function Code Direct-Index Lookup Table Example This section shows how to improve the lookup table by inlining a direct-index S-function with a TLC file. This direct-index lookup table S-function does not require a TLC file. Here the example uses a TLC file for the direct-index lookup table S-function to reduce the code size and increase efficiency of the generated code. Implementation of the direct-index algorithm with inlined TLC file requires the S-function main module, sfun_directlook.c, and a corresponding 14-69 14 External Code Integration lookup_index.c module. The lookup_index.c module contains the GetDirectLookupIndex function that is used to locate the index in the XData for the current x input value when the XData is unevenly spaced. The GetDirectLookupIndex routine is called from both the S-function and the generated code. Here the example uses the wrapper concept for sharing C/C++ code between Simulink MEX-files and the generated code. If the XData is evenly spaced, then both the S-function main module and the generated code contain the lookup algorithm (not a call to the algorithm) to compute the y-value of a given x-value, because the algorithm is short. This illustrates the use of a fully inlined S-function for generating optimal code. The inlined TLC file, which either performs a wrapper call or embeds the optimal C/C++ code, is sfun_directlook.tlc (see the example in “mdlRTW Usage” on page 14-71). Error Handling. In this example, the mdlCheckParameters routine verifies that • The new parameter settings valid.. • XData and YData are vectors of the same length containing real finite numbers. • XDataEvenlySpaced is a scalar. • The XData vector is a monotonically increasing vector and evenly spaced. The mdlInitializeSizes function explicitly calls mdlCheckParameters after it verifies the number of parameters passed to the S-function. After the Simulink engine calls mdlInitializeSizes, it then calls mdlCheckParameters whenever you change the parameters or there is a need to reevaluate them. User Data Caching. The mdlStart routine shows how to cache information that does not change during the simulation (or while the generated code is executing). The example caches the value of the XDataEvenlySpaced parameter in UserData, a field of the SimStruct. The following line in mdlInitializeSizes tells the Simulink engine to disallow changes to XDataEvenlySpaced. ssSetSFcnParamTunable(S, iParam, SS_PRM_NOT_TUNABLE); 14-70 Insert S-Function Code During execution, mdlOutputs accesses the value of XDataEvenlySpaced from UserData rather than calling the mxGetPr MATLAB API function. This increases performance. mdlRTW Usage. The Simulink Coder code generator calls the mdlRTW routine while generating the model.rtw file. To produce optimal code for your Simulink model, you can add information to the model.rtw file about the mode in which your S-Function block is operating. The following example adds parameter settings to the model.rtw file. The parameter settings do not change during execution. In this case, the XDataEvenlySpaced S-function parameter cannot change during execution (ssSetSFcnParamTunable was specified as false (0) for it in mdlInitializeSizes). The example writes it out as a parameter setting (XSpacing) using the function ssWriteRTWParamSettings. Because xData and yData are registered as run-time parameters in mdlSetWorkWidths, the code generator handles writing to the model.rtw file automatically. Before examining the S-function and the inlined TLC file, consider the generated code for the following model. 14-71 14 External Code Integration The model uses evenly spaced XData in the top S-Function block and unevenly spaced XData in the bottom S-Function block. When creating this model, you need to specify the following for each S-Function block. set_param(`sfun_directlook_ex/S-Function','SFunctionModules','lookup_index') set_param(`sfun_directlook_ex/S-Function1','SFunctionModules','lookup_index') This informs the Simulink Coder build process to use the module lookup_index.c when creating the executable. When generating code for this model, the Simulink Coder software uses the S-function’s mdlRTW method to generate a model.rtw file with the value EvenlySpaced for the XSpacing parameter for the top S-Function block, and the value UnEvenlySpaced for the XSpacing parameter for the bottom S-Function block. The TLC-file uses the value of XSpacing to determine what algorithm to include in the generated code. The generated code contains the lookup algorithm when the XData is evenly spaced, but calls the GetDirectLookupIndex routine when the XData is unevenly spaced. The generated model.c or model.cpp code for the lookup table example model is similar to the following: /* * sfun_directlook_ex.c * * Code generation for Simulink model * "sfun_directlook_ex.slx". * ... */ #include "sfun_directlook_ex.h" #include "sfun_directlook_ex_private.h" /* External output (root outports fed by signals with auto storage) */ ExternalOutputs_sfun_directlook_ex sfun_directlook_ex_Y; /* Real-time model */ rtModel_sfun_directlook_ex sfun_directlook_ex_M_; rtModel_sfun_directlook_ex *sfun_directlook_ex_M = &sfun_directlook_ex_M_; 14-72 Insert S-Function Code /* Model output function */ static void sfun_directlook_ex_output(int_T tid) { /* local block i/o variables */ real_T rtb_SFunction_h; real_T rtb_temp1; /* Sin: ' /Sine Wave' */ rtb_temp1 = sfun_directlook_ex_P.SineWave_Amp * sin(sfun_directlook_ex_P.SineWave_Freq * sfun_directlook_ex_M->Timing.t[0] + sfun_directlook_ex_P.SineWave_Phase) + sfun_directlook_ex_P.SineWave_Bias; /* Code that is inlined for the top S-function block in the * sfun_directlook_ex model */ /* S-Function Block: /S-Function */ { const real_T *xData = &sfun_directlook_ex_P.SFunction_XData[0]; const real_T *yData = &sfun_directlook_ex_P.SFunction_YData[0]; real_T spacing = xData[1] - xData[0]; if ( rtb_temp1 <= xData[0] ) { rtb_SFunction_h = yData[0]; } else if ( rtb_temp1 >= yData[20] ) { rtb_SFunction_h = yData[20]; } else { int_T idx = (int_T)( ( rtb_temp1 - xData[0] ) / spacing ); rtb_SFunction_h = yData[idx]; } } /* Outport: ' /Out1' */ sfun_directlook_ex_Y.Out1 = rtb_SFunction_h; /* Code that is inlined for the bottom S-function block in the * sfun_directlook_ex model */ /* S-Function Block: /S-Function1 */ 14-73 14 External Code Integration { const real_T *xData = &sfun_directlook_ex_P.SFunction1_XData[0]; const real_T *yData = &sfun_directlook_ex_P.SFunction1_YData[0]; int_T idx; idx = GetDirectLookupIndex(xData, 5, rtb_temp1); rtb_temp1 = yData[idx]; } /* Outport: ' /Out2' */ sfun_directlook_ex_Y.Out2 = rtb_temp1; } /* Model update function */ static void sfun_directlook_ex_update(int_T tid) { /* Update absolute time for base rate */ if(!(++sfun_directlook_ex_M->Timing.clockTick0)) ++sfun_directlook_ex_M->Timing.clockTickH0; sfun_directlook_ex_M->Timing.t[0] = sfun_directlook_ex_M->Timing.clockTick0 * sfun_directlook_ex_M->Timing.stepSize0 + sfun_directlook_ex_M->Timing.clockTickH0 * sfun_directlook_ex_M->Timing.stepSize0 * 0x10000; { /* Update absolute timer for sample time: [0.1s, 0.0s] */ if(!(++sfun_directlook_ex_M->Timing.clockTick1)) ++sfun_directlook_ex_M->Timing.clockTickH1; sfun_directlook_ex_M->Timing.t[1] = sfun_directlook_ex_M->Timing.clockTick1 * sfun_directlook_ex_M->Timing.stepSize1 + sfun_directlook_ex_M->Timing.clockTickH1 * sfun_directlook_ex_M->Timing.stepSize1 * 0x10000; } } ... 14-74 Insert S-Function Code matlabroot/toolbox/simulink/simdemos/simfeatures/src/sfun_directlook.c. /* * File : sfun_directlook.c * Abstract: * * Direct 1-D lookup. Here we are trying to compute an approximate * solution, p(x) to an unknown function f(x) at x=x0, given data point * pairs (x,y) in the form of a x data vector and a y data vector. For a * given data pair (say the i'th pair), we have y_i = f(x_i). It is * assumed that the x data values are monotonically increasing. * x0 is outside of the range of the x data vector, then the first or * last point will be returned. If the * * This function returns the "nearest" y0 point for a given x0. No * interpolation is performed. * * The S-function parameters are: * XData - double vector * YData - double vector * XDataEvenlySpacing - double scalar 0 (false) or 1 (true) * The third parameter cannot be changed during simulation. * * * To build: mex sfun_directlook.c lookup_index.c * * Copyright 1990-2004 The MathWorks, Inc. * $Revision: 1.1.8.11.2.4 $ */ #define S_FUNCTION_NAME sfun_directlook #define S_FUNCTION_LEVEL 2 #include #include "simstruc.h" #include /* use utility function IsRealVect() */ #if defined(MATLAB_MEX_FILE) 14-75 14 External Code Integration #include "sfun_slutils.h" #endif /*================* * Build checking * *================*/ #if !defined(MATLAB_MEX_FILE) /* * This file cannot be used directly with Simulink Coder. However, * this S-function does work with Simulink Coder via * the Target Language Compiler technology. See matlabroot/ * toolbox/simulink/simdemos/simfeatures/tlc_c/sfun_directlook.tlc * for the C version */ # error This_file_can_be_used_only_during_simulation_inside_Simulink #endif /*=========* * Defines * *=========*/ #define XVECT_PIDX 0 #define YVECT_PIDX 1 #define XDATAEVENLYSPACED_PIDX 2 #define NUM_PARAMS 3 #define XVECT(S) ssGetSFcnParam(S,XVECT_PIDX) #define YVECT(S) ssGetSFcnParam(S,YVECT_PIDX) #define XDATAEVENLYSPACED(S) ssGetSFcnParam(S,XDATAEVENLYSPACED_PIDX) /*==============* * misc defines * *==============*/ #if !defined(TRUE) #define TRUE 1 #endif #if !defined(FALSE) #define FALSE 0 14-76 Insert S-Function Code #endif /*===========* * typedef's * *===========*/ typedef struct SFcnCache_tag { boolean_T evenlySpaced; } SFcnCache; /*===================================================================* * Prototype define for the function in separate file lookup_index.c * *===================================================================*/ extern int_T GetDirectLookupIndex(const real_T *x, int_T xlen, real_T u); /*====================* * S-function methods * *====================*/ #define MDL_CHECK_PARAMETERS /* Change to #undef to remove function */ #if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE) /* Function: mdlCheckParameters ================================================ * Abstract: * This routine will be called after mdlInitializeSizes, whenever * parameters change or get re-evaluated. The purpose of this routine is * to verify the new parameter settings. * * You should add a call to this routine from mdlInitalizeSizes * to check the parameters. After setting your sizes elements, you should: * if (ssGetSFcnParamsCount(S) == ssGetNumSFcnParams(S)) { * * mdlCheckParameters(S); } */ static void mdlCheckParameters(SimStruct *S) { if (!IsRealVect(XVECT(S))) { ssSetErrorStatus(S,"1st, X-vector parameter must be a real finite " 14-77 14 External Code Integration " vector"); return; } if (!IsRealVect(YVECT(S))) { ssSetErrorStatus(S,"2nd, Y-vector parameter must be a real finite " "vector"); return; } /* * Verify that the dimensions of X and Y are the same. */ if (mxGetNumberOfElements(XVECT(S)) != mxGetNumberOfElements(YVECT(S)) || mxGetNumberOfElements(XVECT(S)) == 1) { ssSetErrorStatus(S,"X and Y-vectors must be of the same dimension " "and have at least two elements"); return; } /* * Verify we have a valid XDataEvenlySpaced parameter. */ if ((!mxIsNumeric(XDATAEVENLYSPACED(S)) && !mxIsLogical(XDATAEVENLYSPACED(S))) || mxIsComplex(XDATAEVENLYSPACED(S)) || mxGetNumberOfElements(XDATAEVENLYSPACED(S)) != 1) { ssSetErrorStatus(S,"3rd, X-evenly-spaced parameter must be logical scalar"); return; } /* * Verify x-data is correctly spaced. */ { int_T i; boolean_T spacingEqual; 14-78 real_T *xData = mxGetPr(XVECT(S)); int_T numEl = mxGetNumberOfElements(XVECT(S)); Insert S-Function Code /* * spacingEqual is TRUE if user XDataEvenlySpaced */ spacingEqual = (mxGetScalar(XDATAEVENLYSPACED(S)) != 0.0); if (spacingEqual) { /* XData is 'evenly-spaced' */ boolean_T badSpacing = FALSE; real_T spacing real_T space; = xData[1] - xData[0]; if (spacing <= 0.0) { badSpacing = TRUE; } else { real_T eps = DBL_EPSILON; for (i = 2; i < numEl; i++) { space = xData[i] - xData[i-1]; if (space <= 0.0 || fabs(space-spacing) >= 128.0*eps*spacing ){ badSpacing = TRUE; break; } } } if (badSpacing) { ssSetErrorStatus(S,"X-vector must be an evenly spaced " "strictly monotonically increasing vector"); return; } } else { /* XData is 'unevenly-spaced' */ for (i = 1; i < numEl; i++) { if (xData[i] <= xData[i-1]) { ssSetErrorStatus(S,"X-vector must be a strictly " "monotonically increasing vector"); return; } } } 14-79 14 External Code Integration } } #endif /* MDL_CHECK_PARAMETERS */ /* Function: mdlInitializeSizes ================================================ * Abstract: * The sizes information is used by Simulink to determine the S-function * block's characteristics (number of inputs, outputs, states, and so on). */ static void mdlInitializeSizes(SimStruct *S) { ssSetNumSFcnParams(S, NUM_PARAMS); /* Number of expected parameters */ /* * Check parameters passed in, providing the correct number was specified * in the S-function dialog box. If an incorrect number of parameters * was specified, Simulink will detect the error since ssGetNumSFcnParams * and ssGetSFcnParamsCount will differ. * ssGetNumSFcnParams - This sets the number of parameters your * S-function expects. * ssGetSFcnParamsCount - This is the number of parameters entered by * the user in the Simulink S-function dialog box. */ #if defined(MATLAB_MEX_FILE) if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) { mdlCheckParameters(S); if (ssGetErrorStatus(S) != NULL) { return; } } else { return; /* Parameter mismatch will be reported by Simulink */ } #endif { int iParam = 0; int nParam = ssGetNumSFcnParams(S); 14-80 Insert S-Function Code for ( iParam = 0; iParam < nParam; iParam++ ) { switch ( iParam ) { case XDATAEVENLYSPACED_PIDX: ssSetSFcnParamTunable( S, iParam, SS_PRM_NOT_TUNABLE ); break; default: ssSetSFcnParamTunable( S, iParam, SS_PRM_TUNABLE ); break; } } } ssSetNumContStates(S, 0); ssSetNumDiscStates(S, 0); if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED); ssSetInputPortDirectFeedThrough(S, 0, 1); ssSetInputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL); ssSetInputPortOverWritable(S, 0, TRUE); if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED); ssSetOutputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL); ssSetNumSampleTimes(S, 1); ssSetOptions(S, SS_OPTION_WORKS_WITH_CODE_REUSE | SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_USE_TLC_WITH_ACCELERATOR); } /* mdlInitializeSizes */ 14-81 14 External Code Integration /* Function: mdlInitializeSampleTimes ========================================== * Abstract: * The lookup inherits its sample time from the driving block. */ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); ssSetModelReferenceSampleTimeDefaultInheritance(S); } /* end mdlInitializeSampleTimes */ /* Function: mdlSetWorkWidths =============================================== * Abstract: * Set up the [X,Y] data as run-time parameters * that is, these values can be changed during execution. */ #define MDL_SET_WORK_WIDTHS static void mdlSetWorkWidths(SimStruct *S) { const char_T *rtParamNames[] = {"XData","YData"}; ssRegAllTunableParamsAsRunTimeParams(S, rtParamNames); } #define MDL_START /* Change to #undef to remove function */ #if defined(MDL_START) /* Function: mdlStart ========================================================== * Abstract: * Here we cache the state (true/false) of the XDATAEVENLYSPACED parameter. * We do this primarily to illustrate how to "cache" parameter values (or * information which is computed from parameter values) which do not change * for the duration of the simulation (or in the generated code). In this * case, rather than repeated calls to mxGetPr, we save the state once. * This results in a slight increase in performance. */ static void mdlStart(SimStruct *S) { SFcnCache *cache = malloc(sizeof(SFcnCache)); 14-82 Insert S-Function Code if (cache == NULL) { ssSetErrorStatus(S,"memory allocation error"); return; } ssSetUserData(S, cache); if (mxGetScalar(XDATAEVENLYSPACED(S)) != 0.0){ cache->evenlySpaced = TRUE; }else{ cache->evenlySpaced = FALSE; } } #endif /* MDL_START */ /* Function: mdlOutputs ======================================================== * Abstract: * In this function, you compute the outputs of your S-function * block. Generally outputs are placed in the output vector, ssGetY(S). */ static void mdlOutputs(SimStruct *S, int_T tid) { SFcnCache *cache = ssGetUserData(S); real_T *xData = mxGetPr(XVECT(S)); real_T *yData = mxGetPr(YVECT(S)); InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); real_T *y = ssGetOutputPortRealSignal(S,0); int_T ny = ssGetOutputPortWidth(S,0); int_T xLen = mxGetNumberOfElements(XVECT(S)); int_T i; /* * When the XData is evenly spaced, we use the direct lookup algorithm * to calculate the lookup */ if (cache->evenlySpaced) { real_T spacing = xData[1] - xData[0]; 14-83 14 External Code Integration for (i = 0; i < ny; i++) { real_T u = *uPtrs[i]; if (u <= xData[0]) { y[i] = yData[0]; } else if (u >= xData[xLen-1]) { y[i] = yData[xLen-1]; } else { int_T idx = (int_T)((u - xData[0])/spacing); y[i] = yData[idx]; } } } else { /* * When the XData is unevenly spaced, we use a bisection search to * locate the lookup index. */ for (i = 0; i < ny; i++) { int_T idx = GetDirectLookupIndex(xData,xLen,*uPtrs[i]); y[i] = yData[idx]; } } } /* end mdlOutputs */ /* Function: mdlTerminate ====================================================== * Abstract: * Free the cache which was allocated in mdlStart. */ static void mdlTerminate(SimStruct *S) { SFcnCache *cache = ssGetUserData(S); if (cache != NULL) { free(cache); } } /* end mdlTerminate */ 14-84 Insert S-Function Code #define MDL_RTW /* Change to #undef to remove function */ #if defined(MDL_RTW) && (defined(MATLAB_MEX_FILE) || defined(NRT)) /* Function: mdlRTW ============================================================ * Abstract: * This function is called when Simulink Coder is generating the * model.rtw file. In this routine, you can call the following functions * which add fields to the model.rtw file. * * Important! Since this S-function has this mdlRTW method, it is required * to have a corresponding .tlc file so as to work with Simulink Coder. See the * sfun_directlook.tlc in matlabroot/toolbox/simulink/simdemos/simfeatures/tlc_c/. */ static void mdlRTW(SimStruct *S) { /* * Write out the spacing setting as a param setting, that is, this cannot be * changed during execution. */ { boolean_T even = (mxGetScalar(XDATAEVENLYSPACED(S)) != 0.0); if (!ssWriteRTWParamSettings(S, 1, SSWRITE_VALUE_QSTR, "XSpacing", even ? "EvenlySpaced" : "UnEvenlySpaced")){ return;/* An error occurred which will be reported by Simulink */ } } } #endif /* MDL_RTW */ /*=============================* * Required S-function trailer * *=============================*/ #ifdef MATLAB_MEX_FILE #include "simulink.c" /* Is this file being compiled as a MEX-file? */ /* MEX-file interface mechanism */ #else 14-85 14 External Code Integration #include "cg_sfun.h" /* Code generation registration function */ #endif /* [EOF] sfun_directlook.c */ matlabroot/toolbox/simulink/simdemos/simfeatures/src/lookup_index.c. /* File : lookup_index.c * Abstract: * * Contains a routine used by the S-function sfun_directlookup.c to * compute the index in a vector for a given data value. * * Copyright 1990-2004 The MathWorks, Inc. * $Revision: 1.1.8.11.2.4 $ */ #include "tmwtypes.h" /* * Function: GetDirectLookupIndex ============================================== * Abstract: * Using a bisection search to locate the lookup index when the x-vector * isn't evenly spaced. * * Inputs: * *x * xlen : Number of values in xtable : Pointer to table, x[0] ....x[xlen-1] * u : input value to look up * * * Output: idx * : the index into the table such that: if u is negative * x[idx] <= u < x[idx+1] * else * x[idx] < u <= x[idx+1] */ int_T GetDirectLookupIndex(const real_T *x, int_T xlen, real_T u) { int_T idx 14-86 = 0; Insert S-Function Code int_T bottom = 0; int_T top = xlen-1; /* * Deal with the extreme cases first: * * i] u <= x[bottom] then idx = bottom * ii] u >= x[top] then idx = top-1 * */ if (u <= x[bottom]) { return(bottom); } else if (u >= x[top]) { return(top); } /* * We have: x[bottom] < u < x[top], onward * with search for the index ... */ for (;;) { idx = (bottom + top)/2; if (u < x[idx]) { top = idx; } else if (u > x[idx+1]) { bottom = idx + 1; } else { /* * We have: x[idx] <= u <= x[idx+1], only need * to do two more checks and we have the answer */ if (u < 0) { /* * We want right continuity, that is, * if u == x[idx+1] * then x[idx+1] <= u < x[idx+2] * else x[idx ] <= u < x[idx+1] */ return( (u == x[idx+1]) ? (idx+1) : idx); } else { 14-87 14 External Code Integration /* * We want left continuity, that is, * if u == x[idx] * then x[idx-1] < u <= x[idx * else x[idx ] ] < u <= x[idx+1] */ return( (u == x[idx]) ? (idx-1) : idx); } } } } /* end GetDirectLookupIndex */ /* [EOF] lookup_index.c */ matlabroot/toolbox/simulink/simdemos/simfeatures/tlc_c/sfun_directlook.tlc. %% File : sfun_directlook.tlc %% Abstract: %% Level-2 S-function sfun_directlook block target file. %% It is using direct lookup algorithm without interpolation %% %% Copyright 1990-2004 The MathWorks, Inc. %% $Revision: 1.1.8.11.2.4 $ %implements "sfun_directlook" "C" %% Function: BlockTypeSetup ==================================================== %% Abstract: %% Place include and function prototype in the model's header file. %% %function BlockTypeSetup(block, system) void %% To add this external function's prototype in the header of the generated %% file. %% %openfile buffer extern int_T GetDirectLookupIndex(const real_T *x, int_T xlen, real_T u); %closefile buffer 14-88 Insert S-Function Code % %endfunction %% Function: mdlOutputs ======================================================== %% Abstract: %% Direct 1-D lookup table S-function example. %% Here we are trying to compute an approximate solution, p(x) to an %% unknown function f(x) at x=x0, given data point pairs (x,y) in the %% form of a x data vector and a y data vector. For a given data pair %% (say the i'th pair), we have y_i = f(x_i). It is assumed that the x %% data values are monotonically increasing. %% outside of the range of the x data vector, then the first or last %% point will be returned. If the first or last x is %% %% This function returns the "nearest" y0 point for a given x0. %% No interpolation is performed. %% %% The S-function parameters are: %% XData %% YData %% XEvenlySpaced: 0 or 1 %% The third parameter cannot be changed during execution and is %% written to the model.rtw file in XSpacing filed of the SFcnParamSettings %% record as "EvenlySpaced" or "UnEvenlySpaced". The first two parameters %% can change during execution and show up in the parameter vector. %% %function Outputs(block, system) Output /* % Block: % */ { %assign rollVars = ["U", "Y"] %% %% Load XData and YData as local variables %% const real_T *xData = % ; const real_T *yData = % ; %assign xDataLen = SIZE(XData.Value, 1) %% %% When the XData is evenly spaced, we use the direct lookup algorithm %% to locate the lookup index. 14-89 14 External Code Integration %% %if SFcnParamSettings.XSpacing == "EvenlySpaced" real_T spacing = xData[1] - xData[0]; %roll idx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars %assign u = LibBlockInputSignal(0, "", lcv, idx) %assign y = LibBlockOutputSignal(0, "", lcv, idx) if ( % <= xData[0] ) { % = yData[0]; } else if ( % >= yData[% ] ) { % = yData[% ]; } else { int_T idx = (int_T)( ( % - xData[0] ) / spacing ); % = yData[idx]; } %% %% Generate an empty line if we are not rolling, %% so that it looks nice in the generated code. %% %if lcv == "" %endif %endroll %else %% When the XData is unevenly spaced, we use a bisection search to %% locate the lookup index. int_T idx; %assign xDataAddr = LibBlockParameterAddr(XData, "", "", 0) %roll idx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars %assign u = LibBlockInputSignal(0, "", lcv, idx) idx = GetDirectLookupIndex(xData, % , %); %assign y = LibBlockOutputSignal(0, "", lcv, idx) % = yData[idx]; %% %% Generate an empty line if we are not rolling, %% so that it looks nice in the generated code. %% %if lcv == "" 14-90 Insert S-Function Code %endif %endroll %endif } %endfunction %% EOF: sfun_directlook.tlc Guidelines for Writing Inlined S-Functions • Consider using the block property RTWdata (see “S-Function RTWdata” on page 14-67). This property is a structure of strings that you can associate with a block. The code generator saves the structure with the model in the model.rtw file and makes the .rtw file more readable. For example, suppose you enter the following commands in the MATLAB Command Window: mydata.field1 = 'information for field1'; mydata.field2 = 'information for field2'; set_param(sfun_block, 'RTWdata', mydata); The .rtw file that Simulink Coder generates for the block, will include the comments specified in the structure mydata. • Consider using the mdlRTW function to inline your C MEX S-function in the generated code. This is useful when you want to - Rename tunable parameters in the generated code Introduce nontunable parameters into a TLC file Write S-Functions That Support Expression Folding • “About S-Functions that Support Expression Folding” on page 14-92 • “Categories of Output Expressions” on page 14-93 • “Acceptance or Denial of Requests for Input Expressions” on page 14-98 • “Expression Folding in a TLC Block Implementation” on page 14-100 14-91 14 External Code Integration About S-Functions that Support Expression Folding This section describes how you can take advantage of expression folding to increase the efficiency of code generated by your own inlined S-Function blocks, by calling macros provided in the S-Function API. This section assumes that you are familiar with: • Writing inlined S-functions (see “S-Function Basics”). • “Target Language Compiler” The S-Function API lets you specify whether a given S-Function block should nominally accept expressions at a given input port. A block should not always accept expressions. For example, if the address of the signal at the input is used, expressions should not be accepted at that input, because it is not possible to take the address of an expression. The S-Function API also lets you specify whether an expression can represent the computations associated with a given output port. When you request an expression at a block’s input or output port, the Simulink engine determines whether or not it can honor that request, given the block’s context. For example, the engine might deny a block’s request to output an expression if the destination block does not accept expressions at its input, if the destination block has an update function, or if multiple output destinations exist. The decision to honor or deny a request to output an expression can also depend on the category of output expression the block uses (see “Categories of Output Expressions” on page 14-93). The sections that follow explain • When and how you can request that a block accept expressions at an input port • When and how you can request that a block generate expressions at an outport • The conditions under which the Simulink engine will honor or deny such requests To take advantage of expression folding in your S-functions, you should understand when to request acceptance and generation of expressions for 14-92 Insert S-Function Code specific blocks. You do not have to understand the algorithm by which the Simulink engine chooses to accept or deny these requests. However, if you want to trace between the model and the generated code, it is helpful to understand some of the more common situations that lead to denial of a request. Categories of Output Expressions When you implement a C MEX S-function, you can specify whether the code corresponding to a block’s output is to be generated as an expression. If the block generates an expression, you must specify that the expression is constant, trivial, or generic. A constant output expression is a direct access to one of the block’s parameters. For example, the output of a Constant block is defined as a constant expression because the output expression is simply a direct access to the block’s Value parameter. A trivial output expression is an expression that can be repeated, without any performance penalty, when the output port has multiple output destinations. For example, the output of a Unit Delay block is defined as a trivial expression because the output expression is simply a direct access to the block’s state. Because the output expression involves no computations, it can be repeated more than once without degrading the performance of the generated code. A generic output expression is an expression that should be assumed to have a performance penalty if repeated. As such, a generic output expression is not suitable for repeating when the output port has multiple output destinations. For instance, the output of a Sum block is a generic rather than a trivial expression because it is costly to recompute a Sum block output expression as an input to multiple blocks. Examples of Trivial and Generic Output Expressions. Consider the following block diagram. The Delay block has multiple destinations, yet its output is designated as a trivial output expression, so that it can be used more than once without degrading the efficiency of the code. 14-93 14 External Code Integration The following code excerpt shows code generated from the Unit Delay block in this block diagram. The three root outputs are directly assigned from the state of the Unit Delay block, which is stored in a field of the global data structure rtDWork. Since the assignment is direct, involving no expressions, there is no performance penalty associated with using the trivial expression for multiple destinations. void MdlOutputs(int_T tid) { ... /* Outport: /Out1 incorporates: * UnitDelay: /Unit Delay */ rtY.Out1 = rtDWork.Unit_Delay_DSTATE; /* Outport: /Out2 incorporates: * UnitDelay: /Unit Delay */ rtY.Out2 = rtDWork.Unit_Delay_DSTATE; /* Outport: /Out3 incorporates: * UnitDelay: /Unit Delay */ rtY.Out3 = rtDWork.Unit_Delay_DSTATE; ... } On the other hand, consider the Sum blocks in the following model: 14-94 Insert S-Function Code The upper Sum block in the preceding model generates the signal labeled non_triv. Computation of this output signal involves two multiplications and an addition. If the Sum block’s output were permitted to generate an expression even when the block had multiple destinations, the block’s operations would be duplicated in the generated code. In the case illustrated, the generated expressions would proliferate to four multiplications and two additions. This would degrade the efficiency of the program. Accordingly the output of the Sum block is not allowed to be an expression because it has multiple destinations The code generated for the previous block diagram shows how code is generated for Sum blocks with single and multiple destinations. The Simulink engine does not permit the output of the upper Sum block to be an expression because the signal non_triv is routed to two output destinations. Instead, the result of the multiplication and addition operations is stored in a temporary variable (rtb_non_triv) that is referenced twice in the statements that follow, as seen in the code excerpt below. In contrast, the lower Sum block, which has only a single output destination (Out2), does generate an expression. void MdlOutputs(int_T tid) { /* local block i/o variables */ real_T rtb_non_triv; real_T rtb_Sine_Wave; 14-95 14 External Code Integration /* Sum: /Sum incorporates: * Gain: /Gain * Inport: /u1 * Gain: /Gain1 * Inport: /u2 * * Regarding /Gain: * Gain value: rtP.Gain_Gain * * Regarding /Gain1: * Gain value: rtP.Gain1_Gain */ rtb_non_triv = (rtP.Gain_Gain * rtU.u1) + (rtP.Gain1_Gain * rtU.u2); /* Outport: /Out1 */ rtY.Out1 = rtb_non_triv; /* Sin Block: /Sine Wave */ rtb_Sine_Wave = rtP.Sine_Wave_Amp * sin(rtP.Sine_Wave_Freq * rtmGetT(rtM_model) + rtP.Sine_Wave_Phase) + rtP.Sine_Wave_Bias; /* Outport: /Out2 incorporates: * Sum: /Sum1 */ rtY.Out2 = (rtb_non_triv + rtb_Sine_Wave); } Specify the Category of an Output Expression. The S-Function API provides macros that let you declare whether an output of a block should be an expression, and if so, to specify the category of the expression. The following table specifies when to declare a block output to be a constant, trivial, or generic output expression. 14-96 Insert S-Function Code Types of Output Expressions Category of Expression When to Use Constant Use only if block output is a direct memory access to a block parameter. Trivial Use only if block output is an expression that can appear multiple times in the code without reducing efficiency (for example, a direct memory access to a field of the DWork vector, or a literal). Generic Use if output is an expression, but not constant or trivial. You must declare outputs as expressions in the mdlSetWorkWidths function using macros defined in the S-Function API. The macros have the following arguments: • SimStruct *S: pointer to the block’s SimStruct. • int idx: zero-based index of the output port. • bool value: pass in TRUE if the port generates output expressions. The following macros are available for setting an output to be a constant, trivial, or generic expression: • void ssSetOutputPortConstOutputExprInRTW(SimStruct *S, int idx, bool value) • void ssSetOutputPortTrivialOutputExprInRTW(SimStruct *S, int idx, bool value) • void ssSetOutputPortOutputExprInRTW(SimStruct *S, int idx, bool value) The following macros are available for querying the status set by any prior calls to the macros above: 14-97 14 External Code Integration • bool ssGetOutputPortConstOutputExprInRTW(SimStruct *S, int idx) • bool ssGetOutputPortTrivialOutputExprInRTW(SimStruct *S, int idx) • bool ssGetOutputPortOutputExprInRTW(SimStruct *S, int idx) The set of generic expressions is a superset of the set of trivial expressions, and the set of trivial expressions is a superset of the set of constant expressions. Therefore, when you query an output that has been set to be a constant expression with ssGetOutputPortTrivialOutputExprInRTW, it returns True. A constant expression is considered a trivial expression, because it is a direct memory access that can be repeated without degrading the efficiency of the generated code. Similarly, an output that has been configured to be a constant or trivial expression returns True when queried for its status as a generic expression. Acceptance or Denial of Requests for Input Expressions A block can request that its output be represented in code as an expression. Such a request can be denied if the destination block cannot accept expressions at its input port. Furthermore, conditions independent of the requesting block and its destination blocks can prevent acceptance of expressions. This section discusses block-specific conditions under which requests for input expressions are denied. For information on other conditions that prevent acceptance of expressions, see “Denial of Block Requests to Output Expressions” on page 14-99. A block should not be configured to accept expressions at its input port under the following conditions: • The block must take the address of its input data. It is not possible to take the address of most types of input expressions. • The code generated for the block references the input more than once (for example, the Abs or Max blocks). This would lead to duplication of a potentially complex expression and a subsequent degradation of code efficiency. 14-98 Insert S-Function Code If a block refuses to accept expressions at an input port, then any block that is connected to that input port is not permitted to output a generic or trivial expression. A request to output a constant expression is never denied, because there is no performance penalty for a constant expression, and it is always possible to take the parameter’s address. S-Function API to Specify Input Expression Acceptance. The S-Function API provides macros that let you: • Specify whether a block input should accept nonconstant expressions (that is, trivial or generic expressions) • Query whether a block input accepts nonconstant expressions By default, block inputs do not accept nonconstant expressions. You should call the macros in your mdlSetWorkWidths function. The macros have the following arguments: • SimStruct *S: pointer to the block’s SimStruct. • int idx: zero-based index of the input port. • bool value: pass in TRUE if the port accepts input expressions; otherwise pass in FALSE. The macro available for specifying whether or not a block input should accept a nonconstant expression is as follows: void ssSetInputPortAcceptExprInRTW(SimStruct *S, int portIdx, bool value) The corresponding macro available for querying the status set by any prior calls to ssSetInputPortAcceptExprInRTW is as follows: bool ssGetInputPortAcceptExprInRTW(SimStruct *S, int portIdx) Denial of Block Requests to Output Expressions. Even after a specific block requests that it be allowed to generate an output expression, that request can be denied for generic reasons. These reasons include, but are not limited to 14-99 14 External Code Integration • The output expression is nontrivial, and the output has multiple destinations. • The output expression is nonconstant, and the output is connected to at least one destination that does not accept expressions at its input port. • The output is a test point. • The output has been assigned an external storage class. • The output must be stored using global data (for example is an input to a merge block or a block with states). • The output signal is complex. You do not need to consider these generic factors when deciding whether or not to utilize expression folding for a particular block. However, these rules can be helpful when you are examining generated code and analyzing cases where the expression folding optimization is suppressed. Expression Folding in a TLC Block Implementation To take advantage of expression folding, you must modify the TLC block implementation of an inlined S-Function such that it informs the Simulink engine whether it generates or accepts expressions at its • Input ports, as explained in “S-Function API to Specify Input Expression Acceptance” on page 14-99. • Output ports, as explained in “Categories of Output Expressions” on page 14-93. This section discusses required modifications to the TLC implementation. Expression Folding Compliance. In the BlockInstanceSetup function of your S-function, register your block to be compliant with expression folding. Otherwise, any expression folding requested or allowed at the block’s outputs or inputs will be disabled, and temporary variables will be used. To register expression folding compliance, call the TLC library function LibBlockSetIsExpressionCompliant(block), which is defined in matlabroot/rtw/c/tlc/lib/utillib.tlc. For example: 14-100 Insert S-Function Code %% Function: BlockInstanceSetup =========================================== %% %function BlockInstanceSetup(block, system) void %% % %% %endfunction You can conditionally disable expression folding at the inputs and outputs of a block by making the call to this function conditionally. If you have overridden one of the TLC block implementations provided by the Simulink Coder product with your own implementation, you should not make the preceding call until you have updated your implementation, as described by the guidelines for expression folding in the following sections. Output Expressions. The BlockOutputSignal function is used to generate code for a scalar output expression or one element of a nonscalar output expression. If your block outputs an expression, you should add a BlockOutputSignal function. The prototype of the BlockOutputSignal is %function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void The arguments to BlockOutputSignal are as follows: • block: the record for the block for which an output expression is being generated • system: the record for the system containing the block • portIdx: zero-based index of the output port for which an expression is being generated • ucv: user control variable defining the output element for which code is being generated • lcv: loop control variable defining the output element for which code is being generated • idx: signal index defining the output element for which code is being generated • retType: string defining the type of signal access desired: 14-101 14 External Code Integration "Signal" specifies the contents or address of the output signal. "SignalAddr" specifies the address of the output signal The BlockOutputSignal function returns a text string for the output signal or address. The string should enforce the precedence of the expression by using opening and terminating parentheses, unless the expression consists of a function call. The address of an expression can only be returned for a constant expression; it is the address of the parameter whose memory is being accessed. The code implementing the BlockOutputSignal function for the Constant block is shown below. %% Function: BlockOutputSignal ================================================= %% Abstract: %% Return the reference to the parameter. %% be used by Simulink when optimizing the Block IO data structure. This function *may* %% %function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void %switch retType %case "Signal" %return LibBlockParameter(Value,ucv,lcv,idx) %case "SignalAddr" %return LibBlockParameterAddr(Value,ucv,lcv,idx) %default %assign errTxt = "Unsupported return type: % " % %endswitch %endfunction The code implementing the BlockOutputSignal function for the Relational Operator block is shown below. %% Function: BlockOutputSignal ================================================= %% Abstract: %% Return an output expression. %% be used by Simulink when optimizing the Block IO data structure. This function *may* %% %function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void %switch retType %case "Signal" %assign logicOperator = ParamSettings.Operator 14-102 Insert S-Function Code %if ISEQUAL(logicOperator, "~=") %assign op = "!=" elseif ISEQUAL(logicOperator, "==") %assign op = "==" %else %assign op = logicOperator %endif %assign u0 = LibBlockInputSignal(0, ucv, lcv, idx) %assign u1 = LibBlockInputSignal(1, ucv, lcv, idx) %return "(% % % )" %default %assign errTxt = "Unsupported return type: % " % %endswitch %endfunction Expression Folding for Blocks with Multiple Outputs. When a block has a single output, the Outputs function in the block’s TLC file is called only if the output port is not an expression. Otherwise, the BlockOutputSignal function is called. If a block has multiple outputs, the Outputs function is called if any output port is not an expression. The Outputs function should guard against generating code for output ports that are expressions. This is achieved by guarding sections of code corresponding to individual output ports with calls to LibBlockOutputSignalIsExpr(). For example, consider an S-Function with two inputs and two outputs, where • The first output, y0, is equal to two times the first input. • The second output, y1, is equal to four times the second input. The Outputs and BlockOutputSignal functions for the S-function are shown in the following code excerpt. %% Function: BlockOutputSignal ================================================= %% Abstract: %% Return an output expression. %% be used by Simulink when optimizing the Block IO data structure. This function *may* %% %function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void 14-103 14 External Code Integration %switch retType %case "Signal" %assign u = LibBlockInputSignal(portIdx, ucv, lcv, idx) %case "Signal" %if portIdx == 0 %return "(2 * %)" %elseif portIdx == 1 %return "(4 * %)" %endif %default %assign errTxt = "Unsupported return type: % " % %endswitch %endfunction %% %% Function: Outputs ================================================= %% Abstract: %% Compute output signals of block %% %function Outputs(block,system) Output %assign rollVars = ["U", "Y"] %roll sigIdx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars %assign u0 = LibBlockInputSignal(0, "", lcv, sigIdx) %assign u1 = LibBlockInputSignal(1, "", lcv, sigIdx) %assign y0 = LibBlockOutputSignal(0, "", lcv, sigIdx) %assign y1 = LibBlockOutputSignal(1, "", lcv, sigIdx) %if !LibBlockOutputSignalIsExpr(0) % = 2 * % ; %endif %if !LibBlockOutputSignalIsExpr(1) % = 4 * % ; %endif %endroll %endfunction Comments for Blocks That Are Expression-Folding-Compliant. In the past, all blocks preceded their outputs code with comments of the form /* % Block: % */ 14-104 Insert S-Function Code When a block is expression-folding-compliant, the initial line shown above is generated automatically. You should not include the comment as part of the block’s TLC implementation. Additional information should be registered using the LibCacheBlockComment function. The LibCacheBlockComment function takes a string as an input, defining the body of the comment, except for the opening header, the final newline of a single or multiline comment, and the closing trailer. The following TLC code illustrates registering a block comment. Note the use of the function LibBlockParameterForComment, which returns a string, suitable for a block comment, specifying the value of the block parameter. %openfile commentBuf $c(*) Gain value: % %closefile commentBuf % S-Functions That Specify Port Scope and Reusability You can use the following SimStruct macros in the mdlInitializeSizes method to specify the scope and reusability of the memory used for your S-function’s input and output ports: • ssSetInputPortOptimOpts: Specify the scope and reusability of the memory allocated to an S-function input port • ssSetOutputPortOptimOpts: Specify the scope and reusability of the memory allocated to an S-function output port • ssSetInputPortOverWritable: Specify whether one of your S-function’s input ports can be overwritten by one of its output ports • ssSetOutputPortOverwritesInputPort: Specify whether an output port can share its memory buffer with an input port You declare an input or output as local or global, and indicate its reusability, by passing one of the following four options to the ssSetInputPortOptimOpts and ssSetOutputPortOptimOpts macros: 14-105 14 External Code Integration • SS_NOT_REUSABLE_AND_GLOBAL: Indicates that the input and output ports are stored in separate memory locations in the global block input and output structure • SS_NOT_REUSABLE_AND_LOCAL: Indicates that the Simulink Coder software can declare individual local variables for the input and output ports • SS_REUSABLE_AND_LOCAL: Indicates that the Simulink Coder software can reuse a single local variable for these input and output ports • SS_REUSABLE_AND_GLOBAL: Indicates that these input and output ports are stored in a single element in the global block input and output structure Note Marking an input or output port as a local variable does not imply that the code generator uses a local variable in the generated code. If your S-function accesses the inputs and outputs only in its mdlOutputs routine, the code generator declares the inputs and outputs as local variables. However, if the inputs and outputs are used elsewhere in the S-function, the code generator includes them in the global block input and output structure. The reusability setting indicates if the memory associated with an input or output port can be overwritten. To reuse input and output port memory: 1 Indicate the ports are reusable using either the SS_REUSABLE_AND_LOCAL or SS_REUSABLE_AND_GLOBAL option in the ssSetInputPortOptimOpts and ssSetOutputPortOptimOpts macros 2 Indicate the input port memory is overwritable using ssSetInputPortOverWritable 3 If your S-function has multiple input and output ports, use ssSetOutputPortOverwritesInputPort to indicate which output and input ports share memory The following example shows how different scope and reusability settings effect the generated code. The following model contains an S-function block pointing to the C MEX S-function matlabroot/toolbox/simulink/simdemos/simfeatures/src/sfun_directlook.c, which models a direct 1-D lookup table. 14-106 Insert S-Function Code The S-function’s mdlInitializeSizes method declares the input port as reusable, local, and overwritable and the output port as reusable and local, as follows: static void mdlInitializeSizes(SimStruct *S) { /* snip */ ssSetInputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL); ssSetInputPortOverWritable(S, 0, TRUE); /* snip */ ssSetOutputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL); /* snip */ } The generated code for this model stores the input and output signals in a single local variable rtb_SFunction, as shown in the following output function: static void sl_directlook_output(int_T tid) { /* local block i/o variables */ real_T rtb_SFunction[2]; /* Sin: ' /Sine Wave' */ rtb_SFunction[0] = sin(((real_T)sl_directlook_DWork.counter[0] + sl_directlook_P.SineWave_Offset) * 2.0 * 3.1415926535897931E+000 / sl_directlook_P.SineWave_NumSamp) * sl_directlook_P.SineWave_Amp[0] + sl_directlook_P.SineWave_Bias; rtb_SFunction[1] = sin(((real_T)sl_directlook_DWork.counter[1] + sl_directlook_P.SineWave_Offset) * 2.0 * 3.1415926535897931E+000 / sl_directlook_P.SineWave_NumSamp) * sl_directlook_P.SineWave_Amp[1] + sl_directlook_P.SineWave_Bias; 14-107 14 External Code Integration /* S-Function Block: /S-Function */ { const real_T *xData = &sl_directlook_P.SFunction_XData[0]; const real_T *yData = &sl_directlook_P.SFunction_YData [0]; real_T spacing = xData[1] - xData[0]; if (rtb_SFunction[0] <= xData[0] ) { rtb_SFunction[0] = yData[0]; } else if (rtb_SFunction[0] >= yData[20] ) { rtb_SFunction[0] = yData[20]; } else { int_T idx = (int_T)( ( rtb_SFunction[0] - xData[0] ) / spacing ); rtb_SFunction[0] = yData[idx]; } if (rtb_SFunction[1] <= xData[0] ) { rtb_SFunction[1] = yData[0]; } else if (rtb_SFunction[1] >= yData[20] ) { rtb_SFunction[1] = yData[20]; } else { int_T idx = (int_T)( ( rtb_SFunction[1] - xData[0] ) / spacing ); rtb_SFunction[1] = yData[idx]; } } /* Outport: ' /Out1' */ sl_directlook_Y.Out1[0] = rtb_SFunction[0]; sl_directlook_Y.Out1[1] = rtb_SFunction[1]; UNUSED_PARAMETER(tid); } The following table shows variations of the code generated for this model when using the generic real-time target (GRT). Each row explains a different setting for the scope and reusability of the S-function’s input and output ports. 14-108 Insert S-Function Code Scope and reusability Inputs: Local, reusable, overwritable Outputs: Local, reusable S-function mdlInitializeSizes code ssSetInputPortOptimOpts(S, 0, Generated code The model.c file declares a local variable in the output function. SS_REUSABLE_AND_LOCAL); /* local block i/o variables */ ssSetInputPortOverWritable(S, 0, real_T rtb_SFunction[2]; TRUE); ssSetOutputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL); Inputs: Global, reusable, overwritable Outputs: Global, reusable ssSetInputPortOptimOpts(S, 0, SS_REUSABLE_AND_GLOBAL); The model.h file defines a block signals structure with a single element to store the S-function’s input and output. ssSetInputPortOverWritable(S, 0, TRUE); /* Block signals (auto storage) */ typedef struct { ssSetOutputPortOptimOpts(S, 0, SS_REUSABLE_AND_GLOBAL); real_T SFunction[2]; } BlockIO_sl_directlook; The model.c file uses this element of the structure in calculations of the S-function’s input and output signals. /* Sin: ' /Sine Wave' */ sl_directlook_B.SFunction[0] = sin ... /* snip */ /*S-Function Block: /S-Function*/ { const real_T *xData = &sl_directlook_P.SFunction_XData[0] 14-109 14 External Code Integration Scope and reusability Inputs: Local, not reusable Outputs: Local, not reusable S-function mdlInitializeSizes code Generated code SS_NOT_REUSABLE_AND_LOCAL); The model.c file declares local variables for the S-function’s input and output in the output function ssSetInputPortOverWritable(S, 0, /* local block i/o variables */ ssSetInputPortOptimOpts(S, 0, FALSE); real_T rtb_SineWave[2]; real_T rtb_SFunction[2]; ssSetOutputPortOptimOpts(S, 0, SS_NOT_REUSABLE_AND_LOCAL); Inputs: Global, not reusable Outputs: Global, not reusable ssSetInputPortOptimOpts(S, 0, SS_NOT_REUSABLE_AND_GLOBAL); The model.h file defines a block signal structure with individual elements to store the S-function’s input and output. ssSetInputPortOverWritable(S, 0, FALSE); /* Block signals (auto storage) */ typedef struct { ssSetOutputPortOptimOpts(S, 0, real_T SineWave[2]; SS_NOT_REUSABLE_AND_GLOBAL); real_T SFunction[2]; } BlockIO_sl_directlook; The model.c file uses the different elements in this structure when calculating the S-function’s input and output. /* Sin: ' /Sine Wave' */ sl_directlook_B.SineWave[0] = sin ... /* snip */ /*S-Function Block: /S-Function*/ { const real_T *xData = &sl_directlook_P.SFunction_XData[0] 14-110 Insert S-Function Code S-Functions That Specify Sample Time Inheritance Rules For the Simulink engine to determine whether a model can inherit a sample time, the S-functions in the model need to specify how they use sample times. You can specify this information by calling the macro ssSetModelReferenceSampleTimeInheritanceRule from mdlInitializeSizes or mdlSetWorkWidths. To use this macro: 1 Check whether the S-function calls any of the following macros: • ssGetSampleTime • ssGetInputPortSampleTime • ssGetOutputPortSampleTime • ssGetInputPortOffsetTime • ssGetOutputPortOffsetTime • ssGetSampleTimePtr • ssGetInputPortSampleTimeIndex • ssGetOutputPortSampleTimeIndex • ssGetSampleTimeTaskID • ssGetSampleTimeTaskIDPtr 2 Check for the following in your S-function TLC code: • LibBlockSampleTime • CompiledModel.SampleTime • LibBlockInputSignalSampleTime • LibBlockInputSignalOffsetTime • LibBlockOutputSignalSampleTime • LibBlockOutputSignalOffsetTime 3 Depending on your search results, use ssSetModelReferenceSampleTimeInheritanceRule as indicated in the following table. 14-111 14 External Code Integration If... Use... None of the macros or functions are present, the S-function does not preclude the model from inheriting a sample time. ssSetModelReferenceSampleTimeInheritanceRule (S, USE_DEFAULT_FOR_DISCRETE_INHERITANCE) Any of the macros or functions are used for ssSetModelReferenceSampleTimeInheritanceRule... (S,USE_DEFAULT_FOR_DISCRETE_INHERITANCE) • Throwing errors if sample time is inherited, continuous, or constant • Checking ssIsSampleHit • Checking whether sample time is inherited in either mdlSetInputPortSampleTime or mdlSetOutputPortSampleTime before setting The S-function uses its sample time for computing parameters, outputs, and so on ssSetModelReferenceSampleTimeInheritanceRule (S, DISALLOW_SAMPLE_TIME_INHERITANCE) Note If an S-function does not set the ssSetModelReferenceSampleTimeInheritanceRule macro, by default the Simulink engine assumes that the S-function does not preclude the model containing that S-function from inheriting a sample time. However, the engine issues a warning indicating that the model includes S-functions for which this macro is not set. You can use settings on the Diagnostics/Solver pane of the Configuration Parameters dialog box or Model Explorer to control how the Simulink engine responds when it encounters S-functions that have unspecified sample time inheritance rules. Toggle the Unspecified inheritability of sample time diagnostic to none, warning, or error. The default is warning. 14-112 Insert S-Function Code S-Functions That Support Code Reuse You can reuse the generated code for identical subsystems that occur in multiple instances within a model and across referenced models. For more information about code generation of subsystems for code reuse, see “Code Generation of Subsystems” on page 2-2. If you want your S-function to support code reuse for a subsystem, the S-function must meet the following requirements: • The S-function must be inlined. • Code generated from the S-function must not use static variables. • The S-function must initialize its pointer work vector in mdlStart and not before. • The S-function must not be a sink that logs data to the workspace. • The S-function must register its parameters as run-time parameters in mdlSetWorkWidths. (It must not use ssWriteRTWParameters in its mdlRTW function for this purpose.) • The S-function must not be a device driver. In addition to meeting the preceding requirements, your S-function must set the SS_OPTION_WORKS_WITH_CODE_REUSE flag (see the description of ssSetOptions in the Simulink Writing S-Function documentation). This flag indicates that your S-function meets the requirements for subsystem code reuse. S-Functions for Multirate Multitasking Environments • “About S-Functions for Multirate Multitasking Environments” on page 14-113 • “Rate Grouping Support in S-Functions” on page 14-114 • “Create Multitasking, Multirate, Port-Based Sample Time S-Functions” on page 14-115 About S-Functions for Multirate Multitasking Environments S-functions can be used in models with multiple sample rates and deployed in multitasking target environments. Likewise, S-functions themselves can have 14-113 14 External Code Integration multiple rates at which they operate. The Embedded Coder product generates code for multirate multitasking models using an approach called rate grouping. In code generated for ERT-based targets, rate grouping generates separate model_step functions for the base rate task and each subrate task in the model. Although rate grouping is a code generation feature found in ERT targets only, your S-functions can use it in other contexts when you code them as explained below. Rate Grouping Support in S-Functions To take advantage of rate grouping, you must inline your multirate S-functions if you have not done so. You need to follow certain Target Language Compiler protocols to exploit rate grouping. Coding TLC to exploit rate grouping does not prevent your inlined S-functions from functioning properly in GRT. Likewise, your inlined S-functions will still generate valid ERT code even if you do not make them rate-grouping-compliant. If you do so, however, they will generate more efficient code for multirate models. For instructions and examples of Target Language Compiler code illustrating how to create and upgrade S-functions to generate rate-grouping-compliant code, see “Rate Grouping Compliance and Compatibility Issues” in the Embedded Coder documentation. For each multirate S-function that is not rate grouping-compliant, the Simulink Coder software issues the following warning when you build: Warning: Simulink Coder: Code of output function for multirate block ' /S-Function' is guarded by sample hit checks rather than being rate grouped. This will generate the same code for all rates used by the block, possibly generating dead code. To avoid dead code, you must update the TLC file for the block. You will also find a comment such as the following in code generated for each noncompliant S-function: /* Because the output function of multirate block /S-Function is not rate grouped, the following code might contain unreachable blocks of code. To avoid this, you must update your block TLC file. */ 14-114 Insert S-Function Code The words “update function” are substituted for “output function” in these warnings. Create Multitasking, Multirate, Port-Based Sample Time S-Functions The following instructions show how to support both data determinism and data integrity in multirate S-functions. They do not cover cases where there is no determinism nor integrity. Support for frame-based processing does not affect the requirements. Note The slow rates must be multiples of the fastest rate. The instructions do not apply when two rates being interfaced are not multiples or when the rates are not periodic. Rules for Properly Handling Fast-to-Slow Transitions. The rules that multirate S-functions should observe for inputs are • The input should only be read at the rate that is associated with the input port sample time. • Generally, the input data is written to DWork, and the DWork can then be accessed at the slower (downstream) rate. The input can be read at every sample hit of the input rate and written into DWork memory, but this DWork memory cannot then be directly accessed by the slower rate. Any DWork memory that will be read by the slow rate must only be written by the fast rate when there is a special sample hit. A special sample hit occurs when both this input port rate and rate to which it is interfacing have a hit. Depending on their requirements and design, algorithms can process the data in several locations. The rules that multirate S-functions should observe for outputs are • The output should not be written by any rate other than the rate assigned to the output port, except in the optimized case described below. • The output should always be written when the sample rate of the output port has a hit. 14-115 14 External Code Integration If these conditions are met, the S-Function block can specify that the input port and output port can both be made local and reusable. You can include an optimization when little or no processing needs to be done on the data. In such cases, the input rate code can directly write to the output (instead of by using DWork) when there is a special sample hit. If you do this, however, you must declare the outport port to be global and not reusable. This optimization results in one less memcpy but does introduce nonuniform processing requirements on the faster rate. Whether you use this optimization or not, the most recent input data, as seen by the slower rate, is always the value when both the faster and slower rate had their hits (and possible earlier input data as well, depending on the algorithm). Any subsequent steps by the faster rate and the associated input data updates are not seen by the slower rate until the next hit for the slow rate occurs. Pseudocode Examples of Fast-to-Slow Rate Transition. The pseudocode below abstracts how you should write your C MEX code to handle fast-to-slow transitions, illustrating with an input rate of 0.1 second driving an output rate of one second. A similar approach can be taken when inlining the code. The block has following characteristics: • File: sfun_multirate_zoh.c, Equation: y = u(tslow) • Input: local and reusable • Output: local and reusable • DirectFeedthrough: yes OutputFcn if (ssIsSampleHit(".1")) { if (ssIsSepcialSampleHit("1")) { DWork = u; } } if (ssIsSampleHit("1")) { y = DWork; } An alternative, slightly optimized approach for simple algorithms: 14-116 Insert S-Function Code • Input: local and reusable • Output: global and not reusable because it needs to persist between special sample hits • DirectFeedthrough: yes OutputFcn if (ssIsSampleHit(".1")) { if (ssIsSpecialSampleHit("1")) { y = u; } } Example adding a simple algorithm: • File: sfun_multirate_avg.c; Equation: y = average(u) • Input: local and reusable • Output: local and reusable • DirectFeedthrough: yes (Assume DWork[0:10] and DWork[mycounter] are initialized to zero) OutputFcn if (ssIsSampleHit(".1")) { /* In general, processing on 'u' could be done here, it runs on every hit of the fast rate. */ DWork[DWork[mycounter]++] = u; if (ssIsSpecialSampleHit("1")) { /* In general, processing on DWork[0:10] can be done here, but it does cause the faster rate to have nonuniform processing requirements (every 10th hit, more code needs to be run).*/ DWork[10] = sum(DWork[0:9])/10; DWork[mycounter] = 0; } } if (ssIsSampleHit("1")) { /* Processing on DWork[10] can be done here before outputing. This code runs on every hit of the 14-117 14 External Code Integration slower task. */ y = DWork[10]; } Rules for Properly Handling Slow-to-Fast Transitions. When output rates are faster than input rates, input should only be read at the rate that is associated with the input port sample time, observing the following rules: • Always read input from the update function. • Use no special sample hit checks when reading input. • Write the input to a DWork. • When there is a special sample hit between the rates, copy the DWork into a second DWork in the output function. • Write the second DWork to the output at every hit of the output sample rate. The block can request that the input port be made local but it cannot be set to reusable. The output port can be set to local and reusable. As in the fast-to-slow transition case, the input should not be read by any rate other than the one assigned to the input port. Similarly, the output should not be written to at any rate other than the rate assigned to the output port. An optimization can be made when the algorithm being implemented is only required to run at the slow rate. In such cases, you use only one DWork. The input still writes to the DWork in the update function. When there is a special sample hit between the rates, the output function copies the same DWork directly to the output. You must set the output port to be global and not reusable in this case. This optimization results in one less memcpy operation per special sample hit. In either case, the data that the fast rate computations operate on is always delayed, that is, the data is from the previous step of the slow rate code. Pseudocode Examples of Slow-to-Fast Rate Transition. The pseudocode below abstracts what your S-function needs to do to handle slow-to-fast transitions, illustrating with an input rate of one second driving an output rate of 0.1 second. The block has following characteristics: 14-118 Insert S-Function Code • File: sfun_multirate_delay.c, Equation: y = u(tslow-1) • Input: Set to local, will be local if output/update are combined (ERT) otherwise will be global. Set to not reusable because input needs to be preserved until the update function runs. • Output: local and reusable • DirectFeedthrough: no OutputFcn if (ssIsSampleHit(".1") { if (ssIsSpecialSampleHit("1") { DWork[1] = DWork[0]; } y = DWork[1]; } UpdateFcn if (ssIsSampleHit("1")) { DWork[0] = u; } An alternative, optimized approach can be used by some algorithms: • Input: Set to local, will be local if output/update are combined (ERT) otherwise will be global. Set to not reusable because input needs to be preserved until the update function runs. • Output: global and not reusable because it needs to persist between special sample hits. • DirectFeedthrough: no OutputFcn if (ssIsSampleHit(".1") { if (ssIsSpecialSampleHit("1") { y = DWork; } } UpdateFcn if (ssIsSampleHit("1")) { DWork = u; } 14-119 14 External Code Integration Example adding a simple algorithm: • File: sfun_multirate_modulate.c, Equation: y = sin(tfast) + u(tslow-1) • Input: Set to local, will be local if output/update are combined (an ERT feature) otherwise will be global. Set to not reusable because input needs to be preserved until the update function runs. • Output: local and reusable • DirectFeedthrough: no OutputFcn if (ssIsSampleHit(".1") { if (ssIsSpecialSampleHit("1") { /* Processing not likely to be done here. It causes * the faster rate to have nonuniform processing * requirements (every 10th hit, more code needs to * be run).*/ DWork[1] = DWork[0]; } /* Processing done at fast rate */ y = sin(ssGetTaskTime(".1")) + DWork[1]; } UpdateFcn if (ssIsSampleHit("1")) { /* Processing on 'u' can be done here. There is a delay of one slow rate period before the fast rate sees it.*/ DWork[0] = u;} Build Support for S-Functions • “About Build Support for S-Functions” on page 14-121 • “Implicit Build Support” on page 14-121 • “Specify Additional Source Files for an S-Function” on page 14-122 • “Use TLC Library Functions” on page 14-123 • “Use rtwmakecfg.m API to Customize Generated Makefiles” on page 14-124 14-120 Insert S-Function Code • “Precompile S-Function Libraries” on page 14-129 About Build Support for S-Functions User-written S-Function blocks provide a powerful way to incorporate legacy and custom code into the Simulink and Simulink Coder development environment. In most cases, you should use S-functions to integrate existing code with Simulink Coder generated code. Several approaches to writing S-functions are available as discussed in • “Write Noninlined S-Functions” on page 14-52 • “Write Wrapper S-Functions” on page 14-54 • “Write Fully Inlined S-Functions” on page 14-64 • “Write Fully Inlined S-Functions with mdlRTW Routine” on page 14-65 • “S-Functions That Support Code Reuse” on page 14-113 • “S-Functions for Multirate Multitasking Environments” on page 14-113 S-functions also provide the most flexible and capable way of including build information for legacy and custom code files in the Simulink Coder build process. This section discusses the different ways of adding S-functions to the Simulink Coder build process. Implicit Build Support When building models with S-functions, the code generator automatically adds rules, include paths, and source filenames to the generated makefile. For this to occur, the source files (.h, .c, and .cpp) for the S-function must be in the same folder as the S-function MEX-file. The code generator propagates this information through the token expansion mechanism of converting a template makefile (TMF) to a makefile. The propagation requires the TMF to support the tokens. Details of the implicit build support follow: • If the file sfcnname.h exists in the same folder as the S-function MEX-file (for example, sfcnname.mexext), the folder is added to the include path. 14-121 14 External Code Integration • If the file sfcnname.c or sfcnname.cpp exists in the same folder as the S-function MEX-file, the Simulink Coder code generator adds a makefile rule for compiling files from that folder. • When an S-function is not inlined with a TLC file, the Simulink Coder code generator must compile the S-function’s source file. To determine the name of the source file to add to the list of files to compile, the code generator searches for sfcnname.cpp on the MATLAB path. If the source file is found, the code generator adds the source filename to the makefile. If sfcnname.cpp is not found on the path, the code generator adds the filename sfcnname.c to the makefile, whether or not it is on the MATLAB path. Note For the Simulink engine to find the MEX-file for simulation and code generation, it must exist on the MATLAB path or be in your current MATLAB working folder. Specify Additional Source Files for an S-Function If your S-function has additional source file dependencies, you must add the names of the additional modules to the build process. You can do this by specifying the filenames • In the S-function modules field of the S-Function block parameter dialog box • With the SFunctionModules parameter in a call to the set_param function For example, suppose you build your S-function with multiple modules, as in mex sfun_main.c sfun_module1.c sfun_module2.c You can then add the modules to the build process by doing one of the following: • Specifying sfun_main, sfun_module1, and sfun_module2 in the S-function modules field in the S-Function block dialog box • Entering the following command at the MATLAB command prompt: 14-122 Insert S-Function Code set_param(sfun_block,'SFunctionModules','sfun_module1 sfun_module2') Alternatively, you can define a variable to represent the parameter value. modules = 'sfun_module1 sfun_module2' set_param(sfun_block,'SFunctionModules', modules) Note The S-function modules field and SFunctionsModules parameter do not support complete source file path specifications. To use the parameter, the Simulink Coder software must be able to find the additional source files when executing the makefile. For the Simulink Coder software to locate the additional files, place them in the same folder as the S-function MEX-file. This will enable you to leverage the implicit build support discussed in “Implicit Build Support” on page 14-121. For more complicated S-function file dependencies, such as specifying source files in other locations or specifying libraries or object files, use the rtwmakecfg.m API, as explained in “Use rtwmakecfg.m API to Customize Generated Makefiles” on page 14-124. Use TLC Library Functions If you inline your S-function by writing a TLC file, you can add source filenames to the build process by using the TLC library function LibAddToModelSources. For details, see “LibAddSourceFileCustomSection (file, builtInSection, newSection)” in the Target Language Compiler documentation. Note This function does not support complete source file path specifications and assumes the Simulink Coder software can find the additional source files when executing the makefile. Another useful TLC library function is LibAddToCommonIncludes. Use this function in a #include statement to include S-function header files in the generated model.h header file. For details, see 14-123 14 External Code Integration “LibAddToCommonIncludes(incFileName)” in the Target Language Compiler documentation. For more complicated S-function file dependencies, such as specifying source files in other locations or specifying libraries or object files, use the rtwmakecfg.m API, as explained in “Use rtwmakecfg.m API to Customize Generated Makefiles” on page 14-124. Use rtwmakecfg.m API to Customize Generated Makefiles • “Overview” on page 14-124 • “Create the rtwmakecfg Function” on page 14-125 • “Modify the Template Makefile” on page 14-127 Overview. Simulink Coder TMFs provide tokens that let you add the following items to generated makefiles: • Source folders • Include folders • Run-time library names • Run-time module objects S-functions can add this information to the makefile by using an rtwmakecfg function. This function is particularly useful when building a model that contains one or more of your S-Function blocks, such as device driver blocks. To add information pertaining to an S-function to the makefile, 1 Create the MATLAB language function rtwmakecfg in a file rtwmakecfg.m. The Simulink Coder software associates this file with your S-function based on its folder location. “Create the rtwmakecfg Function” on page 14-125 discusses the requirements for the rtwmakecfg function and the data it should return. 2 Modify your target’s TMF such that it supports macro expansion for the information returned by rtwmakecfg functions. “Modify the Template Makefile” on page 14-127 discusses the required modifications. 14-124 Insert S-Function Code After the TLC phase of the build process, when generating a makefile from the TMF, the Simulink Coder code generator searches for an rtwmakecfg.m file in the folder that contains the S-function component. If it finds the file, the code generator calls the rtwmakecfg function. Create the rtwmakecfg Function. Create the rtwmakecfg.m file containing the rtwmakecfg function in the same folder as your S-function component (sfcname.mexext on a Microsoft Windows system and sfcname and a platform-specific extension on The Open Group UNIX system). The function must return a structured array that contains the following fields: Field Description makeInfo.includePath A cell array that specifies additional include folder names, organized as a row vector. The Simulink Coder code generator expands the folder names into include instructions in the generated makefile. makeInfo.sourcePath A cell array that specifies additional source folder names, organized as a row vector. You must include the folder names of files entered into the S-function modules field on the S-Function Block Parameters dialog box or into the block’s SFunctionModules parameter if they are not in the same folder as the S-function. The Simulink Coder code generator expands the folder names into make rules in the generated makefile. makeInfo.sources A cell array that specifies additional source filenames (C or C++), organized as a row vector. Do not include the name of the S-function or any files entered into the S-function modules field on the S-Function Block Parameters dialog box or into the block’s SFunctionModules parameter. The Simulink Coder code generator expands the filenames into make variables that contain the source files. You should specify only filenames (with extension). Specify path information with the sourcePath field. 14-125 14 External Code Integration Field Description makeInfo.linkLibsObjs A cell array that specifies additional, fully qualified paths to object or library files against which the Simulink Coder generated code should link. The Simulink Coder code generator does not compile the specified objects and libraries. However, it includes them when linking the final executable. This can be useful for incorporating libraries that you do not want the Simulink Coder code generator to recompile or for which the source files are not available. You might also use this element to incorporate source files from languages other than C and C++. This is possible if you first create a C compatible object file or library outside of the Simulink Coder build process. makeInfo.precompile A Boolean flag that indicates whether the libraries specified in the rtwmakecfg.m file exist in a specified location (precompile==1) or if the libraries need to be created in the build folder during the Simulink Coder build process (precompile==0). makeInfo.library A structure array that specifies additional run-time libraries and module objects, organized as a row vector. The Simulink Coder code generator expands the information into make rules in the generated makefile. See the next table for a list of the library fields. The makeInfo.library field consists of the following elements: Element Description makeInfo.library(n).Name A character array that specifies the name of the library (without an extension). makeInfo.library(n).Location A character array that specifies the folder in which the library is located when precompiled. See the description of makeInfo.precompile in the preceding table for more information. A target can use the TargetPreCompLibLocation parameter to override 14-126 Insert S-Function Code Description Element this value. See “Specify the Location of Precompiled Libraries” on page 22-8 for details. makeInfo.library(n).Modules A cell array that specifies the C or C++ source file base names (without an extension) that comprise the library. Do not include the file extension. The makefile appends the object extension. Note The makeInfo.library field must fully specify each library and how to build it. The modules list in the makeInfo.library(n).Modules element cannot be empty. If you need to specify a link-only library, use the makeInfo.linkLibsObjs field instead. Example: disp(['Running rtwmakecfg from folder: ',pwd]); makeInfo.includePath = { fullfile(pwd, 'somedir2') }; makeInfo.sourcePath = {fullfile(pwd, 'somedir2'), fullfile(pwd, 'somedir3')}; makeInfo.sources = { 'src1.c', 'src2.cpp'}; makeInfo.linkLibsObjs = { fullfile(pwd, 'somedir3', 'src3.object'),... fullfile(pwd, 'somedir4', 'mylib.library')}; makeInfo.precompile = 1; makeInfo.library(1).Name = 'myprecompiledlib'; makeInfo.library(1).Location = fullfile(pwd,'somdir2','lib'); makeInfo.library(1).Modules = {'srcfile1' 'srcfile2' 'srcfile3' }; Note If a path that you specify in the rtwmakecfg.m API contains spaces, the code generator does not automatically convert the path to its non-space equivalent. If the build environments you intend to support do not support spaces in paths, refer to “Enabling the Simulink® Coder™ Software to Build When Path Names Contain Spaces” on page 9-44. Modify the Template Makefile. To expand the information generated by an rtwmakecfg function, you can modify the following sections of your target’s TMF: 14-127 14 External Code Integration • Include Path • C Flags and/or Additional Libraries • Rules The TMF code examples below may not apply to your make utility. For additional examples, see the GRT or ERT TMFs located in matlabroot/rtw/c/grt/*.tmf or matlabroot/rtw/c/ert/*.tmf. Add Folder Names to the Makefile Include Path The following TMF code example adds folder names to the include path in the generated makefile: ADD_INCLUDES = \ |>START_EXPAND_INCLUDES<| -I|>EXPAND_DIR_NAME<| \ |>END_EXPAND_INCLUDES<| Additionally, the ADD_INCLUDES macro must be added to the INCLUDES line, as shown below. INCLUDES = -I. -I.. $(MATLAB_INCLUDES) $(ADD_INCLUDES) $(USER_INCLUDES) Add Library Names to the Makefile The following TMF code example adds library names to the generated makefile. LIBS = |>START_PRECOMP_LIBRARIES<| LIBS += |>EXPAND_LIBRARY_NAME<|.a |>END_PRECOMP_LIBRARIES<| |>START_EXPAND_LIBRARIES<| LIBS += |>EXPAND_LIBRARY_NAME<|.a |>END_EXPAND_LIBRARIES<| For more information on how to use configuration parameters to control library names and location during the build process, see “Control Library Location and Naming During Build” on page 22-7. 14-128 Insert S-Function Code Add Rules to the Makefile The following TMF code example adds rules to the generated makefile. |>START_EXPAND_RULES<| $(BLD)/%.o: |>EXPAND_DIR_NAME<|/%.c $(SRC)/$(MAKEFILE) rtw_proj.tmw @$(BLANK) @echo ### "|>EXPAND_DIR_NAME<|\$*.c" $(CC) $(CFLAGS) $(APP_CFLAGS) -o $(BLD)$(DIRCHAR)$*.o \ |>EXPAND_DIR_NAME<|$(DIRCHAR)$*.c > $(BLD)$(DIRCHAR)$*.lst |>END_EXPAND_RULES<| |>START_EXPAND_LIBRARIES<|MODULES_|>EXPAND_LIBRARY_NAME<| = \ |>START_EXPAND_MODULES<| |>EXPAND_MODULE_NAME<|.o \ |>END_EXPAND_MODULES<| |>EXPAND_LIBRARY_NAME<|.a : $(MAKEFILE) rtw_proj.tmw $(MODULES_|>EXPAND_LIBRARY_NAME<|:%.o=$(BLD)/%.o) @$(BLANK) @echo ### Creating $@ $(AR) -r $@ $(MODULES_|>EXPAND_LIBRARY_NAME<|:%.o=$(BLD)/%.o) |>END_EXPAND_LIBRARIES<| |>START_PRECOMP_LIBRARIES<|MODULES_|>EXPAND_LIBRARY_NAME<| = \ |>START_EXPAND_MODULES<| |>EXPAND_MODULE_NAME<|.o \ |>END_EXPAND_MODULES<| |>EXPAND_LIBRARY_NAME<|.a : $(MAKEFILE) rtw_proj.tmw $(MODULES_|>EXPAND_LIBRARY_NAME<|:%.o=$(BLD)/%.o) @$(BLANK) @echo ### Creating $@ $(AR) -r $@ $(MODULES_|>EXPAND_LIBRARY_NAME<|:%.o=$(BLD)/%.o) |>END_PRECOMP_LIBRARIES<| Precompile S-Function Libraries You can precompile new or updated S-function libraries (MEX-files) for a model by using the MATLAB language function rtw_precompile_libs. Using a specified model and a library build specification, this function builds and places the libraries in a precompiled library folder. 14-129 14 External Code Integration By precompiling S-function libraries, you can optimize system builds. Once your precompiled libraries exist, the Simulink Coder code generator can omit library compilation from subsequent builds. For models that use numerous libraries, the time savings for build processing can be significant. To use rtw_precompile_libs, 1 Set the library file suffix, including the file type extension, based on the platform in use. 2 Set the precompiled library folder. 3 Define a build specification. 4 Issue a call to rtw_precompile_libs. The following procedure explains these steps in more detail. 1 Set the library file suffix, including the file type extension, based on the platform in use. Consider checking for the type of platform in use and then using the TargetLibSuffix parameter to set the library suffix accordingly. For example, you might set the suffix to .a for a UNIX platform and _vc.lib otherwise. if isunix suffix = '.a'; else suffix = '_vc.lib'; end set_param(my_model,'TargetLibSuffix', suffix); 2 Set the precompiled library folder. Use one of the following methods to set the precompiled library folder. • Set the TargetPreCompLibLocation parameter, as explained in “Specify the Location of Precompiled Libraries” on page 22-8. • Set the makeInfo.precompile field in an rtwmakecfg.m function file. 14-130 Insert S-Function Code If you set both TargetPreCompLibLocation and makeInfo.precompile, the setting for TargetPreCompLibLocation takes precedence. The following command sets the precompiled library folder for model my_model to folder lib under the current working folder. set_param(my_model,'TargetPreCompLibLocation', fullfile(pwd,'lib')); Note If you set both the target folder for the precompiled library files and a target library file suffix, the Simulink Coder code generator automatically detects whether any precompiled library files are missing while processing builds. 3 Define a build specification. Set up a structure that defines a build specification. The following table describes fields you can define in the structure. All fields except rtwmakecfgDirs are optional. Field Description rtwmakecfgDirs A cell array of strings that name the folders containing rtwmakecfg files for libraries to be precompiled. The function uses the Name and Location elements of makeInfo.library, as returned by rtwmakecfg, to specify the name and location of the precompiled libraries. If you set the TargetPreCompLibLocation parameter to specify the library folder, that setting overrides the makeInfo.library.Location setting. Note: The specified model must contain blocks that use precompiled libraries specified by the rtwmakecfg files because the TMF-to-makefile conversion generates the library rules only if the libraries are used. libSuffix A string that specifies the suffix, including the file type extension, to be appended to the name of each library (for example, .a or _vc.lib). The string must include a period (.). You must set the suffix with either this field or the TargetLibSuffix parameter. If you specify a suffix with both mechanisms, the TargetLibSuffix setting overrides the setting of this field. 14-131 14 External Code Integration Field Description intOnlyBuild A Boolean flag. When set to true, the flag indicates the libraries are to be optimized such that they are compiled from integer code only. This field applies to ERT targets only. makeOpts A string that specifies an option to be included in the rtwMake command line. addLibs A cell array of structures that specify libraries to be built that are not specified by an rtwmakecfg function. Each structure must be defined with two fields that are character arrays: • libName — the name of the library without a suffix • libLoc — the location for the precompiled library The TMF can specify other libraries and how those libraries are to be built. Use this field if you need to precompile those libraries. The following commands set up build specification build_spec, which indicates that the files to be compiled are in folder src under the current working folder. build_spec = []; build_spec.rtwmakecfgDirs = {fullfile(pwd,'src')}; 4 Issue a call to rtw_precompile_libs. Issue a call to rtw_precompile_libs that specifies the model for which you want to build the precompiled libraries and the build specification. For example: rtw_precompile_libs(my_model,build_spec); 14-132 15 Program Building, Interaction, and Debugging • “Compiler or IDE Selection and Configuration” on page 15-2 • “Program Builds” on page 15-12 • “Build and Run a Program” on page 15-43 • “Profile Code Performance” on page 15-45 • “Data Exchange” on page 15-50 15 Program Building, Interaction, and Debugging Compiler or IDE Selection and Configuration In this section... “Choose and Configure a Compiler” on page 15-2 “Troubleshoot Compiler Configurations” on page 15-9 Choose and Configure a Compiler • “Compilers and the Build Process” on page 15-2 • “Simulink® Coder™ and ANSI C/C++ Compliance” on page 15-3 • “Support for C and C++ Code Generation” on page 15-4 • “Support for International (Non-US-ASCII) Characters” on page 15-5 • “C++ Target Language Considerations” on page 15-7 • “Choose and Configure Compiler on Microsoft Windows” on page 15-8 • “Choose and Configure Compiler on UNIX” on page 15-9 • “Include S-Function Source Code” on page 15-9 Compilers and the Build Process The Simulink Coder build process depends upon the installation of one or more supported compilers. Compiler, in this context, refers to a development environment containing a linker and make utility, in addition to a high-level language compiler. For details on supported compiler versions, see http://www.mathworks.com/support/compilers/current_release Most Simulink Coder targets create an executable that runs on your workstation. When creating the executable, the Simulink Coder build process must be able to access a supported compiler. The build process can automatically find a compiler to use based on your default MEX compiler. The build process also requires the selection of a template makefile. The template makefile determines which compiler runs, during the make phase of the build, to compile the generated code. 15-2 Compiler or IDE Selection and Configuration To determine which template makefiles are for your compiler and target, see Targets Available from the System Target File Browser on page 9-12. For both Simulink Coder generated files and user-supplied files, the file extension, .c or .cpp, determines whether a C or a C++ compiler will be used in the Simulink Coder build process. If the file extension is .c, a C compiler will be used to compile the file, and the symbols will use the C linkage convention. If the file extension is .cpp, a C++ compiler will be used to compile the file, and the symbols by default will use the C++ linkage specification. Simulink Coder and ANSI C/C++ Compliance The Simulink Coder software generates code that is compliant with the following standards: Language Supported Standard C ISO/IEC 9899:1990, also known as C89/C90 C++ ISO/IEC 14882:2003 Code generated by the Simulink Coder software from the following sources is ANSI C/C++ compliant: • Simulink built-in block algorithmic code • Simulink Coder and Embedded Coder system level code (task ID [TID] checks, management, functions, and so on) • Code from other blocksets, including the Simulink Fixed Point product, the Communications System Toolbox product, and so on • Code from other code generators, such as MATLAB functions Additionally, the Simulink Coder software can incorporate code from • Embedded targets (for example, startup code, device driver blocks) • User-written S-functions or TLC files 15-3 15 Program Building, Interaction, and Debugging Note Coding standards for these two sources are beyond the control of the Simulink Coder software, and can be a source for compliance problems, such as code that uses C99 features not supported in the ANSI C, C89/C90 subset. Support for C and C++ Code Generation Simulink Coder supports C and C++ code generation. Consider the following as you choose a language for your generated code: • Whether you need to configure Simulink Coder to use a specific compiler. This is required to generate C++ code on Windows. See “Choose and Configure a Compiler” on page 15-2. • The language configuration setting for the model. See “Select the Target Language” on page 9-71. • Whether you need to integrate legacy or custom code with generated code. For a summary of integration options, see “Integration Options” on page 14-2. • Whether you need to integrate C and C++ code. If so, see “Integration Options” on page 14-2. Note You can mix C and C++ code when integrating Simulink Coder generated code with custom code. However, you must be aware of the differences between C and default C++ linkage conventions, and add the extern "C"’ linkage specifier where required. For the details of the differing linkage conventions and how to apply extern "C", refer to a C++ programming language reference book. • “C++ Target Language Limitations” on page 15-4. For an example, enter sfcndemo_cppcount in the MATLAB Command Window. For a Stateflow example, enter sf_cpp. C++ Target Language Limitations. • Simulink Coder does not support C++ code generation for the following: 15-4 Compiler or IDE Selection and Configuration SimDriveline SimMechanics SimPowerSystems Embedded Targets in Embedded Coder Desktop Targets in Simulink Coder xPC Target • The following Embedded Coder dialog box fields currently do not accept the .cpp extension. However, a .cpp file will be generated if you specify a filename without an extension in these fields, with C++ selected as the target language for your generated code. - Data definition filename field on the Data Placement pane of the Configuration Parameters dialog box - Definition file field for an mpt data object in the Model Explorer These restrictions on specifying .cpp will be removed in a future release. Support for International (Non-US-ASCII) Characters Simulink Coder does not include non-US-ASCII characters in compilable portions of source code. However, Simulink, Stateflow, Simulink Coder, and Embedded Coder do support non-US-ASCII characters in certain ways. When non-US-ASCII characters are encountered during code generation, they either become comments in the generated code or do not propagate into the generated source files. Sources of non-US-ASCII characters are described below: • Simulink Block Names: The name of Simulink blocks are permitted to use non-US-ASCII character sets. The block name can be output in a comment above the generated code for that block when the Simulink block / Stateflow object comments check box is selected. If Simulink Coder also uses the block name in the generated code as an identifier, the identifier’s name changes so only US-ASCII characters are present. One exception to using non-US-ASCII characters in block names is for nonvirtual subsystems configured to use the subsystem name as either the function name or the filename. In this case, only US-ASCII characters can be used to name the subsystem. • User comments on Stateflow diagrams: These comments can contain non-US-ASCII characters. They are written to the generated code when the Include comments check box is selected. 15-5 15 Program Building, Interaction, and Debugging • Custom TLC files (.tlc): User-created Target Language Compiler files can have non-US-ASCII characters inside both TLC comments and in any code comments which are output. The Target Language Compiler does not support non-US-ASCII characters in TLC variable or function names. Additional Support with Embedded Coder. Users of Embedded Coder have additional international character support: • Simulink Block Description: Embedded Coder propagates block descriptions entered from Simulink Block Parameter dialog boxes into the generated code as comments when the Simulink block descriptions check box on the Code Generation > Comments pane of the Configuration Parameters dialog box is selected. Non-US-ASCII characters are supported for these descriptions. • Embedded Coder code template file: Code Generation Template (.cgt) files provide customization capability for the generated code. Any output lines in the .cgt file which are C or C++ comments can contain non-US-ASCII characters, for example the file banner and file trailer sections; these comments are propagated to the generated code. However, although TLC comments in .cgt files can contain non-US-ASCII characters, these TLC comments are not propagated to the generated code. • Stateflow object descriptions: Stateflow object descriptions can contain non-US-ASCII characters. The description will appear as a comment above the generated code for that chart when the Stateflow object descriptions check box is selected. • Simulink Parameter Object Description: Simulink Parameter Object descriptions can contain non-US-ASCII characters. The description will appear as a comment above the generated code when the Simulink data object descriptions check box is selected. • MPT Signal Object Description: MPT object descriptions can contain non-US-ASCII characters. The description will appear as a comment above the generated code when the Simulink data object descriptions check box is selected. Character Set Limitation. You can encounter problems with models containing characters of a specific character set, such as Shift JIS, on a host system for which that character set is not configured as the default. 15-6 Compiler or IDE Selection and Configuration When models containing characters of a given character set are used on a host system that is not configured with that character set as the default, Simulink can incorrectly interpret characters during model loading and saving. This can lead to corrupted characters being displayed in the model and possibly the model failing to load. It can also lead to corrupted characters in the model file if you save it. This limitation does not exist when the characters used in the model are in the default character set for the host system. For example, you can use Shift JIS characters with no issues if the host system is configured to use Japanese Windows. Additionally, during code generation, the Target Language Compiler can have similar problems reading characters from either the model.rtw or user written .tlc files. This can result in corrupt characters in generated source file comments or a Target Language Compiler error. For an example of international character set support for code generation, run the example model rtwdemo_international. This example model is set up to work around the character limitations described above. If you run this example from a non-Japanese MATLAB host machine, you must set up an international character set for Simulink. For example, type bdclose all; set_param(0, 'CharacterEncoding', 'Shift_JIS') rtwdemo_international Other uses of non-US-ASCII characters in models or in files used during the build process are not supported; you should not depend on any incidental functionality that may exist. For additional information, see the slCharacterEncoding function. C++ Target Language Considerations To use the C++ target language support, you might need to configure the Simulink Coder software to use a specific compiler. For example, on a Microsoft Windows platform the default compiler is the Lcc C compiler shipped with the MATLAB product, which does not support C++. If you do not configure the Simulink Coder software to use a C++ compiler before you specify C++ for code generation, the following build error message appears: 15-7 15 Program Building, Interaction, and Debugging The specified target is configured to generate C++, but the C-only compiler, LCC, is the default compiler. To specify a C++ compiler, enter 'mex -setup' at the command prompt. To generate C code, click (Open) to open the Configuration Parameters dialog and set the target language to C. Choose and Configure Compiler on Microsoft Windows On Windows platforms, you can use the Lcc C compiler shipped with the MATLAB product, or you can install and use one of the supported Windows compilers. The Simulink Coder code generator will choose a compiler based on the template makefile (TMF) name specified on the Code Generation pane of the Configuration Parameters dialog box. The simplest approach is to let the code generator pick a compiler based on your default compiler, as set up using the mex -setup function. When you use this approach, you do not need to define compiler-specific environment variables, and the Simulink Coder code generator determines the location of the compiler using information from the mexopts.bat file located in the preferences folder (use the prefdir command to verify this location). To use this approach, the TMF filename specified must be a MATLAB language file that returns default compiler information by using the mexopts.bat file. Most targets provided by the Simulink Coder product use this approach, as when grt_default_tmf or ert_default_tmf is specified as the TMF name. Alternatively, the name provided for the TMF can be a compiler-specific template makefile, for example grt_vc.tmf, which designates the Microsoft Visual C++ compiler. When you provide a compiler-specific TMF filename, the Simulink Coder code generator uses the default mexopts.bat information to locate the compiler if mex has been set up for the same compiler as the specified TMF. If mex is not set up with a default compiler, or if it does not match the compiler specified by the TMF, then an environment variable must exist for the compiler specified by the TMF. The environment variable required depends on the compiler. 15-8 Compiler or IDE Selection and Configuration Choose and Configure Compiler on UNIX On a UNIX platform, the Simulink Coder build process uses the default compiler. The default compiler is cc. You should choose the UNIX template makefile for your target. For example, grt_unix.tmf is the template makefile for building a generic real-time program on a UNIX platform. Include S-Function Source Code When the Simulink Coder code generator builds models with S-functions, source code for the S-functions can be either in the current folder or in the same folder as their MEX-file. The code generator adds an include path to the generated makefiles whenever it finds a file named sfncname.h in the same folder that the S-function MEX-file is in. This folder must be on the MATLAB path. Similarly, the Simulink Coder code generator adds a rule for the folder when it finds a file sfncname.c (or .cpp) in the same folder as the S-function MEX-file is in. Troubleshoot Compiler Configurations • “Compiler Version Mismatch Errors” on page 15-9 • “Generated Executable Image Produces Incorrect Results” on page 15-10 • “Compile-Time Errors” on page 15-10 Compiler Version Mismatch Errors Explanation. You received a version mismatch error when you compiled code generated by the Simulink Coder software. User Action. 1 Check the list of currently supported and compatible compilers available at http://www.mathworks.com/support/compilers/current_release/. 15-9 15 Program Building, Interaction, and Debugging 2 If necessary, upgrade or change your compiler. For more information, see “Choose and Configure a Compiler” on page 15-2. 3 Rebuild the model. Generated Executable Image Produces Incorrect Results Explanation. You applied compiler optimizations when you used Simulink Coder to generate an executable image. However, the optimizations caused the executable image to produce incorrect results, even though expected code was generated. User Action. Do one of the following: • Lower the compiler optimization level. 1 Select Custom for the Model Configuration parameter Code Generation > Compiler optimization level. The Custom compiler optimization flags field appears. 2 Specify a lower optimization level in the Custom compiler optimization flags field. 3 Rebuild the model. • Disable compiler optimizations. 1 Select Optimizations off (faster builds) for the Model Configuration parameter Code Generation > Compiler optimization level. 2 Rebuild the model. For more information, see “Control Compiler Optimizations” on page 16-6 and your compiler documentation. Compile-Time Errors Explanations. • You received a compiler configuration error. 15-10 Compiler or IDE Selection and Configuration • Environment variables for your make utility, compiler, or linker are set up incorrectly. For example, installation of Cygwin tools on a Windows platform might affect environment variables used by other compilers. • Custom code specified as an S-function block or in the Code Generation > Custom Code pane of the Configuration Parameters dialog includes errors. For example, the code might refer to a header file that the compiler cannot find. • The model includes a block, such as a device driver block, that is not intended for use with the currently selected target. User Actions. • Make sure that MATLAB supports the compiler and version that you want to use. For a list of currently supported and compatible compilers, see http://www.mathworks.com/support/compilers/current_release/. If necessary, upgrade or change your compiler (see “Choose and Configure a Compiler” on page 15-2). • Review the environment variable settings for your system by using the set command on a Windows platform or setenv on a UNIX platform. Make sure the settings match what is required for the tools you are using. • Remove the custom code from the model, to help isolate the source of the problem, debug, and rebuild. • Remove the target-specific block or configure the model for use with the another target. 15-11 15 Program Building, Interaction, and Debugging Program Builds In this section... “Configure the Build Process” on page 15-12 “Initiate the Build Process” on page 15-14 “Build a Generic Real-Time Program” on page 15-14 “Rebuild a Model” on page 15-27 “Control Regeneration of Top Model Code” on page 15-27 “Reduce Build Time for Referenced Models” on page 15-28 “Relocate Code to Another Development Environment” on page 15-33 “How Executable Programs Are Built From Models” on page 15-38 Configure the Build Process • “Specify TLC Options” on page 15-12 • “Specify Whether To Generate a Makefile” on page 15-13 • “Specify a Make Command” on page 15-13 • “Specify the Template Makefile” on page 15-13 Specify TLC Options You can enter Target Language Compiler (TLC) command line options in the TLC options edit field, for example • -aVarName=1 to declare a TLC variable and/or assign a value to it • -IC:\Work to specify an include path • -v to obtain verbose output from TLC processing (for example, when debugging) Specifying TLC options does not add any flags to the Make command field, as do some of the targets available in the System Target File Browser. For additional information, see “Target Language Compiler Overview”. 15-12 Program Builds Specify Whether To Generate a Makefile The Generate makefile option specifies whether the Simulink Coder build process is to generate a makefile for a model. By default, the Simulink Coder build process generates a makefile. You can suppress the generation of a makefile, for example in support of custom build processing that is not based on makefiles, by clearing Generate makefile . When you clear this option, • The Make command and Template makefile options are unavailable. • You must set up any post code generation build processing, using a user-defined command, as explained in “Customize Post-Code-Generation Build Processing” on page 22-13. Specify a Make Command A high-level MATLAB command, invoked when a build is initiated, controls the Simulink Coder build process. Each target has an associated make command. The Make command field displays this command. Almost all targets use the default command, make_rtw. Third-party targets might supply another make command. See the vendor’s documentation. In addition to the name of the make command, you can supply arguments in the Make command field. These arguments include compiler-specific options, include paths, and other parameters. When the build process invokes the make utility, these arguments are passed along in the make command line. “Template Makefiles and Make Options” on page 9-38 lists the Make command arguments you can use with each supported compiler. Specify the Template Makefile The Template makefile field has these functions: • If you have selected a target configuration using the System Target File Browser, this field displays the name of a MATLAB language file that selects a template makefile for your development environment. For example, in “Code Generation Pane: General”, the Template makefile field displays grt_default_tmf, indicating that the build process invokes grt_default_tmf.m. 15-13 15 Program Building, Interaction, and Debugging “Template Makefiles and Make Options” on page 9-38 gives a detailed description of the logic by which the Simulink Coder build process selects a template makefile. • Alternatively, you can explicitly enter the name of a specific template makefile (including the extension) or a MATLAB language file that returns a template make file in this field. You must do this if you are using a target configuration that does not appear in the System Target File Browser. For example, do this if you have written your own template makefile for a custom target environment or you. If you specify your own template makefile, be sure to include the filename extension. If you omit the extension, the Simulink Coder build process attempts to find and execute a file with the extension .m (that is, a MATLAB language file). The template make file (or a MATLAB language file that returns a template make file) must be on the MATLAB path. To determine whether the file is on the MATLAB path, enter the following command in the MATLAB Command Window: which tmf_filename Initiate the Build Process You can initiate code generation and the build process by using the following options: • Clear the Generate code only option on the Code Generation pane of the Configuration Parameters dialog box and click Build. • Press Ctrl+B. • Select Code > C/C++ Code > Build Model. • Invoke the rtwbuild command from the MATLAB command line. • Invoke the slbuild command from the MATLAB command line. Build a Generic Real-Time Program • “About Building a Program” on page 15-15 • “Working and Build Folders” on page 15-15 • “Set Program Parameters” on page 15-16 15-14 Program Builds • “Select a Target Configuration” on page 15-18 • “Build and Run a Program” on page 15-23 • “Contents of the Build Folder” on page 15-25 About Building a Program This section walks through the process of generating C code and building an executable program from an example model. The resulting stand-alone program runs on your workstation, independent of external timing and events. Working and Build Folders It is convenient to work with a local copy of the sldemo_f14 model, stored in its own folder, f14example. Set up your working folder as follows: 1 In the MATLAB Current Folder browser, navigate to a folder where you have write access. 2 Create the working folder from the MATLAB command line by typing: mkdir f14example 3 Make f14example your working folder: cd f14example 4 Open the sldemo_f14 model: sldemo_f14 The model appears in the Simulink window. 5 In the model window, choose File > Save As. Navigate to your working folder, f14example. Save a copy of the sldemo_f14 model. During code generation, the Simulink Coder software creates a build folder within your working folder. The build folder name is model_target_rtw, derived from the name of the source model and the chosen target. The build folder stores generated source code and other files created during the build process. You examine the build folder contents at the end of this example. 15-15 15 Program Building, Interaction, and Debugging Note When a model contains Model blocks (which enable one Simulink model to include others), special project folders are created in your working folder to organize code for referenced models. Project folders exist alongside of Simulink Coder build folders, and are always named slprj. “Generate Code for Referenced Models” on page 3-4 describes navigating project folder structures in Model Explorer. Set Program Parameters To generate code from your sldemo_f14 model, you must change some of the simulation parameters. In particular, note that generic real-time (GRT) and most other targets require that the model specify a fixed-step solver. Note The Simulink Coder software can generate code for models using variable-step solvers for rapid simulation (rsim) and S-function targets only. To set parameters, use the Model Explorer as follows: 1 Open Model Explorer by selecting Model Explorer from the model’s View menu. 2 In the Model Hierarchy pane, expand the model name node to reveal its components. 3 Click Configuration (Active) in the left pane. 4 Click Solver in the center pane. The Solver pane appears at the right. 5 Enter the following parameter values on the Solver pane (some may already be set): • Start time: 0.0 • Stop time: 60 • Type: Fixed-step • Solver: ode5 (Dormand-Prince) 15-16 Program Builds • Fixed step size (fundamental sample time): 0.1 • Tasking mode for periodic sample times: SingleTasking The Solver pane with the modified parameter settings is shown below. Note the tan background color of the controls you just changed. The color also appears on fields that were set automatically by your choices in other fields. Use this visual feedback to verify that what you set is what you intended. When you apply your changes, the background color reverts to white. 6 Click Apply to register your changes. 7 Save the model. Simulation parameters persist with the model, for use in future sessions. 15-17 15 Program Building, Interaction, and Debugging Select a Target Configuration Note Some of the steps in this section do not require you to make changes. They are included to help you familiarize yourself with the Simulink Coder user interface. As you step through the dialog boxes, place the mouse pointer on any item of interest to see a tooltip describing its function. To specify the desired target configuration, you choose a system target file, a template makefile, and a make command. In these examples (and in most applications), you do not need to specify these parameters individually. Here, you use the ready-to-run generic real-time target (GRT) configuration. The GRT target is designed to build a stand-alone executable program that runs on your workstation. To select the GRT target via the Model Explorer: 1 With the sldemo_f14 model open, select View > Model Explorer to open the Model Explorer. 2 In the Model Hierarchy pane, expand the model node to reveal its components. 3 Click Configuration (Active) in the left pane. 4 Click Code Generation in the center pane. The Code Generation pane appears at the right. This pane has several tabs. 5 Click the General tab to activate the pane that controls target selection. 15-18 Program Builds 6 Click the Browse button next to the System target file field. This opens the System Target File Browser, illustrated below. The browser displays a list of all currently available target configurations. Your available configurations may differ. When you select a target configuration, the Simulink Coder software automatically chooses the system target file, template makefile, and make command for that configuration. Their names appear at the bottom left of the window. Note The system target file browser lists all system target files found on the MATLAB path. Using some of these might require additional licensed products, such as the Embedded Coder product. 15-19 15 Program Building, Interaction, and Debugging 7 From the list of available configurations, select Generic Real-Time Target (as shown above) and then click OK. The Code Generation pane displays the system target file (grt.tlc), make command (make_rtw), and template makefile (grt_default_tmf), as shown below: 15-20 Program Builds 8 Select the Code Generation > Debug pane. The options displayed here control build verbosity and debugging support, and are common to all target configurations. Make sure that all options are set to their defaults, as shown below. 15-21 15 Program Building, Interaction, and Debugging 9 Select the Code Generation > Symbols pane. The options on this pane control the look and feel of generated code. 15-22 Program Builds 10 Select the Code Generation > Comments pane. The options displayed here control the types of comments included in generated code. Make sure that all options are set to their defaults, as shown below. 11 Make sure that the Generate code only check box at the bottom of the pane is cleared. 12 Save the model. Build and Run a Program The Simulink Coder build process generates C code from the model, and then compiles and links the generated program to create an executable image. To build and run the program, 1 With the sldemo_f14 model open, go to the Model Explorer window. In the Code Generation pane, click the Build button to start the build process. A number of messages concerning code generation and compilation appear in the MATLAB Command Window. The initial message is ### Starting build procedure for model: sldemo_f14 The contents of many of the succeeding messages depends on your compiler and operating system. The final message is ### Successful completion of build procedure for model: sldemo_f14 15-23 15 Program Building, Interaction, and Debugging The working folder now contains an executable, sldemo_f14.exe (Microsoft Windows platforms) or sldemo_f14 (UNIX platforms). In addition, the Simulink Coder build process has created a project folder, slprj, and a build folder, sldemo_f14_grt_rtw, in your working folder. Note The Simulink Coder build process displays a code generation report after generating the code for the sldemo_f14 model. The example “Optimizing Generated Code” on page 18-2 provides more information about how to create and use a code generation report. 2 To observe the contents of the working folder after the build, type the dir command from the MATLAB Command Window. dir . .. sldemo_f14.exe sldemo_f14.slx sldemo_f14_grt_rtw slprj 3 To run the executable from the Command Window, type !sldemo_f14 The ! character passes the command that follows it to the operating system, which runs the stand-alone sldemo_f14 program. The program produces one line of output in the Command Window: **starting the model** No data is output. 4 Finally, to see the files created in the build folder, type dir sldemo_f14_grt_rtw The exact list of files produced varies among MATLAB platforms and versions. Here is a sample list from a Windows platform. . .. 15-24 grt_main.obj html rt_nonfinite.h rt_nonfinite.obj Program Builds buildInfo.mat defines.txt sldemo_f14.bat sldemo_f14.c sldemo_f14.h sldemo_f14.mk sldemo_f14.obj sldemo_f14_private.h sldemo_f14_ref.rsp sldemo_f14_types.h modelsources.txt ode5.obj rtGetInf.c rtGetInf.h rtGetInf.obj rtGetNaN.c rtGetNaN.h rtGetNaN.obj rt_logging.obj rt_nonfinite.c rt_rand.c rt_rand.h rt_rand.obj rt_sim.obj rtmodel.h rtw_proj.tmw rtwtypes.h rtwtypeschksum.mat Contents of the Build Folder The build process creates a build folder and names it model_target_rtw, where model is the name of the source model and target is the target selected for the model. In this example, the build folder is named sldemo_f14_grt_rtw. The build folder includes the following generated files. Note The code generation report you created for the sldemo_f14 model in the previous section displays a link for each file listed below, which you can click to explore the file contents. File Description sldemo_f14.c Standalone C code that implements the model rt_nonfinite.c rtGetInf.c rtGetNaN.c Functions to initialize nonfinite types (Inf, NaN, and -Inf) rt_rand.c Random functions, included only if used by the application sldemo_f14.h An include header file containing definitions of parameters and state variables sldemo_f14_private.h Header file containing common include definitions 15-25 15 Program Building, Interaction, and Debugging File Description sldemo_f14_types.h Forward declarations of data types used in the code rt_nonfinite.h rtGetInf.h rtGetNaN.h Provides support for nonfinite numbers in the generated code, dynamically generates Inf, NaN, and -Inf rt_rand.h Imported declarations for random functions, included only if used by the application rtmodel.h Master header file for including generated code in the static main program (its name never changes, and it simply includes sldemo_f14.h) rtwtypes.h Static include file for Simulink simstruct data types; some embedded targets tailor this file to reduce overhead, but GRT does not The build folder contains other files used in the build process, most of which you can disregard for the present: • sldemo_f14.mk — Makefile generated from a template for the GRT target • Object (.obj) files • sldemo_f14.bat — Batch control file • rtw_proj.tmw — Marker file • buildInfo.mat — Build information for relocating generated code to another development environment • defines.txt — Preprocessor defines required for compiling the generated code • sldemo_f14_ref.rsp — Data to include as command-line arguments to mex (Windows systems only) The build folder also contains a subfolder, html, which contains the files that make up the code generation report. For more information about the code generation report, see “Reports for Code Generation” on page 11-2. 15-26 Program Builds Rebuild a Model If you update generated source code or makefiles manually to add customizations, you can rebuild the files with the rtwrebuild command. This command recompiles the modified files by invoking the generated makefile. Alternatively, you can use this command from the Model Explorer, 1 In the Model Hierarchy pane, expand the node for the model of interest. 2 Click the Code for model node. 3 In the Code pane, click run rtwrebuild, listed to the right of the label Code Recompile Command. Control Regeneration of Top Model Code When you rebuild a model, by default, the build process performs checks to determine whether changes to the model or relevant settings require regeneration of the top model code. Top model code is regenerated if any of the following conditions is true: • The structural checksum of the model has changed. • The top-model-only checksum has changed. The top-model-only checksum provides information about top model parameters, such as application lifespan, maximum stack size, make command, verbose and .rtw file debug settings, and the TLC options parameter. • Any of the following TLC debugging model options, located on the Code Generation > Debug pane of the Configuration Parameters dialog box, is on: - Start TLC debugger when generating code (TLCDebug) Start TLC coverage when generating code (TLCCoverage) Enable TLC assertion (TLCAssert) Profile TLC (ProfileTLC) If the checks determine that top model code generation is required, the build process fully regenerates and compiles the model code. 15-27 15 Program Building, Interaction, and Debugging If the checks indicate that the top model generated code is current with respect to the model, and no model settings require full regeneration, the build process omits regeneration of the top model code. This can significantly reduce model build times. Regardless of whether the top model code is regenerated, the build process subsequently calls all build process hooks, including STF_make_rtw_hook functions and the post code generation command, and reruns the makefile so that any external dependencies are recompiled and relinked. Note Target authors can perform actions related to code regeneration, including forcing or reacting to code regeneration, in the STF_make_rtw_hook functions that are called by the build process. For more information, see “Control Code Regeneration Using STF_make_rtw_hook.m” on page 22-26. If you want to control or override the default top model build behavior, use one of the following command-line options: • To ignore the checksum and force regeneration of the top model code: - rtwbuild(model,'ForceTopModelbuild',true) slbuild(model,'StandaloneRTWTarget','ForceTopModelBuild',true) • To clean the model build area enough to trigger regeneration of the top model code at the next build (slbuild only): slbuild(model,'CleanTopModel') Note You can also force regeneration of the top model code by deleting code generation folders, for example, slprj or the generated model code folder. Reduce Build Time for Referenced Models • “Parallel Building For Large Model Reference Hierarchies” on page 15-29 • “Parallel Building Configuration Requirements” on page 15-30 • “Build Models In a Parallel Computing Environment” on page 15-30 15-28 Program Builds • “Locate Parallel Build Logs” on page 15-31 Parallel Building For Large Model Reference Hierarchies In a parallel computing environment, you can increase the speed of code generation and compilation for models containing large model reference hierarchies by building referenced models in parallel whenever conditions allow. For example, if you have Parallel Computing Toolbox™ software, code generation and compilation for each referenced model can be distributed across the cores of a multicore host computer. If you additionally have MATLAB Distributed Computing Server™ (MDCS) software, code generation and compilation for each referenced model can be distributed across remote workers in your MATLAB Distributed Computing Server configuration. The performance gain realized by using parallel builds for referenced models depends on several factors, including how many models can be built in parallel for a given model referencing hierarchy, the size of the referenced models, and parallel computing resources such as number of local and/or remote workers available and the hardware attributes of the local and remote machines (amount of RAM, number of cores, and so on). For configuration requirements that might apply to your parallel computing environment, see “Parallel Building Configuration Requirements” on page 15-30. For a description of the general workflow for building referenced models in parallel whenever conditions allow, see “Build Models In a Parallel Computing Environment” on page 15-30. For information on how to configure a custom embedded target to support parallel builds, see “Support Model Referencing” on page 24-101. Note In an MDCS parallel computing configuration, parallel building is designed to work interactively with the MATLAB Distributed Computing Server software. You can initiate builds from the Simulink user interface or from the MATLAB Command Window using commands such as slbuild. You cannot initiate builds using batch or other batch mode workflows. 15-29 15 Program Building, Interaction, and Debugging Parallel Building Configuration Requirements The following requirements apply to configuring your parallel computing environment for building model reference hierarchies in parallel whenever conditions allow: • For local pools, the host machine must have enough RAM to support the number of local workers (MATLAB sessions) that you plan to use. For example, setting matlabpool to 4 results in five MATLAB sessions on your machine, each using approximately 120 MB of memory at startup. • Remote MDCS workers participating in a parallel build must use a common platform and compiler. • A consistent MATLAB environment must be set up in each MATLAB worker session as in the MATLAB client session — for example, all shared base workspace variables, MATLAB path settings, and so forth. One approach is to use the PreLoadFcn callback of the top model. If you configure your model to load the top model with each MATLAB worker session, its preload function can be used for any MATLAB worker session setup. Build Models In a Parallel Computing Environment To take advantage of parallel building for a model reference hierarchy: 1 Set up a pool of local and/or remote MATLAB workers in your parallel computing environment. a Make sure that Parallel Computing Toolbox software is licensed and installed. b To use remote workers, make sure that MATLAB Distributed Computing Server software is licensed and installed. c Issue MATLAB commands to set up the worker pool, for example, matlabpool 4. 2 In the Configuration Parameters dialog box, go to the Model Referencing pane and select the Enable parallel model reference builds option. This selection enables the parameter MATLAB worker initialization for builds. 15-30 Program Builds For MATLAB worker initialization for builds, select one of the following values: • None if the software should perform no special worker initialization. Specify this value if the child models in the model reference hierarchy do not rely on anything in the base workspace beyond what they explicitly set up (for example, with a model load function). • Copy base workspace if the software should attempt to copy the base workspace to each worker. Specify this value if you use a setup script to prepare the base workspace for all models to use. • Load top model if the software should load the top model on each worker. Specify this value if the top model in the model reference hierarchy handles all of the base workspace setup (for example, with a model load function). 3 Optionally, inspect the model reference hierarchy to determine, based on model dependencies, which models will be built in parallel. For example, you can use the Model Dependency Viewer from the Simulink Analysis > Model Dependencies menu. 4 Build your model. Messages in the MATLAB Command Window record when each parallel or serial build starts and finishes. The order in which referenced models build is nondeterministic. They might build in a different order each time the model is built. If you need more information about a parallel build, for example, if a build fails, see “Locate Parallel Build Logs” on page 15-31. Locate Parallel Build Logs When you build a model for which referenced models are built in parallel, messages in the MATLAB Command Window record when each parallel or serial build starts and finishes. Any referenced models that build in parallel have only summary log entries in the command window, even if verbose builds are turned on. For example, ### Initializing parallel workers for parallel model reference build. 15-31 15 Program Building, Interaction, and Debugging ### Parallel worker initialization complete. ### Starting parallel model reference SIM build for 'bot_model001' ### Starting parallel model reference SIM build for 'bot_model002' ### Starting parallel model reference SIM build for 'bot_model003' ### Starting parallel model reference SIM build for 'bot_model004' ### Finished parallel model reference SIM build for 'bot_model001' ### Finished parallel model reference SIM build for 'bot_model002' ### Finished parallel model reference SIM build for 'bot_model003' ### Finished parallel model reference SIM build for 'bot_model004' ### Starting parallel model reference RTW build for 'bot_model001' ### Starting parallel model reference RTW build for 'bot_model002' ### Starting parallel model reference RTW build for 'bot_model003' ### Starting parallel model reference RTW build for 'bot_model004' ### Finished parallel model reference RTW build for 'bot_model001' ### Finished parallel model reference RTW build for 'bot_model002' ### Finished parallel model reference RTW build for 'bot_model003' ### Finished parallel model reference RTW build for 'bot_model004' If a parallel builds fails, you might see output similar to the following: ### Initializing parallel workers for parallel model reference build. ### Parallel worker initialization complete. ... ### Starting parallel model reference RTW build for 'bot_model002' ### Starting parallel model reference RTW build for 'bot_model003' ### Finished parallel model reference RTW build for 'bot_model002' ### Finished parallel model reference RTW build for 'bot_model003' ### Starting parallel model reference RTW build for 'bot_model001' ### Starting parallel model reference RTW build for 'bot_model004' ### Finished parallel model reference RTW build for 'bot_model004' ### The following error occurred during the parallel model reference RTW build for 'bot_model001': Error(s) encountered while building model "bot_model001" ### Cleaning up parallel workers. To obtain more detailed information about the failed build, you can examine the parallel build log. For each referenced model built in parallel, the build process generates a file named model_buildlog.txt, where model is the 15-32 Program Builds name of the referenced model. This file contains the full build log for that model. If a parallel build completes, the build log file is placed in the build subfolder corresponding to the referenced model. For example, for a build of referenced model bot_model004, you would look for the build log file bot_model004_buildlog.txt in a referenced model subfolder such as build_folder/slprj/grt/bot_model004, build_folder/slprj/ert/bot_model004, or build_folder/slprj/sim/bot_model004. If a parallel build fails, the build log can be found in a referenced model subfolder under the build subfolder /par_mdl_ref/model. For example, for a failed parallel build of model bot_model001, you would look for the build log file bot_model001_buildlog.txt in a subfolder such as build_folder/par_mdl_ref/bot_model001/slprj/grt/bot_model001, build_folder/par_mdl_ref/bot_model001/slprj/ert/bot_model001, or build_folder/par_mdl_ref/bot_model001/slprj/sim/bot_model001. Relocate Code to Another Development Environment • “About Code Relocation” on page 15-33 • “Package Code Using the Graphical User Interface” on page 15-34 • “Package Code Using the Command-Line Interface” on page 15-34 • “packNGo Function Limitations” on page 15-38 About Code Relocation If you need to relocate the static and generated code files for a model to another development environment, such as a system or an integrated development environment (IDE) that does not include MATLAB and Simulink products, use the Simulink Coder pack-and-go utility. This utility uses the tools for customizing the build process after code generation and a packNGo function to find and package files for building an executable image. The files are packaged in a compressed file that you can relocate and unpack using a standard zip utility. To package model code files, you can do either of the following: 15-33 15 Program Building, Interaction, and Debugging • Use the model option Package code and artifacts on the Code Generation pane of the Configuration Parameters dialog box. See “Package Code Using the Graphical User Interface” on page 15-34. • Use MATLAB commands to configure a PostCodeGenCommand parameter with a call to the packNGo function. See “Package Code Using the Command-Line Interface” on page 15-34. The command-line interface provides more control over the details of code packaging. Package Code Using the Graphical User Interface To package and relocate code for your model using the graphical user interface: 1 Open the Configuration Parameters dialog box and select the Code Generation pane. 2 Select the option Package code and artifacts. This option configures the build process to run the packNGo function after code generation to package generated code and artifacts for relocation. 3 In the Zip file name field, enter the name of the zip file in which to package generated code and artifacts for relocation. The file name can be specified with or without the .zip extension. If you specify no extension or an extension other than .zip, the zip utility adds the.zip extension. If no value is specified, the build process uses the name model.zip, where model is the name of the top model for which code is being generated. 4 Apply changes and generate code for your model. Inspect the resulting zip file to verify that it is ready for relocation. Depending on the zip tool you use you might be able to open and inspect the file without unpacking it. 5 Relocate the zip file to the destination development environment and unpack the file. Package Code Using the Command-Line Interface To package and relocate code for your model using the command-line interface: 15-34 Program Builds 1 Select a structure for the zip file. 2 Select a name for the zip file. 3 Package the model code files in the zip file. 4 Inspect the generated zip file. 5 Relocate and unpack the zip file. Select a Structure for the Zip File. Before you generate and package the files for a model build, decide whether you want the files to be packaged in a flat or hierarchical folder structure. By default, the packNGo function packages the files in a single, flat folder structure. This is the simplest approach and might be the optimal choice. If... Then Use a... You are relocating files to an IDE that does not use the generated makefile or the code is not dependent on the relative location of required static files Single, flat folder structure The target development environment must maintain the folder structure of the source environment because it uses the generated makefile or the code is dependent on the relative location of files Hierarchical structure If you use a hierarchical structure, the packNGo function creates two levels of zip files, a primary zip file, which in turn contains the following secondary zip files: • mlrFiles.zip — files in your matlabroot folder tree • sDirFiles.zip — files in and under your build folder where you initiated the model’s code generation • otherFiles.zip — required files not in the matlabroot or start folder trees 15-35 15 Program Building, Interaction, and Debugging Paths for the secondary zip files are relative to the root folder of the primary zip file, maintaining the source development folder structure. Select a Name for the Zip File. By default, the packNGo function names the primary zip file model.. You have the option of specifying a different name. If you specify a file name and omit the file type extension, the function appends . to the name you specify. Package Model Code in a Zip File. You package model code files by using the PostCodeGenCommand configuration parameter, packNGo function, and the model’s build information object. You can set up the packaging operation to use • A system generated build information object. In this case, use set_param to set the configuration parameter PostCodeGenCommand to an explicit call to the packNGo function before generating the model code. For example: set_param(bdroot, 'PostCodeGenCommand', 'packNGo(buildInfo);'); This command instructs the Simulink Coder build process to evaluate the call to packNGo, using the system generated build information object for the currently selected model, after generating and writing the model’s code to disk and before generating a makefile. • A build information object that you construct programmatically, as explained in “Customize Post-Code-Generation Build Processing” on page 22-13. In this case, you might use other build information functions to selectively include paths and files in the build information object that you then specify with the packNGo function. For example: . . . myModelBuildInfo = RTW.BuildInfo; addSourceFiles(myModelBuildInfo, {'test1.c' 'test2.c' 'driver.c'}); . . . 15-36 Program Builds packNGo(myModelBuildInfo); To change the default behavior of packNGo, see the following examples: To... Specify... Change the structure of the file packaging to hierarchical packNGo(buildInfo, {'packType' 'hierarchical'}); Rename the primary zip file packNGo(buildInfo, {'fileName' 'zippedsrcs'}); Change the structure of the file packaging to hierarchical and rename the primary zip file packNGo(buildInfo, {'packType' 'hierarchical'... 'fileName' 'zippedsrcs'}); Include all header files found on the include path (rather than the minimal header files required to build the code) in the zip file packNGo(buildInfo, {'minimalHeaders' false}); Note The packNGo function potentially can modify the build information passed in the first packNGo argument. As part of packaging model code, packNGo might find additional files from source and include paths recorded in the model’s build information and add them to the build information. Inspect a Generated Zip File. Inspect the generated zip file to verify that it is ready for relocation. Depending on the zip tool you use you might be able to open and inspect the file without unpacking it. If you need to unpack the file and you packaged the model code files as a hierarchical structure, you will need to unpack the primary and secondary zip files. When you unpack the secondary zip files, relative paths of all files are preserved. Relocate and Unpack a Zip File. Relocate the generated zip file to the destination development environment and unpack the file. 15-37 15 Program Building, Interaction, and Debugging Code Packaging Example. The following example guides you through the steps for packaging code files generated for the example model rtwdemo_rtwintro using the command-line interface: 1 Set your working folder to a writable folder. 2 Open the model rtwdemo_rtwintro and save a copy to your working folder. 3 Enter the following command in the MATLAB Command Window: set_param('rtwdemo_rtwintro', 'PostCodeGenCommand',... 'packNGo(buildInfo, {''packType'' ''hierarchical''})'); You must double the single-quotes due to the nesting of character arrays 'packType' and 'hierarchical' within the character array that specifies the call to packNGo. 4 Generate code for the model. 5 Inspect the generated zip file, rtwdemo_rtwintro.zip. The zip file contains the two secondary zip files, mlrFiles.zip and sDirFiles.zip. 6 Inspect the zip files mlrFiles.zip and sDirFiles.zip. 7 Relocate the zip file to a destination environment and unpack it. packNGo Function Limitations The following limitations apply to use of the packNGo function: • The function operates on source files, such as *.c, *.cpp, and *.h files, only. The function does not support compile flags, defines, or makefiles. • Unnecessary files might be included. The function might find additional files from source and include paths recorded in the model’s build information and include them, even if they are not used. How Executable Programs Are Built From Models • “Build Process Steps” on page 15-39 • “Customized Makefile Generation” on page 15-39 15-38 Program Builds • “Executable Program Generation” on page 15-40 Build Process Steps The Simulink Coder software generates C code only or generates the C code and produces an executable image, depending on the level of processing you choose. By default, a Build button appears on the Code Generation pane of the Configuration Parameters dialog box. This button completes the entire build process and an executable image results. If you select the Generate code only check box to the left of the button, the button label changes to Generate code. When you click the Build or Generate code button, the Simulink Coder software performs the following build process. If the software detects code generation constraints for your model, it issues warning or error messages. 1 “Model Compilation” on page 10-31 2 “Code Generation” on page 10-31 3 “Customized Makefile Generation” on page 15-39 4 “Executable Program Generation” on page 15-40 For more information, see “Generate a Code Generation Report” on page 11-5. You can also view an HTML report in Model Explorer. Customized Makefile Generation After generating the code, the Simulink Coder software generates a customized makefile, model.mk. The generated makefile instructs the make system utility to compile and link source code generated from the model, as well as any required harness program, libraries, or user-provided modules. The Simulink Coder software creates model.mk from a system template file, system.tmf (where system stands for the selected target name). The system template makefile is designed for your target environment. You have the option of modifying the template makefile to specify compilers, compiler options, and additional information used during the creation of the executable. 15-39 15 Program Building, Interaction, and Debugging The Simulink Coder software creates the model.mk file by copying the contents of system.tmf and expanding lexical tokens (symbolic names) that describe your model’s configuration. The Simulink Coder software provides many system template makefiles, configured for specific target environments and development systems. “Selecting a Target” on page 9-34 in the Simulink Coder documentation lists all template makefiles that are bundled with the Simulink Coder software. To see an example template makefile, navigate to matlabroot/rtw/c/grt, and open with an editor the file grt_msvc.tmf. You can fully customize your build process by modifying an existing template makefile or providing your own template makefile. Executable Program Generation The following figure shows how the Simulink Coder software controls automatic program building. 15-40 Program Builds Click Build Button Simulink Model Generate Code Template Makefile Generate Makefile Create Executable? model.c model.h model_private.h Custom Makefile model.mk No Yes Invoke make Stop During the final stage of processing, the Simulink Coder build process invokes the generated makefile, model.mk, which in turn compiles and links the generated code. On PC platforms, a batch file is created to invoke the generated makefile. The batch file sets up the environment for invoking the make utility and related compiler tools. To avoid recompilation of C files, the make utility performs date checking on the dependencies between the object and C files; only out-of-date source files are compiled. Optionally, the makefile can download the resulting executable image to your target hardware. 15-41 15 Program Building, Interaction, and Debugging This stage is optional, as illustrated by the control logic in the preceding figure. You might choose to omit this stage, for example, if you are targeting an embedded microcontroller or a digital signal processing (DSP) board. To omit this stage of processing, select the Generate code only check box on the Code Generation pane of the Configuration Parameters dialog box. You can then cross-compile your code and download it to your target hardware. If you select Create code generation report on the Code Generation > Report pane, a navigable summary of source files is produced when the model is built. The report files occupy a folder called html within the build folder. The report contents vary depending on the target, but all reports feature links to generated source files. The following display shows an example of an HTML code generation report for a generic real-time (GRT) target. 15-42 Build and Run a Program Build and Run a Program The Simulink Coder build process generates C code from the model, and then compiles and links the generated program to create an executable image. To build and run the program, 1 With the sldemo_f14 model open, go to the Model Explorer window. In the Code Generation pane, click the Build button to start the build process. A number of messages concerning code generation and compilation appear in the MATLAB Command Window. The initial message is ### Starting build procedure for model: sldemo_f14 The contents of many of the succeeding messages depends on your compiler and operating system. The final message is ### Successful completion of build procedure for model: sldemo_f14 The working folder now contains an executable, sldemo_f14.exe (Microsoft Windows platforms) or sldemo_f14 (UNIX platforms). In addition, the Simulink Coder build process has created a project folder, slprj, and a build folder, sldemo_f14_grt_rtw, in your working folder. Note The Simulink Coder build process displays a code generation report after generating the code for the sldemo_f14 model. The example “Optimizing Generated Code” on page 18-2 provides more information about how to create and use a code generation report. 2 To observe the contents of the working folder after the build, type the dir command from the MATLAB Command Window. dir . .. sldemo_f14.exe sldemo_f14.slx sldemo_f14_grt_rtw slprj 3 To run the executable from the Command Window, type 15-43 15 Program Building, Interaction, and Debugging !sldemo_f14 The ! character passes the command that follows it to the operating system, which runs the stand-alone sldemo_f14 program. The program produces one line of output in the Command Window: **starting the model** No data is output. 4 Finally, to see the files created in the build folder, type dir sldemo_f14_grt_rtw The exact list of files produced varies among MATLAB platforms and versions. Here is a sample list from a Windows platform. . .. buildInfo.mat defines.txt sldemo_f14.bat sldemo_f14.c sldemo_f14.h sldemo_f14.mk sldemo_f14.obj sldemo_f14_private.h sldemo_f14_ref.rsp sldemo_f14_types.h 15-44 grt_main.obj html modelsources.txt ode5.obj rtGetInf.c rtGetInf.h rtGetInf.obj rtGetNaN.c rtGetNaN.h rtGetNaN.obj rt_logging.obj rt_nonfinite.c rt_nonfinite.h rt_nonfinite.obj rt_rand.c rt_rand.h rt_rand.obj rt_sim.obj rtmodel.h rtw_proj.tmw rtwtypes.h rtwtypeschksum.mat Profile Code Performance Profile Code Performance In this section... “About Profiling Code Performance” on page 15-45 “How to Profile Code Performance” on page 15-45 “Run Profiling Hooks for Generated Code” on page 15-48 “Profiling Limitation” on page 15-49 About Profiling Code Performance By profiling the performance of generated code, you can help verify that the code meets performance requirements. Profiling can be especially important early in the development cycle for identifying potential architectural issues that can be more expensive to address later in the process. Profiling can also identify bottlenecks and procedural issues that indicate a need for optimization, for example, with an inner loop or inline code. Note If you have an Embedded Coder license, see “Code Execution Profiling” for an alternative and simpler approach based on software-in-the-loop (SIL) or processor-in-the-loop (PIL) simulations. How to Profile Code Performance You can profile code generated with code generation technology by using a Target Language Compiler (TLC) hook function interface. To use the profile hook function interface: 1 For your target, create a TLC file that defines the following hook functions. Write the functions so that they specify profiling code. The code generator adds the hook function code to code generated for atomic systems in the model. 15-45 15 15-46 Program Building, Interaction, and Debugging Function Input Arguments Output Type Description ProfilerHeaders void Array of header file names Return an array of the header file names to be included in the generated code. ProfilerTypedefs void typedefs Generate code statements for profiler type definitions. ProfilerGlobalData system Global data for the specified system Generate code statements that declare global data. ProfilerExternDataDecls system extern declarations for the specified system Generate code statements that create global extern declarations. ProfilerSystemDecls system, functionType Declarations for the specified system for the specified functionType Generate code for required variable declarations within the scope of an atomic subsystem Output, Update, OutputUpdate, or Derivatives function. ProfilerSystemStart system, functionType Profiler start commands for the specified system and functionType Generate code that starts the profiler within the scope of an atomic subsystem Output, Update, OutputUpdate, or Derivatives function. Profile Code Performance Function Input Arguments Output Type Description ProfilerSystemFinish system, functionType Profiler end commands for the specified system and functionType Generate code that stops the profiler within the scope of an atomic subsystem’s Output, Update, OutputUpdate, or Derivatives function. ProfilerSystemTerminate system Profiler termination code for the specified Generate code that terminates profiling (and possibly reports results) for an atomic subsystem. system For an example TLC file, see matlabroot/toolbox/rtw/rtwdemos/rtwdemo_profile_hook.tlc. 2 In your target.tlc file, define the following global variables. Define... To Be... ProfileGenCode TLC_TRUE or 1 to turn on profiling (TLC_FALSE or 0 to turn off profiling) ProfilerTLC The name of the TLC file that you created in step 1 A quick way to define global variables is to define the parameters with the -a option. You can do this in the Configuration Parameters dialog box, in Code Generation > TLC options. 3 Consider setting configuration parameters for generating a code generation report. You can then examine the profiling code in the context of the code generated for the model. 15-47 15 Program Building, Interaction, and Debugging 4 Build the model. The build process embeds the profiling code in the hook function locations in the generated code for the model. 5 Run the generated executable file. In the MATLAB Command Window, enter !model-name . You see the profiling report you programmed in the profiling TLC file that you created. For example, a profile report might list the number of calls made to each system in a model and the number of CPU cycles spent in each system. For an example, see “Run Profiling Hooks for Generated Code” on page 15-48. For details on programming a .tlc file and defining TLC configuration variables, see “Target Language Compiler”. Run Profiling Hooks for Generated Code The example Profiling Hooks for Generated Code shows how to use special hooks provided by Simulink Coder to add profiling code snippets to the generated code for your models. The basis for this example is the Target Language Compiler (TLC) hook function interface described in “How to Profile Code Performance” on page 15-45. The hooks allow you to add profiling code snippets within nonvirtual (atomic) systems in the model, which allow you to profile those atomic systems. For this example, the file matlabroot/toolbox/rtw/rtwdemos/rtwdemo_profile_hook.tlc implements the required profiling functions. You can inspect this file for more information on each of the profiling functions. Run the example as follows: 1 Open the model rtwdemo_profile; for example, you can enter the command rtwdemo_profile in the MATLAB Command Window. 2 Change your working folder to one for which you have write permission. 3 Double-click one of the Generate Code blocks. This configures the selected code generation target options with the profiling hooks and builds the model. When the build process is completed, a window opens with a display of the generated code. Browse through the code to see the profile-specific C code that has been generated. 15-48 Profile Code Performance 4 Enter !rtwdemo_profile in the MATLAB Command Window to run the generated executable file. This command displays a textual report of the number of calls made to each system in the example model and the number of CPU cycles that were spent in each system. Profiling Limitation The TLC hook function interface for profiling code performance does not support the S-function target (rtwsfcn.tlc). 15-49 15 Program Building, Interaction, and Debugging Data Exchange In this section... “Host/Target Communication” on page 15-50 “Logging” on page 15-105 “Parameter Tuning” on page 15-119 “Data Interchange Using the C API” on page 15-137 “ASAP2 Data Measurement and Calibration” on page 15-174 “Direct Memory Access to Generated Code” on page 15-189 Host/Target Communication • “About Host/Target Communication” on page 15-50 • “Set Up an External Mode Communication Channel” on page 15-51 • “Use the External Mode User Interface” on page 15-63 • “External Mode Compatible Blocks and Subsystems” on page 15-83 • “External Mode Communication” on page 15-86 • “Choose Communication Protocol for Client and Server” on page 15-89 • “Use External Mode Programmatically” on page 15-98 • “External Mode Limitations” on page 15-103 About Host/Target Communication External mode allows two separate systems, a host and a target, to communicate. The host is the computer where the MATLAB and Simulink environments execute. The target is the computer where the executable created by the code generation and build process runs. The host (the Simulink environment) transmits messages requesting the target to accept parameter changes or to upload signal data. The target responds by executing the request. External mode communication is based 15-50 Data Exchange on a client/server architecture, in which the Simulink environment is the client and the target is the server. External mode lets you • Modify, or tune, block parameters in real time. In External mode, whenever you change parameters in the block diagram, the Simulink engine downloads them to the executing target program. This lets you tune your program’s parameters without recompiling. • View and log block outputs in many types of blocks and subsystems. You can monitor and/or store signal data from the executing target program, without writing special interface code. You can define the conditions under which data is uploaded from target to host. For example, data uploading could be triggered by a selected signal crossing zero in a positive direction. Alternatively, you can manually trigger data uploading. External mode works by establishing a communication channel between the Simulink engine and generated code. The channel’s low-level transport layer handles the physical transmission of messages. The Simulink engine and the generated model code are independent of this layer. The transport layer and the code directly interfacing to it are isolated in separate modules that format, transmit, and receive messages and data packets. This design allows for different targets to use different transport layers. ERT, GRT, GRT malloc, and RSim targets support External mode host/target communication by using TCP/IP and RS-232 (serial) communication. The xPC Target product uses a customized transport layer. The Wind River Systems Tornado target supports TCP/IP only. The Real-Time Windows Target product uses shared memory. Set Up an External Mode Communication Channel • “About Setting Up External Mode Communication Channels” on page 15-52 • “Set Up the Model” on page 15-52 • “Build the Target Executable” on page 15-54 • “Run the External Mode Target Program” on page 15-58 • “Tune Parameters” on page 15-62 15-51 15 Program Building, Interaction, and Debugging About Setting Up External Mode Communication Channels. This section provides step-by-step instructions for getting started with External mode, a very useful environment for rapid prototyping. The example consists of four parts, each of which depends on completion of the preceding ones, in order. The four parts correspond to the steps that you follow in simulating, building, and tuning an actual real-time application: 1 Set up the model. 2 Build the target executable. 3 Run the External mode target program. 4 Tune parameters. The example presented uses the GRT target, and does not require hardware other than the computer on which you run the Simulink and Simulink Coder software. The generated executable in this example runs on the host computer in a separate process from MATLAB and Simulink. The procedures for building, running, and testing your programs are almost identical in UNIX and PC environments. The discussion notes differences where applicable. Set Up the Model. In this part of the example, you create a simple model, extmode_example, and a folder called ext_mode_example to store the model and the generated executable: 1 Create the folder from the MATLAB command line by typing mkdir ext_mode_example 2 Make ext_mode_example your working folder: cd ext_mode_example 15-52 Data Exchange 3 Create a model in Simulink with a Sine Wave block for the input signal, two Gain blocks in parallel, and two Scope blocks. The model is shown below. Be sure to label the Gain and Scope blocks as shown, so that subsequent steps will be clear to you. 4 Define and assign two variables A and B in the MATLAB workspace as follows: A = 2; B = 3; 5 Open Gain block A and set its Gain parameter to the variable A. 6 Similarly, open Gain block B and set its Gain parameter to the variable B. 15-53 15 Program Building, Interaction, and Debugging When the target program is built and connected to Simulink in External mode, you can download new gain values to the executing target program by assigning new values to workspace variables A and B, or by editing the values in the block parameters dialog. You explore this in “Tune Parameters” on page 15-62. 7 Verify operation of the model. Open the Scope blocks and run the model. When A = 2 and B = 3, the output looks like this. 8 From the File menu, choose Save As. Save the model as extmode_example. Build the Target Executable. In this section, you set up the model and code generation parameters required for an External mode compatible target program. Then you generate code and build the target executable: 1 Open Model Explorer by selecting Model Explorer from the model’s View menu. 2 In the Model Hierarchy pane, click the + sign preceding the model name to reveal its components. 3 Click Configuration (Active) in the left pane. 4 Select Solver in the center pane. The Solver pane appears at the right. 15-54 Data Exchange 5 In the Solver options subpane: a Select Fixed-step in the Type field. b Select discrete (no continuous states) in the Solver field. c Specify 0.1 in the Fixed-step size field. (Otherwise, the Simulink Coder build process posts a warning and supplies a value when you generate code.) 6 Click Apply. The Solver options subpane appears below. Note that after you click Apply, the controls you changed again have a white background color. 7 Click Data Import/Export in the center pane, and clear the Time and Output check boxes. In this example, data is not logged to the workspace or to a MAT-file. Click Apply. 8 Click Optimization in the center pane and click the Signals and Parameters tab in the right pane. Make sure that the Inline parameters option is not selected. Although External mode supports inlined parameters, you will not explore them in this example. Click Apply if you have made any changes. 9 Click Code Generation in the center pane. By default, the generic real-time (GRT) target is selected on the Code Generation pane. Select the Interface tab. The Interface pane appears at the right. 10 On the Interface pane, select External mode from the Interface pull-down menu in the Data exchange section. This enables generation of External mode support code and reveals two more sections of controls: Host/Target interface and Memory management. 15-55 15 Program Building, Interaction, and Debugging 11 In the Host/Target interface section, make sure that the value tcpip is selected for the Transport layer parameter. The Data exchange section now looks like this: External mode supports communication via TCP/IP, serial, and custom transport protocols. The MEX-file name field specifies the name of a MEX-file that implements host and target communications on the host side. The default for TCP/IP is ext_comm, a MEX-file provided with the Simulink Coder software. You can override this default by supplying other files. See “Create a Transport Layer for External Communication” on page 23-14 in the Simulink Coder documentation for details if you need to support other transport layers. The MEX-file arguments field lets you specify arguments, such as a TCP/IP server port number, to be passed to the external interface program. Note that these arguments are specific to the external interface you are using. For information on setting these arguments, see MEX-File Optional Arguments for TCP/IP Transport on page 92 and MEX-File Optional Arguments for Serial Transport on page 94 in the Simulink Coder documentation. This example uses the default arguments. Leave the MEX-file arguments field blank. 12 Click Apply to save the Interface settings. 13 Save the model. 15-56 Data Exchange 14 Click Code Generation in the center pane of the Model Explorer. On the right, make sure that Generate code only is cleared, then click the Build button to generate code and create the target program. The content of subsequent messages depends on your compiler and operating system. The final message is ### Successful completion of build procedure for model: extmode_example In the next section, you will run the extmode_example executable and use Simulink as an interactive front end to the running target program. 15-57 15 Program Building, Interaction, and Debugging Run the External Mode Target Program. The target executable, extmode_example, is now in your working folder. In this section, you run the target program and establish communication between Simulink and the target. Note An external-mode program like extmode_example is a host-based executable. Its execution is not tied to RTOS or a periodic timer interrupt, and it does not run in real time. The program just runs as fast as possible, and the time units it counts off are simulated time units that do not correspond to time in the world outside the program. The External Signal & Triggering dialog box (accessed via the External Mode Control Panel) displays a list of all the blocks in your model that support External mode signal monitoring and logging. The dialog box also lets you configure the signals that are viewed and how they are acquired and displayed. You can use it to reconfigure signals while the target program runs. In this example, you observe and use the default settings of the External Signal & Triggering dialog box. 15-58 Data Exchange 1 From the Code menu of the model diagram, select External Mode Control Panel, which lets you configure signal monitoring and data archiving. It also lets you connect to the target program and start and stop execution of the model code. The top three buttons are for use after the target program has started. The two lower buttons open separate dialog boxes: • The Signal & triggering button opens the External Signal & Triggering dialog box. This dialog box lets you select the signals that are collected from the target system and viewed in External mode. It also lets you select a signal that triggers uploading of data when certain signal conditions are met, and define the triggering conditions. • The Data archiving button opens the External Data Archiving dialog box. Data archiving lets you save data sets generated by the target program for future analysis. This example does not use data archiving. See “Data Archiving” on page 15-79 in the Simulink Coder documentation for more information. 15-59 15 Program Building, Interaction, and Debugging 2 In the External Mode Control Panel, click the Signal & Triggering button. The External Signal & Triggering dialog box opens. The default configuration of the External Signal & Triggering dialog box is designed to select all signals for monitoring. The default configuration sets signal monitoring to begin as soon as the host and target programs have connected. The figure below shows the default configuration for extmode_example. 15-60 Data Exchange 3 Make sure that the External Signal & Triggering dialog box is set to the defaults as shown: • Select all check box is selected. All signals in the Signal selection list are marked with an X in the Block column. • Trigger Source: manual • Trigger Mode: normal • Duration: 1000 • Delay: 0 • Arm when connecting to target: selected Click Close, and then close the External Mode Control Panel. For information on the options mentioned above, see “External Signal Uploading and Triggering” on page 15-75 in the Simulink Coder documentation. 4 To run the target program, you must open a command prompt window (on UNIX systems, an Xterm window). At the command prompt, change to the ext_mode_example folder that you created in step 1. The target program is in this folder. cd ext_mode_example Next, type the following command: extmode_example -tf inf -w and press Return. Note On Microsoft Windows platforms, you can also use the “bang” command (!) in the MATLAB Command Window (note that the trailing ampersand is required): !extmode_example -tf inf -w & 15-61 15 Program Building, Interaction, and Debugging The target program begins execution. Note that the target program is in a wait state, so no activity occurs in the MATLAB Command Window. The -tf switch overrides the stop time set for the model in Simulink. The inf value directs the model to run indefinitely. The model code runs until the target program receives a stop message from Simulink. The -w switch instructs the target program to enter a wait state until it receives a Start Real-Time Code message from the host. This switch is required if you want to view data from time step 0 of the target program execution, or if you want to modify parameters before the target program begins execution of model code. 5 Open Scope blocks A and B. At this point, no signals are visible on the scopes. When you connect Simulink to the target program and begin model execution, the signals generated by the target program will be visible on the scope displays. 6 The model itself must be in External mode before communication between the model and the target program can begin. To enable External mode, select External from the Simulation > Mode menu. 7 Reopen the External Mode Control Panel (found in the Code menu) and click Connect. This initiates a handshake between Simulink and the target program. When Simulink and the target are connected, the Start Real-Time Code button becomes enabled, and the label of the Connect button changes to Disconnect. 8 Click the Start Real-Time Code button. The outputs of Gain blocks A and B are displayed on the two scopes in your model. Having established communication between Simulink and the running target program, you can tune block parameters in Simulink and observe the effects the parameter changes have on the target program. You do this in the next section. Tune Parameters. You can change the gain factor of either Gain block by assigning a new value to the variable A or B in the MATLAB workspace. When you change block parameter values in the workspace during a simulation, you must explicitly update the block diagram with these changes. When the block diagram is updated, the new values are downloaded to the target program. 15-62 Data Exchange To tune the variables A and B, 1 In the MATLAB Command Window, assign new values to both variables, for example: A = 0.5;B = 3.5; 2 Activate the extmode_example model window. Select Update Diagram from the Simulation menu, or press Ctrl+D. As soon as Simulink has updated the block parameters, the new gain values are downloaded to the target program, and the effect of the gain change becomes visible on the scopes. 3 You can also enter gain values directly into the Gain blocks. To do this, open the Block Parameters dialog box for Gain block A or B in the model. Enter a new numerical value for the gain and click Apply. As soon as you click Apply, the new value is downloaded to the target program and the effect of the gain change becomes visible on the scope. Similarly, you can change the frequency, amplitude, or phase of the sine wave signal by opening the Block Parameters dialog box for the Sine Wave block and entering a new numerical value.. Note You cannot change the sample time of the Sine Wave block. Block sample times are part of the structural definition of the model and are part of the generated code. Therefore, if you want to change a block sample time, you must stop the External mode simulation, reset the block’s sample time, and rebuild the executable. 4 To simultaneously disconnect host/target communication and end execution of the target program, pull down the Simulation menu and select Stop Real-Time Code. You can also do this from the External Mode Control Panel. Use the External Mode User Interface • “External Mode Interface Options” on page 15-64 • “External Mode Related Menu and Toolbar Items” on page 15-66 15-63 15 Program Building, Interaction, and Debugging • “External Mode Control Panel” on page 15-70 • “Target Interfacing” on page 15-73 • “External Signal Uploading and Triggering” on page 15-75 • “Data Archiving” on page 15-79 • “Parameter Downloading” on page 15-82 External Mode Interface Options. The ERT, GRT, GRT malloc, RSim, and Wind River Systems Tornado targets and the Real-Time Windows Target product support External mode. All targets that support it feature a set of External mode options on their respective target pane of the Configuration Parameters dialog box. This pane is normally named Interface). The next figure is the Data exchange section from the Interface pane of the GRT target dialog box, and is discussed below. Note The xPC Target product also uses External mode communications. External mode in the xPC Target product is always on, and has no interface options. The Data exchange section at the bottom of the Interface pane includes the following elements: • Interface menu: Selects which of three mutually exclusive data interfaces to include in the generated code. Options are 15-64 Data Exchange - None C API External mode ASAP2 This chapter discusses only the External mode option. For information on other options, see “Specifying Target Interfaces” on page 9-58. Once you select External mode from the Interface menu, the following options appear beneath: • Transport layer menu: Identifies messaging protocol for host/target communications; choices are tcpip and serial. The default is tcpip. When you select a protocol, the MEX-file name that implements the protocol is shown to the right of the menu. • MEX-file arguments text field: Optionally enter a list of arguments to be passed to the transport layer MEX-file for communicating with executing targets; these will vary according to the protocol you use. For more information on the transport options, see “Target Interfacing” on page 15-73 and “Choose Communication Protocol for Client and Server” on page 15-89. You can add other transport protocols yourself by following instructions given in “Create a Transport Layer for External Communication” on page 23-14. • Static memory allocation check box: Controls how memory for External mode communication buffers in the target is allocated. When you select this option, the following one appears beneath it: • Static memory buffer size text field: Number of bytes to preallocate for External mode communications buffers in the target when Static memory allocation is used. Note Selecting External mode from the Interface menu does not cause the Simulink model to operate in External mode (see “External Mode Related Menu and Toolbar Items” on page 15-66, below). Its function is to instrument the code generated for the target to support External mode. 15-65 15 Program Building, Interaction, and Debugging The Static memory allocation check box (for GRT and ERT targets) directs the Simulink Coder software to generate code for External mode that uses only static memory allocation (“malloc-free” code). When selected, it activates the Static memory buffer size edit field, in which you specify the size of the static memory buffer used by External mode. The default value is 1,000,000 bytes. Should you enter too small a value for your application, External mode issues an out-of-memory error when it tries to allocate more memory than you allowed. In such cases, increase the value in the Static memory buffer size field and regenerate the code. Notes • To determine how much memory you need to allocate, enable verbose mode on the target (by including OPTS="-DVERBOSE" on the make command line). As it executes, External mode displays the amount of memory it tries to allocate and the amount of memory available to it each time it attempts an allocation. Should an allocation fail, this console log can be used to adjust the size entered in the Static memory buffer size field. • When you create an ERT target, External mode can generate pure integer code. Select this feature by clearing the Support floating-point numbers option on the Interface pane of the Configuration Parameters dialog box or Model Explorer. Clearing this option makes the code, including External mode support code, free of doubles and floats. For more details, see “Code Generation Pane: Interface”. External Mode Related Menu and Toolbar Items. To communicate with a target program, the model must be operating in External mode. To enable External mode, select External from the Simulation > Mode menu. 15-66 Data Exchange Simulation Mode Menu Options and Target Connection Control (Host Disconnected from Target) Once External mode is enabled, you can connect to and control the target program by doing any of the following: • Select Connect To Target from the Simulation menu. • Click the Connect To Target toolbar button. • Use the Ctrl+T keyboard shortcut. Note When External mode is selected in the model window, the Ctrl+T keyboard shortcut is remapped from a toggle for Start and Stop (simulation) to a toggle for Connect To Target and Disconnect From Target. Selecting External mode in the model window controls execution only, and does not cause the Simulink Coder software to generate code for External mode. To do this, you must select External mode from the Interface menu 15-67 15 Program Building, Interaction, and Debugging on the Interface tab of the Configuration Parameters dialog box, as described in “External Mode Interface Options” on page 15-64. Note You can enable External mode, and simultaneously connect to the target system, by using the External Mode Control Panel dialog box. See “External Mode Control Panel” on page 15-70. Simulation Menu When a Simulink model is in External mode, the upper section of the Simulation menu contains External mode options. Initially, the Simulink model is disconnected from the target program, and the menu displays the options shown in the next figure. Simulation Menu External Mode Options (Host Disconnected from Target) The Connect To Target option establishes communication with the target program. When a connection is established, the target program might be executing model code, or it might be awaiting a command from the host to start executing model code. You can also accomplish this by clicking the Connect To Target toolbar button, as shown in Simulation Mode Menu Options and Target Connection Control (Host Disconnected from Target) on page 15-67. If the target program is executing model code, the Simulation menu contents change, as shown in the next figure. 15-68 Data Exchange Simulation Menu External Mode Options (Target Executing Model Code) The Disconnect From Target option disconnects the Simulink model from the target program, which continues to run. The Stop Real-Time Code option terminates execution of the target program and disconnects the Simulink model from the target system. If the target program is in a wait state, the Start Real-Time Code option is enabled, as shown in the next figure. The Start Real-Time Code option instructs the target program to begin executing the model code. Simulation Menu External Mode Options (Target Awaiting Start Command) Toolbar Controls The Simulink toolbar controls, shown in Simulation Mode Menu Options and Target Connection Control (Host Disconnected from Target) on page 15-67, let you control the same External mode functions as the Simulation menu. The Simulink model editor displays External mode buttons to the left of the Simulation mode menu. Initially, the toolbar displays a Connect To Target 15-69 15 Program Building, Interaction, and Debugging button and a disabled Start Real-Time Code button. Click the Connect To Target button to connect the Simulink engine to the target program. When a connection is established, the target program might be executing model code, or it might be awaiting a command from the host to start executing model code. If the target program is executing model code, the toolbar displays a Stop Real-Time Code button and a Disconnect From Target button (shown in ). Click the Stop Real-Time Code button to command the target program to stop executing model code and disconnect the Simulink engine from the target system. Click the Disconnect From Target button to disconnect the Simulink engine from the target program while leaving the target program running. If the target program is in a wait state, the toolbar displays a Start Real-Time Code button and a Disconnect From Target button. Click the Start Real-Time Code button to instruct the target program to start executing model code. Click the Disconnect From Target button to disconnect the Simulink engine from the target program. External Mode Control Panel. The External Mode Control Panel, illustrated in the next figure, provides centralized control of all External mode features, including • Host/target connection, disconnection, and target program start/stop functions, and enabling of External mode • Arming and disarming the data upload trigger • External mode communications configuration • Uploading data to Floating Scopes • Timing of parameter downloads • Selection of signals from the target program to be viewed and monitored on the host • Configuration of data archiving features Select External Mode Control Panel from the Code menu on the Simulink model editor to open the External Mode Control Panel dialog box. 15-70 Data Exchange Control the connection between host and manual arming of data uploading trigger Control timing of parameter downloads Control use of floating scopes in external mode Open dialog boxes that configure external mode target interface, signal properties, and data archiving The following sections describe the features supported by the External Mode Control Panel. Connecting, Starting, and Stopping The External Mode Control Panel performs the same connect/disconnect and start/stop functions found in the Simulation menu and the Simulink toolbar (see “External Mode Related Menu and Toolbar Items” on page 15-66). 15-71 15 Program Building, Interaction, and Debugging The Connect/Disconnect button connects to or disconnects from the target program. The button text changes in accordance with the state of the connection. If External mode is not enabled at the time the Connect button is clicked, the External Mode Control Panel enables External mode automatically. The Start/Stop Real-Time Code button commands the target to start or terminate model code execution. The button is disabled until a connection to the target is established. The button text changes in accordance with the state of the target program. Floating Scope Options The Floating scope pane of the External Mode Control Panel controls when and for how long data is uploaded to Floating Scope blocks. When used under External mode, Floating Scopes • Do not appear in the signal and triggering GUI • Support manual triggering only The behavior of wired scopes is not restricted in these ways. The Floating scope pane contains a check box and an edit field: • Enable data uploading check box, which functions as an Arm trigger button for floating scopes. When the target is disconnected it controls whether or not to arm when connecting the floating scopes. When already connected it acts as a toggle button to arm/cancel the trigger. • Duration edit field, which specifies the duration for floating scopes. By default, it is set to auto, which causes whatever value is specified in the signal and triggering GUI (which by default is 1000 base rate steps) to be used. 15-72 Data Exchange Target Interfacing. The Simulink Coder product lets you implement client and server transport for External mode using either TCP/IP or serial protocols. You can use the socket-based External mode implementation provided by the Simulink Coder product with the generated code, provided that your target system supports TCP/IP. Otherwise, use or customize the serial transport layer option provided. A low-level transport layer handles physical transmission of messages. Both the Simulink engine and the model code are independent of this layer. Both the transport layer and code directly interfacing to the transport layer are isolated in separate modules that format, transmit, and receive messages and data packets. You specify the transport mechanism using the Transport layer menu in the Host/Target interface subpane of the Interface pane of the Configuration Parameters dialog box, shown below. External interface MEX-file being used (specified in extmode_transports.m or sl_customization.m) Type optional arguments to the external interface MEX-file here. This file must be in the current directory or one that is on your MATLAB path. The Host/Target interface subpane also displays MEX-file name, the name of a MEX-file that implements host/target communications for the selected External mode transport layer. This is known as the external interface MEX-file. The default is ext_comm, the TCP/IP-based external 15-73 15 Program Building, Interaction, and Debugging interface file provided for use with the GRT, GRT malloc, ERT, RSim, and Tornado targets. If you select the serial transport option, the MEX-file name ext_serial_win32_com is displayed in this location. Note Custom or third-party targets can use a custom transport layer and a different external interface MEX-file. For more information on creating a custom transport layer, see “Create a Transport Layer for External Communication” on page 23-14. For more information on specifying a TCP/IP or serial transport layer for a custom target, see “Using the TCP/IP Implementation” on page 15-90 or “Using the Serial Implementation” on page 15-93. The MEX-file arguments edit field lets you optionally specify arguments that are passed to the External mode interface MEX-file for communicating with executing targets. The meaning of the MEX-file arguments depends on the MEX-file implementation. For TCP/IP interfaces, ext_comm allows three optional arguments: • Network name of your target (for example, 'myPuter' or '148.27.151.12') • Verbosity level (0 for no information or 1 for detailed information) • TCP/IP server port number (an integer value between 256 and 65535, with a default of 17725) For serial transport, ext_serial_win32_comm allows three optional arguments: • Verbosity level (0 for no information or 1 for detailed information) • Serial port ID (for example, 1 for COM1, and so on) • Baud rate (selected from the set 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, with a default baud rate of 57600) See “Choose Communication Protocol for Client and Server” on page 15-89 for details on MEX-file transport architecture and arguments. 15-74 Data Exchange External Signal Uploading and Triggering. Clicking the Signal & Triggering button of the External Mode Control Panel activates the External Signal & Triggering dialog box, as shown in the next figure. The External Signal & Triggering dialog box displays a list of all blocks and subsystems in your model that support External mode signal uploading. See “External Mode Compatible Blocks and Subsystems” on page 15-83 for information on which types of blocks are External mode compatible. The External Signal & Triggering dialog box lets you select the signals that are collected from the target system and viewed in External mode. It also lets you select a signal that triggers uploading of data when certain signal conditions are met, and define the triggering conditions. Default Operation The preceding figure shows the default settings of the External Signal & Triggering dialog box. The default operation of the External Signal & Triggering dialog box is designed to simplify monitoring the target program. 15-75 15 Program Building, Interaction, and Debugging If you use the default settings, you do not need to preconfigure signals and triggers. Simply start the target program and connect the Simulink engine to it. All External mode compatible blocks will be selected and the trigger will be armed. Signal uploading begins immediately upon connection to the target program. The default configuration is • Arm when connecting to target: on • Trigger Mode: normal • Trigger Source: manual • Select all: on Signal Selection All External mode compatible blocks in your model appear in the Signal selection list of the External Signal & Triggering dialog box. You use this list to select signals to be viewed. An X appears to the left of each selected block’s name. The Select all check box selects all signals. By default, Select all is on. If Select all is off, you can select or deselect individual signals using the on and off radio buttons. To select a signal, click the desired list entry and click the on radio button. To deselect a signal, click the desired list entry and click the off radio button. Alternatively, you can double-click a signal in the list to toggle between selection and deselection. The Clear all button deselects all signals. Trigger Options The Trigger panel located at the bottom left of the External Signal & Triggering dialog contains options that control when and how signal data is collected (uploaded) from the target system. These options are 15-76 Data Exchange • Source: manual or signal. Selecting manual directs External mode to start logging data when the Arm trigger button on the External Mode Control Panel is clicked. Selecting signal tells External mode to start logging data when a selected trigger signal satisfies trigger conditions specified in the Trigger signal panel. When the trigger conditions are satisfied (that is, the signal crosses the trigger level in the specified direction) a trigger event occurs. If the trigger is armed, External mode monitors for the occurrence of a trigger event. When a trigger event occurs, data logging begins. • Arm when connecting to target: If this option is selected, External mode arms the trigger automatically when the Simulink engine connects to the target. If the trigger source is manual, uploading begins immediately. If the trigger mode is signal, monitoring of the trigger signal begins immediately, and uploading begins upon the occurrence of a trigger event. If Arm when connecting to target is not selected, you must manually arm the trigger by clicking the Arm trigger button in the External Mode Control Panel. • Duration: The number of base rate steps for which External mode logs data after a trigger event (default is 1000). For example, if the fastest rate in the model is 1 second: - If a signal sampled at 1 Hz is logged for 10 base rate steps, External mode will collect 10 samples. - If a signal sampled at 2 Hz is logged for 10 base rate steps, External mode will collect 20 samples. • Mode: normal or one-shot. In normal mode, External mode automatically rearms the trigger after each trigger event. In one-shot mode, External mode collects only one buffer of data each time you arm the trigger. See “Data Archiving” on page 15-79 for more details on the effect of the Mode setting. • Delay: The delay represents the amount of time that elapses between a trigger occurrence and the start of data collection. The delay is expressed in base rate steps, and can be positive or negative (default is 0). A negative delay corresponds to pretriggering. When the delay is negative, data from the time preceding the trigger is collected and uploaded. 15-77 15 Program Building, Interaction, and Debugging Trigger Signal Selection You can designate one signal as a trigger signal. To select a trigger signal, select signal from the Trigger Source menu. This activates the Trigger signal panel (see the next figure). Then, click the desired entry in the Signal selection list and click the Trigger signal button. When a signal is selected as a trigger, a T appears to the left of the block’s name in the Signal selection list. In the next figure, the Scope A signal is the trigger. Scope B is also selected for viewing, as indicated by the X to the left of the block name. Trigger signal panel External Signal & Triggering Window with Trigger Selected After selecting the trigger signal, you can define the trigger conditions and set the Port and Element fields in the Trigger signal panel. 15-78 Data Exchange Setting Trigger Conditions Note The Trigger signal panel and the Port and Element fields of the External Signal & Triggering dialog box are enabled only when trigger Source is set to signal. By default, any element of the first input port of the specified trigger block can cause the trigger to fire (that is, Port 1, any element). You can modify this behavior by adjusting the Port and Element fields located on the right side of the Trigger signal panel. The Port field accepts a number or the keyword last. The Element field accepts a number or the keywords any and last. The Trigger Signal panel defines the conditions under which a trigger event will occur. • Level: Specifies a threshold value. The trigger signal must cross this value in a designated direction to fire the trigger. By default, the level is 0. • Direction: rising, falling, or either. This specifies the direction in which the signal must be traveling when it crosses the threshold value. The default is rising. • Hold-off: Applies only to normal mode. Expressed in base rate steps, Hold-off is the time between the termination of one trigger event and the rearming of the trigger. Data Archiving. In External mode, you can use the Simulink Scope and To Workspace blocks to archive data to disk. Clicking the Data Archiving button of the External Mode Control Panel opens the External Data Archiving dialog box, which supports the following features. Folder Notes Use this option to add annotations that pertain to a collection of related data files in a folder. Clicking the Edit directory note button opens the MATLAB editor. Place comments that you want saved to a file in the specified folder in this window. By default, the comments are saved to the folder last written to by data archiving. 15-79 15 Program Building, Interaction, and Debugging File Notes Clicking Edit file note opens a file finder window that is, by default, set to the last file to which you have written. Selecting any MAT-file opens an edit window. Add or edit comments in this window that you want saved with your individual MAT-file. Automated Data Archiving Clicking the Enable Archiving check box activates the automated data archiving features of External mode. To understand how the archiving features work, consider the handling of data when archiving is not enabled. There are two cases, one-shot and normal mode. In one-shot mode, after a trigger event occurs, each selected block writes its data to the workspace just as it would at the end of a simulation. If another one-shot is triggered, the existing workspace data is overwritten. In normal mode, External mode automatically rearms the trigger after each trigger event. Consequently, you can think of normal mode as a series of one-shots. Each one-shot in this series, except for the last, is referred to as an intermediate result. Since the trigger can fire at any time, writing intermediate results to the workspace generally results in unpredictable overwriting of the workspace variables. For this reason, the default behavior is to write only the results from the final one-shot to the workspace. The intermediate results are discarded. If you know that enough time exists between triggers for inspection of the intermediate results, then you can override the default behavior by checking the Write intermediate results to workspace check box. This option does not protect the workspace data from being overwritten by subsequent triggers. The options in the External Data Archiving dialog box support automatic writing of logging results, including intermediate results, to disk. Data archiving provides the following settings: • Directory: Specifies the folder in which data is saved. External mode appends a suffix if you select Increment directory when trigger armed. 15-80 Data Exchange • File: Specifies the filename in which data is saved. External mode appends a suffix if you select Increment file after one-shot. • Increment directory when trigger armed: External mode uses a different folder for writing log files each time that you click the Arm trigger button. The folders are named incrementally, for example, dirname1, dirname2, and so on. • Increment file after one-shot: New data buffers are saved in incremental files: filename1, filename2, and so on. This happens automatically in normal mode. • Append file suffix to variable names: Whenever External mode increments filenames, each file contains variables with identical names. Selecting Append file suffix to variable name results in each file containing unique variable names. For example, External mode will save a variable named xdata in incremental files (file_1, file_2, and so on) as xdata_1, xdata_2, and so on. This is useful if you want to load the MAT-files into the workspace and compare variables at the MATLAB command prompt. Without the unique names, each instance of xdata would overwrite the previous one in the MATLAB workspace. • Write intermediate results to workspace: Select this option if you want the Simulink Coder software to write all intermediate results to the workspace. The next figure shows the External Data Archiving dialog box with archiving enabled. 15-81 15 Program Building, Interaction, and Debugging Unless you select Enable archiving, entries for the Directory and File fields are not accepted. Parameter Downloading. The Batch download check box on the External Mode Control Panel enables or disables batch parameter changes. By default, batch download is not enabled. If batch download is not enabled, changes made directly to block parameters by using parameter dialog boxes are sent to the target when you click the OK or Apply button. Changes to MATLAB workspace variables are sent when an Update diagram is performed. If batch download is enabled, the Download button is enabled. Changes made to block parameters are stored locally until you click the Download button. When you click the Download button, the changes are sent in a single transmission. When parameter changes have been made and are awaiting batch download, the External Mode Control Panel displays the message Parameter changes pending... to the right of the download button. (See the next figure.) This message disappears after the Simulink engine receives notification from the target that the new parameters have been installed in the parameter vector of the target system. The External Mode Control Panel with the batch download option activated appears in the next figure. 15-82 Data Exchange Parameter changes pending... Parameter changes pending... message appears if unsent parameter value changes are awaiting download External Mode Control Panel in Batch Download Mode External Mode Compatible Blocks and Subsystems • “Compatible Blocks” on page 15-83 • “Signal Viewing Subsystems” on page 15-84 • “Supported Blocks for Data Archiving” on page 15-86 Compatible Blocks. In External mode, you can use the following types of blocks to receive and view signals uploaded from the target program: 15-83 15 Program Building, Interaction, and Debugging • Floating Scope and Scope blocks • Spectrum Scope and Vector Scope blocks from the DSP System Toolbox product • Blocks from the Gauges Blockset product • Display blocks • To Workspace blocks • User-written S-Function blocks An External mode method is built into the S-function API. This method allows user-written blocks to support External mode. See matlabroot/simulink/simstruc.h. • XY Graph blocks In addition to these types of blocks, you can designate certain subsystems as Signal Viewing Subsystems and use them to receive and view signals uploaded from the target program. See “Signal Viewing Subsystems” on page 15-84 for more information. You select External mode compatible blocks and subsystems, and arm the trigger, by using the External Signal & Triggering dialog box. By default, all such blocks in a model are selected, and a manual trigger is set to be armed when connected to the target program. Signal Viewing Subsystems. A Signal Viewing Subsystem is an atomic subsystem that encapsulates processing and viewing of signals received from the target system. A Signal Viewing Subsystem runs only on the host, generating no code in the target system. Signal Viewing Subsystems run in all simulation modes — normal, accelerated, and external. Signal Viewing Subsystems are useful in situations where you want to process or condition signals before viewing or logging them, but you do not want to perform these tasks on the target system. By using a Signal Viewing Subsystem, you can generate smaller and more efficient code on the target system. Like other External mode compatible blocks, Signal Viewing Subsystems are displayed in the External Signal & Triggering dialog box. 15-84 Data Exchange To declare a subsystem to be a Signal Viewing Subsystem, 1 Select the Treat as atomic unit option in the Block Parameters dialog box. For more information on atomic subsystems, see “Code Generation of Subsystems” on page 2-2. 2 Use the following set_param command to turn the SimViewingDevice property on, set_param('blockname', 'SimViewingDevice','on') where 'blockname' is the name of the subsystem. 3 Make sure the subsystem meets the following requirements: • It must be a pure sink block. That is, it must contain no Outport blocks or Data Store blocks. It can contain Goto blocks only if the corresponding From blocks are contained within the subsystem boundaries. • It must have no continuous states. The following model, sink_examp, contains an atomic subsystem, theSink. The subsystem theSink, shown in the next figure, applies a gain and an offset to its input signal and displays it on a Scope block. 15-85 15 Program Building, Interaction, and Debugging If theSink is declared as a Signal Viewing Subsystem, the generated target program includes only the code for the Sine Wave block. If theSink is selected and armed in the External Signal & Triggering dialog box, the target program uploads the sine wave signal to theSink during simulation. You can then modify the parameters of the blocks within theSink and observe their effect upon the uploaded signal. If theSink were not declared as a Signal Viewing Subsystem, its Gain, Constant, and Sum blocks would run as subsystem code on the target system. The Sine Wave signal would be uploaded to the Simulink engine after being processed by these blocks, and viewed on sink_examp/theSink/Scope2. Processing demands on the target system would be increased by the additional signal processing, and by the downloading of changes in block parameters from the host. Supported Blocks for Data Archiving. In External mode, you can use the following types of blocks to archive data to disk: • Scope blocks • To Workspace blocks You configure data archiving by using the External Data Archiving dialog box, as described in “Data Archiving” on page 15-79. External Mode Communication • “About External Mode Communication” on page 15-86 • “Download Mechanism” on page 15-87 • “Inlined and Tunable Parameters” on page 15-88 About External Mode Communication. This section describes how the Simulink engine and a target program communicate, and how and when they transmit parameter updates and signal data to each other. Depending on the setting of the Inline parameters option when the target program is generated, there are differences in the way parameter updates are handled. “Download Mechanism” on page 15-87 describes the operation of External mode communications with Inline parameters off. “Inlined 15-86 Data Exchange and Tunable Parameters” on page 15-88 describes the operation of External mode with Inline parameters on. Download Mechanism. In External mode, the Simulink engine does not simulate the system represented by the block diagram. By default, when External mode is enabled, the Simulink engine downloads all parameters to the target system. After the initial download, the engine remains in a waiting mode until you change parameters in the block diagram or until the engine receives data from the target. When you change a parameter in the block diagram, the Simulink engine calls the external interface MEX-file, passing new parameter values (along with other information) as arguments. The external interface MEX-file contains code that implements one side of the interprocess communication (IPC) channel. This channel connects the Simulink process (where the MEX-file executes) to the process that is executing the external program. The MEX-file transfers the new parameter values by using this channel to the external program. The other side of the communication channel is implemented within the external program. This side writes the new parameter values into the target’s parameter structure (model_P). The Simulink side initiates the parameter download operation by sending a message containing parameter information to the external program. In the terminology of client/server computing, the Simulink side is the client and the external program is the server. The two processes can be remote, or they can be local. Where the client and server are remote, a protocol such as TCP/IP is used to transfer data. Where the client and server are local, a serial connection or shared memory can be used to transfer data. The next figure shows this relationship. The Simulink engine calls the external interface MEX-file whenever you change parameters in the block diagram. The MEX-file then downloads the parameters to the external program by using the communication channel. 15-87 15 Program Building, Interaction, and Debugging Simulink Process External Program Process mexFunction External Program Client IPC Code Server IPC Code External Interface ext_svr. MEX-file (e.g., ext_comm) Interprocess Communication Channel Transport Layer External Mode Architecture Inlined and Tunable Parameters. By default, all parameters (except those listed in “External Mode Limitations” on page 15-103) in an External mode program are tunable; that is, you can change them by using the download mechanism described in this section. If you select the Inline parameters option (on the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box), the Simulink Coder code generator embeds the numerical values of model parameters (constants), instead of symbolic parameter names, in the 15-88 Data Exchange generated code. Inlining parameters generates smaller and more efficient code. However, inlined parameters, because they effectively become constants, are not tunable. The Simulink Coder software lets you improve overall efficiency by inlining most parameters, while at the same time retaining the flexibility of run-time tuning for selected parameters that are important to your application. When you inline parameters, you can use the Model Parameter Configuration dialog box to remove individual parameters from inlining and declare them to be tunable. In addition, the Model Parameter Configuration dialog box offers you options for controlling how parameters are represented in the generated code. For more information on tunable parameters, see “Parameters” on page 7-10. Automatic Parameter Uploading on Host/Target Connection Each time the Simulink engine connects to a target program that was generated with Inline parameters on, the target program uploads the current value of its tunable parameters (if any) to the host. These values are assigned to the corresponding MATLAB workspace variables. This procedure synchronizes the host and target with respect to parameter values. All workspace variables required by the model must be initialized at the time of host/target connection. Otherwise the uploading cannot proceed and an error results. Once the connection is made, these variables are updated to reflect the current parameter values on the target system. Automatic parameter uploading takes place only if the target program was generated with Inline parameters on. “Download Mechanism” on page 15-87 describes the operation of External mode communications with Inline parameters off. Choose Communication Protocol for Client and Server • “Introduction” on page 15-90 • “Using the TCP/IP Implementation” on page 15-90 • “Using the Serial Implementation” on page 15-93 15-89 15 Program Building, Interaction, and Debugging • “Run the External Program” on page 15-95 • “Implement an External Mode Protocol Layer” on page 15-98 Introduction. The Simulink Coder product provides code to implement both the client and server side of External mode communication using either TCP/IP or serial protocols. You can use the socket-based External mode implementation provided by the Simulink Coder product with the generated code, provided that your target system supports TCP/IP. If not, use or customize the serial transport layer option provided. A low-level transport layer handles physical transmission of messages. Both the Simulink engine and the model code are independent of this layer. Both the transport layer and code directly interfacing to the transport layer are isolated in separate modules that format, transmit, and receive messages and data packets. See “Target Interfacing” on page 15-73 for information on selecting a transport layer. Using the TCP/IP Implementation. You can use TCP/IP-based client/server implementation of External mode with real-time programs on The Open Group UNIX or PC systems. For help in customizing External mode transport layers, see “Create a Transport Layer for External Communication” on page 23-14. To use Simulink External mode over TCP/IP, you must • Make sure that the external interface MEX-file for your target’s TCP/IP transport is specified. Targets provided by MathWorks specify the name of the external interface MEX-file in matlabroot/toolbox/simulink/simulink/extmode_transports.m. The name of the interface appears as uneditable text in the Host/Target interface section of the Interface pane of the Configuration Parameters dialog box. The TCP/IP default is ext_comm. To specify a TCP/IP transport for a custom target, you must add an entry of the following form to an sl_customization.m file on the MATLAB path: function sl_customization(cm) 15-90 Data Exchange cm.ExtModeTransports.add('stf.tlc', 'transport', 'mexfile', 'Level1'); %end function where - stf.tlc is the name of the system target file for which the transport will be registered (for example, 'mytarget.tlc') - transport is the transport name to display in the Transport layer - menu on the Interface pane of the Configuration Parameters dialog box (for example, 'tcpip') mexfile is the name of the transport’s associated external interface MEX-file (for example, 'ext_comm') You can specify multiple targets and/or transports with additional cm.ExtModeTransports.add lines, for example: function sl_customization(cm) cm.ExtModeTransports.add('mytarget.tlc', 'tcpip', 'ext_comm', 'Level1'); cm.ExtModeTransports.add('mytarget.tlc', 'serial', ... 'ext_serial_win32_comm', 'Level1'); %end function • Be sure that the template makefile is configured to link the source files for the TCP/IP server code and that it defines the compiler flags when building the generated code. • Build the external program. • Run the external program. • Set the Simulink model to External mode and connect to the target. The next figure shows the structure of the TCP/IP-based implementation. 15-91 15 Program Building, Interaction, and Debugging Target UNIX or PC Host Simulink in External Mode Target Code Process block parameter changes ext_svr.c Update block parameters ext_comm TCP/IP on Ethernet External Mode Message Format header data in target format TCP/IP-Based Client/Server Implementation for External Mode MEX-File Optional Arguments for TCP/IP Transport In the External Target Interface dialog box, you can specify optional arguments that are passed to the External mode interface MEX-file for communicating with executing targets. • Target network name: the network name of the computer running the external program. By default, this is the computer on which the Simulink product is running. The name can be 15-92 String delimited by single quotes, such as 'myPuter' Data Exchange - IP address delimited by single quotes, such as '148.27.151.12' • Verbosity level: controls the level of detail of the information displayed during the data transfer. The value is either 0 or 1 and has the following meaning: 0 — No information 1 — Detailed information • TCP/IP server port number: The default value is 17725. You can change the port number to a value between 256 and 65535 to avoid a port conflict. The arguments are positional and must be specified in order. For example, if you want to specify the verbosity level (the second argument), then you must also specify the target network name (the first argument). Arguments can be delimited by white space or commas. For example: '148.27.151.12' 1 30000 You can specify command-line options to the external program when you launch it. See “Run the External Program” on page 15-95 for more information. Using the Serial Implementation. Controlling host/target communications on a serial channel is similar to controlling host/target communications on a TCP/IP channel. To use Simulink External mode over a serial channel, you must • Execute the target and host on a Microsoft Windows platform. • Make sure that the external interface MEX-file for your target’s serial transport is specified. Targets provided by MathWorks specify the name of the external interface MEX-file in matlabroot/toolbox/simulink/simulink/extmode_transports.m. The name of the interface appears as uneditable text in the Host/Target interface section of the Interface pane of the Configuration Parameters dialog box. The serial default is serial. To specify a serial transport for a custom target, you must add an entry of the following form to an sl_customization.m file on the MATLAB path: 15-93 15 Program Building, Interaction, and Debugging function sl_customization(cm) cm.ExtModeTransports.add('stf.tlc', 'transport', 'mexfile', 'Level1'); %end function where - stf.tlc is the name of the system target file for which the transport will be registered (for example, 'mytarget.tlc') - transport is the transport name to display in the Transport layer - menu on the Interface pane of the Configuration Parameters dialog box (for example, 'serial') mexfile is the name of the transport’s associated external interface MEX-file (for example, 'ext_serial_win32_comm') You can specify multiple targets and/or transports with additional cm.ExtModeTransports.add lines, for example: function sl_customization(cm) cm.ExtModeTransports.add('mytarget.tlc', 'tcpip', 'ext_comm', 'Level1'); cm.ExtModeTransports.add('mytarget.tlc', 'serial', ... 'ext_serial_win32_comm', 'Level1'); %end function • Be sure that the template makefile is configured to link the source files for the serial server code and that it defines the compiler flags when building the generated code. • Build the external program. • Run the external program. • Set the Simulink model to External mode and connect to the target. MEX-File Optional Arguments for Serial Transport In the MEX-file arguments field of the Interface pane of the Configuration Parameters dialog box, you can specify arguments that are passed to the External mode interface MEX-file for communicating with the executing targets. For serial transport, the optional arguments to ext_serial_win32_comm are 15-94 Data Exchange • Verbosity level: controls the level of detail of the information displayed during the data transfer. The value is either 0 or 1 and has the following meaning: 0 — No information 1 — Detailed information • Serial port ID (for example, 1 for COM1, and so on) If the target program is executing on the same machine as the host and communications is through a loopback serial cable, the target’s port ID must differ from that of the host (as specified in the MEX-file arguments edit field). When you start the target program using a serial connection, you must specify the port ID to use to connect it to the host. Do this by including the -port command-line option. For example, mytarget.exe -port 2 -w • Baud rate (selected from the set 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, with a default baud rate of 57600) The arguments are positional and must be specified in order. For example, if you want to specify the serial port ID (the second argument), then you must also specify the verbosity level (the first argument). Arguments can be delimited by white space or commas. For example: 1 1 115200 You can specify command-line options to the external program when you launch it. The following section provides details on using command-line arguments. Run the External Program. The external program must be running before you can use the Simulink product in External mode. To run the external program, you type a command of the form model -opt1 ... -optN where model is the name of the external program and -opt1 ... -optN are options. (See Command-Line Options for the External Program on page 15-95 15 Program Building, Interaction, and Debugging 97.) In the examples in this section, the name of the external program is assumed to be ext_example. Running the External Program Under the Windows Environment In the Windows environment, you can run the external programs in either of the following ways: • Open a Command Prompt window. At the command prompt, type the name of the target executable, followed by any options, as in the following example: ext_example -tf inf -w • Alternatively, you can launch the target executable from the MATLAB command prompt. In this case the command must be preceded by an exclamation point (!) and followed by an ampersand (&), as in the following example: !ext_example -tf inf -w & The ampersand (&) causes the operating system to spawn another process to run the target executable. If you do not include the ampersand, the program still runs, but you will be unable to enter commands at the MATLAB command prompt or manually terminate the executable. Running the External Program Under the UNIX Environment In the UNIX environment, you can run the external programs in either of the following ways: • Open an Xterm window. At the command prompt, type the name of the target executable, followed by any options, as in the following example: ext_example -tf inf -w • Alternatively, you can launch the target executable from the MATLAB command prompt. In the UNIX environment, if you start the external 15-96 Data Exchange program from the MATLAB command prompt, you must run it in the background so that you can still access the Simulink environment. The command must be preceded by an exclamation point (!) and followed by an ampersand (&), as in the following example: !ext_example -tf inf -w & runs the executable from the MATLAB command prompt by spawning another process to run it. Command-Line Options for the External Program External mode target executables generated by the Simulink Coder code generator support the following command-line options: • -tf n option The -tf option overrides the stop time set in the Simulink model. The argument n specifies the number of seconds the program will run. The value inf directs the model to run indefinitely. In this case, the model code will run until the target program receives a stop message from the Simulink engine. The following example sets the stop time to 10 seconds. ext_example -tf 10 When integer-only ERT targets are built and executed in External mode, the stop time parameter (-tf) is interpreted by the target as the number of base rate ticks rather than the number of seconds to execute. Note The -tf option works with GRT, GRT malloc, ERT, RSim, and Tornado targets. If you are creating a custom target and want to support the -tf option, you must implement the option yourself. See “Create a Transport Layer for External Communication” on page 23-14 for more information. • -w option: Instructs the target program to enter a wait state until it receives a message from the host. At this point, the target is running, but 15-97 15 Program Building, Interaction, and Debugging not executing the model code. The start message is sent when you select Start Real-Time Code from the Simulation menu or click the Start Real-Time Code button in the External Mode Control Panel. Use the -w option if you want to view data from time step 0 of the target program execution, or if you want to modify parameters before the target program begins execution of model code. • -port n option: Specifies the TCP/IP port number, n, for the target program. The port number of the target program must match that of the host. The default port number is 17725. The port number must be a value between 256 and 65535. Note The -tf, -w, and -port options are supported by the TCP/IP and serial transport layer modules shipped with the Simulink Coder product (although -port is interpreted differently by each). The -baud option is serial only. By default, these modules are linked into External mode target executables. If you are implementing a custom External mode transport layer and want to support these options, you must implement them in your code. Implement an External Mode Protocol Layer. If you want to implement your own transport layer for External mode communication, you must modify certain code modules provided by the Simulink Coder product and create a new external interface MEX-file. This advanced topic is described in detail in “Create a Transport Layer for External Communication” on page 23-14. Use External Mode Programmatically You can run external-mode applications from the MATLAB command line or programmatically in scripts. Use the get_param and set_param commands to retrieve and set the values of model simulation command-line parameters, such as SimulationMode and SimulationCommand, and External mode command-line parameters, such as ExtModeCommand and ExtModeTrigType. (For more information on using get_param and set_param to tune model parameters, see “Tune Parameters” on page 7-36.) 15-98 Data Exchange The following sequence of model simulation commands assumes that a Simulink model is open and that you have loaded a target program to which the model will connect using External mode. 1 Change the Simulink model to External mode: set_param(gcs, 'SimulationMode', 'external') 2 Connect the open model to the loaded target program: set_param(gcs, 'SimulationCommand', 'connect') 3 Start running the target program: set_param(gcs, 'SimulationCommand', 'start') 4 Stop running the target program: set_param(gcs, 'SimulationCommand', 'stop') 5 Disconnect the target program from the model: set_param(gcs, 'SimulationCommand', 'disconnect') The next table lists External mode command-line parameters that you can use in get_param and set_param commands. The table provides brief descriptions, valid values (bold type highlights defaults), and a mapping to External Mode dialog box equivalents. Note For External mode parameters that are equivalent to Interface pane options in the Configuration Parameters dialog box, see the ExtMode table entries in “Parameter Command-Line Information Summary”. 15-99 15 Program Building, Interaction, and Debugging External Mode Command-Line Parameters Parameter and Values Dialog Box Equivalent Description ExtModeAddSuffixToVar off, on External Data Archiving: Append file suffix to variable names check box Increment variable names for each incremented filename. ExtModeArchiveDirName string External Data Archiving: Directory text field Save data in specified folder. ExtModeArchiveFileName string External Data Archiving: File text field Save data in specified file. ExtModeArchiveMode string - off, on External Data Archiving: Enable archiving check box Activate automated data archiving features. ExtModeArmWhenConnect off, on External Signal & Triggering: Arm when connecting to target check box Arm the trigger as soon as the Simulink Coder software connects to the target. ExtModeAutoIncOneShot off, on External Data Archiving: Increment file after one-shot check box Save new data buffers in incremental files. ExtModeAutoUpdateStatusClock Not available Continuously upload and display target time on the model window status bar. ExtModeBatchMode off, on External Mode Control Panel: Batch download check box Enable or disable downloading of parameters in batch mode. ExtModeChangesPending off, on Not available When ExtModeBatchMode is enabled, indicates whether any parameters remain in the queue of parameters to be downloaded to the target. ExtModeCommand string Not available Issue an External mode command to the target program. (Microsoft Windows platforms only) off, on 15-100 Data Exchange External Mode Command-Line Parameters (Continued) Parameter and Values Dialog Box Equivalent Description ExtModeConnected off, on External Mode Control Panel: Connect/Disconnect button Indicate the state of the connection with the target program. ExtModeEnableFloating off, on External Mode Control Panel: Enable data uploading check box Enable or disable the arming and canceling of triggers when a connection is established with floating scopes. ExtModeIncDirWhenArm off, on External Data Archiving: Increment directory when trigger armed check box Write log files to incremental folders each time the trigger is armed. ExtModeLogAll off, on External Signal & Triggering: Select all check box Upload all available signals from the target to the host. ExtModeLogCtrlPanelDlg string Not available Return a handle to the External Mode Control Panel dialog box or –1 if the dialog box does not exist. ExtModeParamChangesPending off, on Not available When the Simulink Coder software is connected to the target and ExtModeBatchMode is enabled, indicates whether any parameters remain in the queue of parameters to be downloaded to the target. More efficient than ExtModeChangesPending, because it checks for a connection to the target. 15-101 15 Program Building, Interaction, and Debugging External Mode Command-Line Parameters (Continued) Parameter and Values Dialog Box Equivalent Description ExtModeSkipDownloadWhenConnect off, on Not available Connect to the target program without downloading parameters. ExtModeTrigDelay integer (0) External Signal & Triggering: Delay text field Specify the amount of time (expressed in base rate steps) that elapses between a trigger occurrence and the start of data collection. ExtModeTrigDirection string - rising, falling, either External Signal & Triggering: Direction menu Specify the direction in which the signal must be traveling when it crosses the threshold value. ExtModeTrigDuration integer (1000) External Signal & Triggering: Duration text field Specify the number of base rate steps for which External mode is to log data after a trigger event. ExtModeTrigDurationFloating string - integer (auto) External Mode Control Panel: Duration text field Specify the duration for floating scopes. If auto is specified, the value of ExtModeTrigDuration is used. ExtModeTrigElement string - integer, any, last External Signal & Triggering: Element text field Specify the elements of the input port of the specified trigger block that can cause the trigger to fire. ExtModeTrigHoldOff integer (0) External Signal & Triggering: Hold-off text field Specify the base rate steps between when a trigger event terminates and the trigger is rearmed. ExtModeTrigLevel integer (0) External Signal & Triggering: Level text field Specify the threshold value the trigger signal must cross to fire the trigger. 15-102 Data Exchange External Mode Command-Line Parameters (Continued) Parameter and Values Dialog Box Equivalent Description ExtModeTrigMode string - normal, oneshot External Signal & Triggering: Mode menu Specify whether the trigger is to rearm automatically after each trigger event or whether only one buffer of data is to be collected each time the trigger is armed. ExtModeTrigPort string - integer (1), last External Signal & Triggering: Port text field Specify the input port of the specified trigger block for which elements can cause the trigger to fire. ExtModeTrigType string - manual, signal External Signal & Triggering: Source menu Specify whether to start logging data when the trigger is armed or when a specified trigger signal satisfies trigger conditions. ExtModeUploadStatus string - inactive, armed, uploading Not available Return the status of the External mode upload mechanism — inactive, armed, or uploading. ExtModeWriteAllDataToWs off, on External Data Archiving: Write intermediate results to workspace check box Write all intermediate results to the workspace. External Mode Limitations • “Limitation on Changing Parameters” on page 15-104 • “Limitation on Mixing 32-bit and 64-bit Architectures” on page 15-105 • “Limitation on Uploading Data” on page 15-105 • “Limitation on Uploading Variable-Size Signals” on page 15-105 • “Limitation on Archiving Data” on page 15-105 15-103 15 Program Building, Interaction, and Debugging • “Limitation on Scopes in Referenced Models” on page 15-105 Limitation on Changing Parameters. In general, you cannot change a parameter if doing so results in a change in the structure of the model. For example, you cannot change • The number of states, inputs, or outputs of any block • The sample time or the number of sample times • The integration algorithm for continuous systems • The name of the model or of any block • The parameters to the Fcn block If you cause any of these changes to the block diagram, then you must rebuild the program with newly generated code. However, you can change parameters in transfer function and state space representation blocks in specific ways: • The parameters (numerator and denominator polynomials) for the Transfer Fcn (continuous and discrete) and Discrete Filter blocks can be changed (as long as the number of states does not change). • Zero entries in the State-Space and Zero Pole (both continuous and discrete) blocks in the user-specified or computed parameters (that is, the A, B, C, and D matrices obtained by a zero-pole to state-space transformation) cannot be changed once external simulation is started. • In the State-Space block, if you specify the matrices in the controllable canonical realization, then all changes to the A, B, C, D matrices that preserve this realization and the dimensions of the matrices are allowed. If the Simulink block diagram does not match the external program, the Simulink engine displays an error informing you that the checksums do not match (that is, the model has changed since you generated code). This means that you must rebuild the program from the new block diagram (or reload another one) to use External mode. If the external program is not running, the Simulink engine displays an error informing you that it cannot connect to the external program. 15-104 Data Exchange Limitation on Mixing 32-bit and 64-bit Architectures. When you use External mode, the machine running the Simulink product and the machine running the target executable must have matching bit architectures, either 32-bit or 64-bit. This is because the Simulink Coder software varies a model’s checksum based on whether it is configured for a 32-bit or 64-bit platform. If you attempt to connect from a 32-bit machine to a 64-bit machine or vice versa, the External mode connection fails. Limitation on Uploading Data. External mode does not support uploading data values for fixed-point or enumerated types into workspace parameters. Limitation on Uploading Variable-Size Signals. External mode does not support uploading variable-size signals for the following targets: • xPC Target • Texas Instruments C2000™ Limitation on Archiving Data. External mode supports the Scope and To Workspace blocks for archiving data to disk. However, External mode does not support scopes other than the Scope block for archiving data. For example, you cannot use Floating Scope blocks or Signal and Scope Manager viewer objects to archive data in External mode. Limitation on Scopes in Referenced Models. In a model hierarchy, if the top model simulates in External mode and a referenced model simulates in Normal or Accelerator mode, scopes in the referenced model do not display. However, if the top model is changed to simulate in Normal mode, the behavior of scopes in the referenced models differs between Normal and Accelerator mode. Scopes in a referenced model simulating in Normal mode display, while scopes in a referenced model simulating in Accelerator mode do not display. Logging • “Log Data for Analysis” on page 15-106 • “About Logging to MAT-Files” on page 15-115 • “Configure State, Time, and Output Logging” on page 15-116 15-105 15 Program Building, Interaction, and Debugging • “Log Data with Scope and To Workspace Blocks” on page 15-117 • “Log Data with To File Blocks” on page 15-118 • “Data Logging Differences Between Single- and Multitasking” on page 15-118 Log Data for Analysis • “About Logging Data” on page 15-106 • “Data Logging During Simulation” on page 15-107 • “Data Logging from Generated Code” on page 15-111 About Logging Data. Simulink Coder MAT-file data logging facility enables a generated program to save system states, outputs, and simulation time at each model execution time step. The data is written to a MAT-file, named (by default) model.mat, where model is the name of your model. In this example, data generated by the model rtwdemo_f14 is logged to the file rtwdemo_f14.mat. Refer to “Build a Generic Real-Time Program” on page 15-14 for instructions on setting up rtwdemo_f14 in a working folder if you have not done so already. To configure data logging, click Data Import/Export in the center pane of the Model Explorer. The process is the same as configuring a Simulink model to save output to the MATLAB workspace. For each workspace return variable you define and enable, the Simulink Coder software defines a parallel MAT-file variable. For example, if you save simulation time to the variable tout, your generated program logs the same data to a variable named rt_tout. You can change the prefix rt_ to a suffix (_rt), or eliminate it entirely. You do this by selecting Code Generation in the center pane of the Model Explorer, then clicking the Interface tab. 15-106 Data Exchange Note Simulink lets you log signal data from anywhere in a model via the Log signal data option in the Signal Properties dialog box (accessed via context menu by right-clicking signal lines). The Simulink Coder software does not use this method of signal logging in generated code. To log signals in generated code, you must either use the Data Import/Export options described below or include To File or To Workspace blocks in your model. In this example, you modify the rtwdemo_f14 model so that the generated program saves the simulation time and system outputs to the file rtwdemo_f14.mat. Then you load the data into the MATLAB workspace and plot simulation time against one of the outputs. The rtwdemo_f14 model should be open and configured as described in “Build a Generic Real-Time Program” on page 15-14. Data Logging During Simulation. To use the data logging feature: 1 Open Model Explorer by selecting Model Explorer from the model’s View menu. 2 In the Model Hierarchy pane, click the + sign preceding the model name to reveal its components. 3 Click Configuration (Active) in the left pane. 4 Click Data Import/Export in the center pane. The Data Import/Export pane, which appears at the right, lets you specify which outport data is to be saved to the workspace and what variable names to use for it. 5 Select the Time option. This tells Simulink to save time step data during simulation as a variable named tout. You can enter a different name to distinguish different simulation runs (for example using different step sizes), but take the default for this example. Selecting Time enables the Simulink Coder code generator to create code that logs the simulation time to a MAT-file. 6 Select the Output option. This tells Simulink to save output signal data during simulation as a variable named yout. Selecting Output enables the Simulink Coder code generator to create code that logs the root Output blocks (Angle of Attack and Pilot G Force) to a MAT-file. 15-107 15 Program Building, Interaction, and Debugging Note The sort order of the yout array is based on the port number of the Outport blocks, starting with 1. Angle of Attack and Pilot G Force are logged to yout(:,1) and yout(:,2), respectively. 15-108 Data Exchange 7 If any other options are enabled, clear them. Set Decimation to 1 and Format to Array. The figure below shows the dialog. 15-109 15 Program Building, Interaction, and Debugging 8 Click Apply to register your changes. 9 Save the model. 10 Open the Pilot G Force Scope block of the model, then run the model by choosing Simulation > Run in the model window. The resulting Pilot G Force scope display is shown below. 11 Verify that the simulation time and outputs have been saved to the MATLAB workspace in MAT-files. At the MATLAB prompt, type: whos *out Simulink displays: Name tout yout 15-110 Size 601x1 601x2 Bytes 4808 9616 Class Attributes double double Data Exchange 12 Verify that Pilot G Force was logged by plotting simulation time versus that variable. At the MATLAB prompt, type: plot(tout,yout(:,2)) The resulting plot is shown below. Data Logging from Generated Code. In the second part of this example, you build and run a Simulink Coder executable of the rtwdemo_f14 model that outputs a MAT-file containing the simulation time and outputs you previously examined. Even though you have already generated code for the rtwdemo_f14 model, you must now regenerate that code because you have changed the model by enabling data logging. The steps below explain this procedure. To avoid overwriting workspace data with data from simulation runs, the Simulink Coder code generator modifies identifiers for variables logged by Simulink. You can control these modifications from the Model Explorer: 1 Open Model Explorer by selecting Model Explorer from the model’s View menu. 2 In the Model Hierarchy pane, click the + sign preceding the model name to reveal its components. 15-111 15 Program Building, Interaction, and Debugging 3 Click Configuration (Active) in the left pane. 4 In the center pane, click Code Generation. The Code Generation pane appears to the right. 5 Click the Interface tab. 6 Set MAT-file variable name modifier to _rt. This adds the suffix _rt to each variable that you selected to be logged in the first part of this example (tout, yout). 15-112 Data Exchange 7 Clear the Generate code only check box, if it is currently selected. The pane should look like this: 8 Click Apply to register your changes. 9 Save the model. 10 To generate code and build an executable, click the Build button. 11 When the build concludes, run the executable with the command: !rtwdemo_f14 15-113 15 Program Building, Interaction, and Debugging 12 The program now produces two message lines, indicating that the MAT-file has been written. ** starting the model ** ** created rtwdemo_f14.mat ** 13 Load the MAT-file data created by the executable and look at the workspace variables from simulation and the generated program by typing: load rtwdemo_f14.mat whos tout* yout* Simulink displays: Name tout tout_rt yout yout_rt Size 601x1 601x1 601x2 601x2 Bytes 4808 4808 9616 9616 Class Attribute double double double double Note that all arrays have the same number of elements. 15-114 Data Exchange 14 Observe that the variables tout_rt (time) and yout_rt (Pilot G Force and Angle of Attack) have been loaded from the file. Plot Pilot G Force as a function of time. plot(tout_rt,yout_rt(:,2)) The resulting plot is identical to the plot you produced in step 10 of the previous part of this example: About Logging to MAT-Files Multiple techniques are available by which a program generated by the Simulink Coder software can save data to a MAT-file for analysis. See also “Log Data for Analysis” on page 15-106 for a data logging tutorial. Note Data logging is available only for targets that have access to a file system. In addition, only the RSim target executables are capable of accessing MATLAB workspace data. 15-115 15 Program Building, Interaction, and Debugging Configure State, Time, and Output Logging The Data Import/Export pane enables a generated program to save system states, outputs, and simulation time at each model execution time step. The data is written to a MAT-file, named (by default) model.mat. Before using this data logging feature, you should learn how to configure a Simulink model to return output to the MATLAB workspace. This is discussed in “Export Simulation Data”. For each workspace return variable that you define and enable, the code generator defines a MAT-file variable. For example, if your model saves simulation time to the workspace variable tout, your generated program logs the same data to a variable named (by default) rt_tout. The code generated by the code generator logs the following data: • All root Outport blocks The default MAT-file variable name for system outputs is rt_yout. The sort order of the rt_yout array is based on the port number of the Outport block, starting with 1. • All continuous and discrete states in the model The default MAT-file variable name for system states is rt_xout. • Simulation time The default MAT-file variable name for simulation time is rt_tout. • “Override the Default MAT-File Name” on page 15-116 • “Override the Default MAT-File Variable Names” on page 15-117 • “Override the Default MAT-File Buffer Size” on page 15-117 Override the Default MAT-File Name. The MAT-file name defaults to model.mat. To specify a different file name, 1 In the model window, select Simulation > Model Configuration Parameters. The dialog box opens. 2 Click Code Generation. 15-116 Data Exchange 3 Append the following option to the existing text in the Make command field: OPTS="-DSAVEFILE=filename" Override the Default MAT-File Variable Names. By default, the code generation software prefixes the string rt_ to the variable names for system outputs, states, and simulation time to form MAT-file variable names. To change this prefix, 1 In the model window, select Simulation > Model Configuration Parameters. The dialog box opens. 2 Click Code Generation. 3 Select grt.tlc for System target file. 4 Select Code Generation > Interface 5 Select a prefix (rt_) or suffix (_rt) from the MAT-file variable name modifier field, or choose none for no prefix (other targets may or may not have this option). Override the Default MAT-File Buffer Size. The size of the buffer for MAT-file data logging defaults to 1024 bytes. To specify a different buffer size, 1 In the model window, select Simulation > Model Configuration Parameters. The dialog box opens. 2 Click Code Generation. 3 Append the following option to the existing text in the Make command field: OPTS="-DDEFAULT_BUFFER_SIZE=n" where n specifies a buffer size in bytes. Log Data with Scope and To Workspace Blocks The code generated by the code generator also logs data from these sources: 15-117 15 Program Building, Interaction, and Debugging • All Scope blocks that have the Save data to workspace parameter enabled You must specify the variable name and data format in each Scope block’s dialog box. • All To Workspace blocks in the model You must specify the variable name and data format in each To Workspace block’s dialog box. The variables are written to model.mat, along with any variables logged from the Workspace I/O pane. Log Data with To File Blocks You can also log data to a To File block. The generated program creates a separate MAT-file (distinct from model.mat) for each To File block in the model. The file contains the block’s time and input variable(s). You must specify the filename, variable names, decimation, and sample time in the To File block’s dialog box. Note Models referenced by Model blocks do not perform data logging in that context except for states, which you can include in the state logged for top models. Code generated by the Simulink Coder software for referenced models does not perform data logging to MAT-files. Data Logging Differences Between Single- and Multitasking When logging data in single-tasking and multitasking systems, you will notice differences in the logging of • Noncontinuous root Outport blocks • Discrete states In multitasking mode, the logging of states and outputs is done after the first task execution (and not at the end of the first time step). In single-tasking mode, the code generated by the build procedure logs states and outputs after the first time step. 15-118 Data Exchange See Data Logging in Single-Tasking and Multitasking Model Execution for more details on the differences between single-tasking and multitasking data logging. Note The rapid simulation target (RSim) provides enhanced logging options. See “Rapid Simulations” on page 12-2 for more information. Parameter Tuning • “Tunable Parameter Storage” on page 15-119 • “Tunable Parameter Storage Classes” on page 15-121 • “Declare Tunable Parameters” on page 15-124 • “Tunable Expressions” on page 15-128 • “Linear Block Parameter Tunability” on page 15-132 • “Tunable Workspace Parameter Data Type Considerations” on page 15-133 • “Tune Parameters from the Command Line” on page 15-135 • “Interfaces for Tuning Parameters” on page 15-137 Tunable Parameter Storage A tunable parameter is a block parameter whose value can be changed at run-time. A tunable parameter is inherently noninlined. Consequently, when Inlined parameters is off, all parameters are members of model_P, and thus are tunable. A tunable expression is an expression that contains one or more tunable parameters. When you declare a parameter tunable, you control whether or not the parameter is stored within model_P. You also control the symbolic name of the parameter in the generated code. When you declare a parameter tunable, you specify • The storage class of the parameter. 15-119 15 Program Building, Interaction, and Debugging The storage class property of a parameter specifies how the Simulink Coder product declares the parameter in generated code. The term “storage class,” as used in the Simulink Coder product, is not synonymous with the term storage class specifier, as used in the C language. • A storage type qualifier, such as const or volatile. This is simply a string that is included in the variable declaration. • (Implicitly) the symbolic name of the variable or field in which the parameter is stored. The Simulink Coder product derives variable and field names from the names of tunable parameters. The Simulink Coder product generates a variable or struct storage declaration for each tunable parameter. Your choice of storage class controls whether the parameter is declared as a member of model_P or as a separate global variable. You can use the generated storage declaration to make the variable visible to external legacy code. You can also make variables declared in your code visible to the generated code. You are responsible for linking your code to generated code modules. You can use tunable parameters or expressions in your root model and in masked or unmasked subsystems, subject to certain restrictions. (See “Tunable Expressions” on page 15-128.) Override Inlined Parameters for Tuning. When the Inline parameters option is selected, you can use the Model Parameter Configuration dialog box to remove individual parameters from inlining and declare them to be tunable. This allows you to improve overall efficiency by inlining most parameters, while at the same time retaining the flexibility of run-time tuning for selected parameters. Another way you can achieve the same result is by using Simulink data objects; see “Parameters” on page 7-10 for specific details. The mechanics of declaring tunable parameters are discussed in “Declare Tunable Parameters” on page 15-124. 15-120 Data Exchange Tunable Parameter Storage Classes The Simulink Coder product defines four storage classes for tunable parameters. You must declare a tunable parameter to have one of the following storage classes: • SimulinkGlobal (Auto): This is the default storage class. The Simulink Coder product stores the parameter as a member of model_P. Each member of model_P is initialized to the value of the corresponding workspace variable at code generation time. • ExportedGlobal: The generated code instantiates and initializes the parameter and model.h exports it as a global variable. An exported global variable is independent of the model_P data structure. Each exported global variable is initialized to the value of the corresponding workspace variable at code generation time. • ImportedExtern: model_private.h declares the parameter as an extern variable. Your code must supply the variable definition and initializer. • ImportedExternPointer: model_private.h declares the variable as an extern pointer. Your code must supply the pointer variable definition and initializer, if any. The generated code for model.h includes model_private.h to make the extern declarations available to subsystem files. As an example of how the storage class declaration affects the code generated for a parameter, consider the next figure. 15-121 15 Program Building, Interaction, and Debugging The workspace variable Kp sets the gain of the Gain1 block. Assume that the value of Kp is 3.14. The following table shows the variable declarations and the code generated for the gain block when Kp is declared as a tunable parameter. An example is shown for each storage class. Note The Simulink Coder product uses column-major ordering for two-dimensional signal and parameter data. When interfacing your hand-written code to such signals or parameters by using ExportedGlobal, ImportedExtern, or ImportedExternPointer declarations, make sure that your code observes this ordering convention. The symbolic name Kp is preserved in the variable and field names in the generated code. 15-122 Data Exchange Storage Class SimulinkGlobal (Auto) Generated Variable Declaration and Code typedef struct _Parameters_tunable_sin Parameters_tunable_sin; struct _Parameters_tunable_sin { real_T Kp; }; Parameters_tunable_sin tunable_sin_P = { 3.14 }; . . tunable_sin_Y.Out1 = rtb_u * tunable_sin_P.Kp; ExportedGlobal real_T Kp = 3.14; . . tunable_sin_Y.Out1 = rtb_u * Kp; ImportedExtern extern real_T Kp; . . tunable_sin_Y.Out1 = rtb_u * Kp; ImportedExtern Pointer extern real_T *Kp; . . tunable_sin_Y.Out1 = rtb_u * (*Kp); 15-123 15 Program Building, Interaction, and Debugging Declare Tunable Parameters • “Declare Workspace Variables as Tunable Parameters” on page 15-124 • “Declare New Tunable Parameters” on page 15-124 • “Declare Tunable Parameters Using Configuration Parameter Dialog” on page 15-125 • “Select Workspace Variables” on page 15-126 • “Create New Tunable Parameters” on page 15-127 • “Set Tunable Parameter Properties” on page 15-128 • “Remove Unused Tunable Parameters” on page 15-128 Declare Workspace Variables as Tunable Parameters. To declare tunable parameters, 1 Open the Model Parameter Configuration dialog box. 2 In the Source list pane, select one or more variables. 3 Click Add to table . The variables then appear as tunable parameters in the Global (tunable) parameters pane. 4 Select a parameter in the Global (tunable) parameters pane. 5 Select a storage class from the Storage class menu. 6 Optionally, select (or enter) a storage type qualifier, such as const or volatile for the parameter. 7 Click Apply, or click OK to apply changes and close the dialog box. Declare New Tunable Parameters. To declare tunable parameters, 1 Open the Model Parameter Configuration dialog box. 2 In the Global (tunable) parameters pane, click New. 3 Specify a name for the parameter. 15-124 Data Exchange 4 Select a storage class from the Storage class menu. 5 Optionally, select (or enter) a storage type qualifier, such as const or volatile for the parameter. 6 Click Apply, or click OK to apply changes and close the dialog box. Declare Tunable Parameters Using Configuration Parameter Dialog. The Model Parameter Configuration dialog box lets you select base workspace variables and declare them to be tunable parameters in the current model. Using controls in the dialog box, you move variables from a source list to a global (tunable) parameter list for a model. To open the dialog box, 1 Select the Inline parameters check box on the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box. This activates a Configure button, as shown below. 2 Click Configure to open the Model Configuration Parameter dialog box. 15-125 15 Program Building, Interaction, and Debugging Note The Model Configuration Parameter dialog box cannot tune parameters within referenced models. See “Parameterize Model References” for tuning techniques that work with referenced models. Select Workspace Variables. The Source list pane displays a menu and a scrolling table of numerical workspace variables. To select workspace variables, 1 From the menu, select the source of variables you want listed. 15-126 To List... Choose... All variables in the MATLAB workspace that have numeric values MATLAB workspace Only variables in the MATLAB workspace that have numeric values and are referenced by the model Referenced workspace variables Data Exchange A list of workspace variables appear in the Source List pane. 2 Select one or more variables from the source list. This enables the Add to table button. 3 Click Add to table to add the selected variables to the tunable parameters list in the Global (tunable) parameters pane. In the Source list, the names of variables added to the tunable parameters list are displayed in bold type (see the preceding figure). Note If you selected a variable with a name that matches a block parameter that is not tunable and you click Add to table , a warning appears during simulation and code generation. To update the list of variables to reflect the current state of the workspace, at any time, click Refresh list . For example, you might use Refresh list if you define or remove variables in the workspace while the Model Parameter Configuration dialog box is open. Create New Tunable Parameters. To create a new tunable parameter, 1 In the Global (tunable) parameters pane, click New. 2 In the Name field, enter a name for the parameter. If you enter a name that matches the name of a workspace variable in the Source list pane, that variable is declared tunable and appears in italics in the Source list. 3 Click Apply. The model does not need to be using a parameter before you create it. You can add references to the parameter later. Note If you edit the name of an existing variable in the list, you actually create a new tunable variable with the new name. The previous variable is removed from the list and loses its tunability (that is, it is inlined). 15-127 15 Program Building, Interaction, and Debugging Set Tunable Parameter Properties. To set the properties of tunable parameters listed in the Global (tunable) parameters pane, select a parameter and then specify a storage class and, optionally, a storage type qualifier. Property Description Storage class Select one of the following to be used for code generation: • SimulinkGlobal (Auto) • ExportedGlobal • ImportedExtern • ImportedExternPointer See “Tunable Parameter Storage Classes” on page 15-121 for definitions. Storage type qualifier For variables with any storage class except SimulinkGlobal (Auto), you can add a qualifier (such as const or volatile) to the generated storage declaration. To do so, you can select a predefined qualifier from the list or add qualifiers not in the list. The code generator does not check the storage type qualifier for validity, and includes the qualifier string in the generated code without checking syntax . Remove Unused Tunable Parameters. To remove unused tunable parameters from the table in the Global (tunable) parameters pane, click Remove. All removed variables are inlined if the Inlined parameters option is enabled. Tunable Expressions • “Tunable Expressions in Masked Subsystems” on page 15-129 • “Tunable Expression Limitations” on page 15-131 15-128 Data Exchange The Simulink Coder product supports the use of tunable variables in expressions. An expression that contains one or more tunable parameters is called a tunable expression. Tunable Expressions in Masked Subsystems. Tunable expressions are allowed in masked subsystems. You can use tunable parameter names or tunable expressions in a masked subsystem dialog box. When referenced in lower-level subsystems, such parameters remain tunable. As an example, consider the masked subsystem in the next figure. The masked variable k sets the gain parameter of theGain. Suppose that the base workspace variable b is declared tunable with SimulinkGlobal (Auto) storage class. The next figure shows the tunable expression b*3 in the subsystem’s mask dialog box. Tunable Expression in Subsystem Mask Dialog Box The Simulink Coder product produces the following output computation for theGain. The variable b is represented as a member of the global parameters structure, model_P. (For clarity in showing the individual Gain block computation, expression folding is off in this example.) /* Gain: ' /theGain' */ 15-129 15 Program Building, Interaction, and Debugging rtb_theGain_C = rtb_SineWave_n * ((subsys_mask_P.b * 3.0)); /* Outport: ' /Out1' */ subsys_mask_Y.Out1 = rtb_theGain_C; As this example shows, for GRT targets, the parameter structure is mangled to create the structure identifier model_P (subject to the identifier length constraint). This is done to avoid namespace clashes in combining code from multiple models using model reference. ERT-based targets provide ways to customize identifier names. When expression folding is on, the above code condenses to /* Outport: ' /Out1' incorporates: * Gain: ' /theGain' */ subsys_mask_Y.Out1 = rtb_SineWave_n * ((subsys_mask_P.b * 3.0)); Expressions that include variables that were declared or modified in mask initialization code are not tunable. As an example, consider the subsystem above, modified as follows: • The mask initialization code is t = 3 * k; • The parameter k of the myGain block is 4 + t. • Workspace variable b = 2. The expression b * 3 is plugged into the mask dialog box as in the preceding figure. Since the mask initialization code can run only once, k is evaluated at code generation time as 4 + (3 * (2 * 3) ) The Simulink Coder product inlines the result. Therefore, despite the fact that b was declared tunable, the code generator produces the following output computation for theGain. (For clarity in showing the individual Gain block computation, expression folding is off in this example.) 15-130 Data Exchange /* Gain Block: /theGain */ rtb_temp0 *= (22.0); Tunable Expression Limitations. Currently, there are certain limitations on the use of tunable variables in expressions. When an unsupported expression is encountered during code generation a warning is issued and the equivalent numeric value is generated in the code. The limitations on tunable expressions are • Complex expressions are not supported, except where the expression is simply the name of a complex variable. • The use of certain operators or functions in expressions containing tunable operands is restricted. Restrictions are applied to four categories of operators or functions, classified in the following table: Category Operators or Functions 1 + - .* ./ < > <= >= == ~= & | 2 * / 3 abs, acos, asin, atan, atan2, boolean, ceil, cos, cosh, exp, floor, log, log10, sign, sin, sinh, sqrt, tan, tanh, 4 single, int8, int16, int32, uint8, uint16, uint32 5 : .^ ^ [] {} . \ .\ ' .' ; , The rules applying to each category are as follows: - Category 1 is unrestricted. These operators can be used in tunable expressions with any combination of scalar or vector operands. - Category 2 operators can be used in tunable expressions where at least one operand is a scalar. That is, scalar/scalar and scalar/matrix operand combinations are supported, but not matrix/matrix. - Category 3 lists all functions that support tunable arguments. Tunable arguments passed to these functions retain their tunability. Tunable arguments passed to any other functions lose their tunability. - Category 4 lists the casting functions that do not support tunable arguments. Tunable arguments passed to these functions lose their tunability. 15-131 15 Program Building, Interaction, and Debugging Note The Simulink Coder product casts values using MATLAB typecasting rules. The MATLAB typecasting rules are different from C code typecasting rules. For example, using the MATLAB typecasting rules, int8(3.7) returns the result 4, while in C code int8(3.7) returns the result 3. See “Data Type Conversion” for more information on MATLAB typecasting. - Category 5 operators are not supported. • Expressions that include variables that were declared or modified in mask initialization code are not tunable. • The Fcn block does not support tunable expressions in code generation. • Model workspace parameters can take on only the Auto storage class, and thus are not tunable. See “Parameterize Model References” for tuning techniques that work with referenced models. • Non-double expressions are not supported. • Blocks that access parameters only by address support the use of tunable parameters, if the parameter expression is a simple variable reference. When an operation such as a data type conversion or a math operation is applied, the Simulink Coder product creates a nontrivial expression that cannot be accessed by address, resulting in an error during the build process. Linear Block Parameter Tunability The following blocks have a Realization parameter that affects the tunability of their parameters: • Transfer Fcn • State-Space • Discrete State-Space The Realization parameter must be set by using the MATLAB set_param function, as in the following example. set_param(gcb,'Realization','auto') 15-132 Data Exchange The following values are defined for the Realization parameter: • general: The block’s parameters are preserved in the generated code, permitting parameters to be tuned. • sparse: The block’s parameters are represented in the code by transformed values that increase the computational efficiency. Because of the transformation, the block’s parameters are no longer tunable. • auto: This setting is the default. A general realization is used if one or more of the block’s parameters are tunable. Otherwise sparse is used. Note To tune the parameter values of a block of one of the above types without restriction during an External mode simulation, you must set Realization to general. Code Reuse for Subsystems with Mask Parameters. The Simulink Coder product can generate reusable (reentrant) code for a model containing identical atomic subsystems. Selecting the Reusable function option for Function packaging enables such code reuse, and causes a single function with arguments to be generated that is called when any of the identical atomic subsystem executes. See “Subsystems” for details and restrictions on the use of this option. Mask parameters become arguments to reusable functions. However, for reuse to occur, each instance of a reusable subsystem must declare the same set of mask parameters. If, for example subsystem A has mask parameters b and K, and subsystem B has mask parameters c and K, then code reuse is not possible, and the Simulink Coder product will generate separate functions for A and B. Tunable Workspace Parameter Data Type Considerations If you are using tunable workspace parameters, you need to be aware of potential issues regarding data types. A workspace parameter is tunable when the following conditions exist: • You select the Inline parameters option on the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box 15-133 15 Program Building, Interaction, and Debugging • The parameter has a storage class other than Auto When generating code for tunable workspace parameters, the Simulink Coder product checks and compares the data types used for a particular parameter in the workspace and in Block Parameter dialog boxes. If... The Simulink Coder Product... The data types match Uses that data type for the parameter in the generated code. You do not explicitly specify a data type other than double in the workspace Uses the data type specified by the block in the generated code. If multiple blocks share a parameter, they must all specify the same data type. If the data type varies between blocks, the product generates an error similar to the following: Variable 'K' is used in incompatible ways in the dialog fields of the following: cs_params/Gain, cs_params/Gain1. The variable'value is being used both directly and after a transformation. Only one of these usages is permitted for any given variable. You explicitly specify a data type other than double in the workspace Uses the data type from the workspace for the parameter. The block typecasts the parameter to the block specific data type before using it. Guidelines for Specifying Data Types. The following table provides guidelines on specifying data types for tunable workspace parameters. 15-134 If You Want to... Then Specify Data Types in... Minimize memory usage (int8 instead of single) The workspace explicitly Avoid typecasting Blocks only Data Exchange If You Want to... Then Specify Data Types in... Interface to legacy or custom code The workspace explicitly Use the same parameter for multiple blocks that specify different data types The workspace explicitly The Simulink Coder product enforces limitations on the use of data types other than double in the workspace, as explained in “Limitations on Specifying Workspace Data Types Explicitly” on page 15-135. Limitations on Specifying Workspace Data Types Explicitly. When you explicitly specify a data type other than double in the workspace, blocks typecast the parameter to another data type. This is an issue for blocks that use pointer access for their parameters. Blocks cannot use pointer access if they need to typecast the parameter before using it (because of a data type mismatch). Another case in which this occurs is for workspace variables with bias or fractional slope. Two possible solutions to these problems are • Remove the explicit data type specification in the workspace for parameters used in such blocks. • Modify the block so that it uses the parameter with the same data type as specified in the workspace. For example, the Lookup Table block uses the data types of its input signal to determine the data type that it uses to access the X-breakpoint parameter. You can prevent the block from typecasting the run-time parameter by converting the input signal to the data type used for X-breakpoints in the workspace. (Similarly, the output signal is used to determine the data types used to access the lookup table Y data.) Tune Parameters from the Command Line When parameters are MATLAB workspace variables, the Model Parameter Configuration dialog box is the recommended way to see or set the properties of tunable parameters. In addition to that dialog box, you can also use MATLAB get_param and set_param commands. 15-135 15 Program Building, Interaction, and Debugging Note You can also use Simulink.Parameter objects for tunable parameters. See “Configure Parameter Objects for Code Generation” on page 7-39 for details. The following commands return the tunable parameters and corresponding properties: • get_param(gcs, 'TunableVars') • get_param(gcs, 'TunableVarsStorageClass') • get_param(gcs, 'TunableVarsTypeQualifier') The following commands declare tunable parameters or set corresponding properties: • set_param(gcs, 'TunableVars', str) The argument str (string) is a comma-separated list of variable names. • set_param(gcs, 'TunableVarsStorageClass', str) The argument str (string) is a comma-separated list of storage class settings. The valid storage class settings are - Auto ExportedGlobal ImportedExtern ImportedExternPointer • set_param(gcs, 'TunableVarsTypeQualifier', str) The argument str (string) is a comma-separated list of storage type qualifiers. The following example declares the variable k1 to be tunable, with storage class ExportedGlobal and type qualifier const. The number of variables and number of specified storage class settings must match. If you specify multiple variables and storage class settings, separate them with a comma. 15-136 Data Exchange set_param(gcs, 'TunableVars', 'k1') set_param(gcs, 'TunableVarsStorageClass','ExportedGlobal') set_param(gcs, 'TunableVarsTypeQualifier','const') Other configuration parameters you can get and set are listed in “Parameter Reference”. Interfaces for Tuning Parameters The Simulink Coder product includes • Support for developing a Target Language Compiler API for tuning parameters independent of External mode. See “Parameter Functions” in the Target Language Compiler documentation for information. • A C application program interface (API) for tuning parameters independent of External mode. See “Data Interchange Using the C API” on page 15-137 for information. • An interface for exporting ASAP2 files, which you customize to use parameter objects. For details, see “ASAP2 Data Measurement and Calibration” on page 15-174. Data Interchange Using the C API The C API allows you to write host-based or target-based code that interacts with signals, states, root-level inputs/outputs, and parameters in your target-based application code. • “About Data Exchange and C API” on page 15-137 • “Generate C API Files” on page 15-138 • “Description of C API Files” on page 15-141 • “Use the C API in an Application” on page 15-160 • “C API Limitations” on page 15-173 About Data Exchange and C API Some Simulink Coder applications must interact with signals, states, root-level inputs/outputs, or parameters in the generated code for a model. For example, calibration applications monitor and modify parameters. Signal 15-137 15 Program Building, Interaction, and Debugging monitoring or data logging applications interface with signal, state, and root-level input/output data. Using the Simulink Coder C API, you can build target applications that log signals, states, and root-level inputs/outputs, monitor signals, states, and root-level inputs/outputs, and tune parameters, while the generated code executes. The C API minimizes its memory footprint by sharing information common to signals, states, root-level inputs/outputs, and parameters in smaller structures. Signal, state, root-level input/output, and parameter structures include an index into the structure map, allowing multiple signals, states, root-level inputs/outputs, or parameters to share data. When you configure a model to use the C API, the Simulink Coder code generator generates two additional files, model_capi.c (or .cpp) and model_capi.h, where model is the name of the model. The code generator places the two C API files in the build folder, based on settings in the Configuration Parameters dialog box. The C API source code file contains information about global block output signals, states, root-level inputs/outputs, and global parameters defined in the generated code model source code. The C API header file is an interface header file between the model source code and the generated C API. You can use the information in these C API files to create your application. Among the files generated are those shown in the next figure. model.c model.h model.mdl Generate code Generated Files with C API Selected Generate C API Files To generate C API files for your model: 15-138 model_capi.c model_capi.h Data Exchange 1 Select the C API interface for your model. There are two ways to select the C API interface for your model, as described in the following sections. • “Select C API with Configuration Parameters Dialog” on page 15-139 • “Select C API from the Command Line” on page 15-140 2 Generate code for your model. After generating code, you can examine the files model_capi.c (or .cpp) and model_capi.h in the model build folder. Select C API with Configuration Parameters Dialog. 1 Open your model, and launch either the Configuration Parameters dialog box or Model Explorer. 2 Go to the Code Generation > Interface pane and, in the Data exchange section, select C API as the value for the Interface parameter. The Generate C API for: signals, Generate C API for: parameters, Generate C API for: states, and Generate C API for: root-level I/O check boxes are displayed. 3 Select options: • If you want to generate C API code for global block output signals, select the Generate C API for: signals check box. • If you want to generate C API code for global block parameters, select the Generate C API for: parameters check box. • If you want to generate C API code for discrete and continuous states, select the Generate C API for: states check box. • If you want to generate C API code for root-level inputs and outputs, select the Generate C API for: root-level I/O check box. 15-139 15 Program Building, Interaction, and Debugging If you select all four check boxes, support for accessing signals, parameters, states, and root-level I/O will appear in the C API generated code. Select C API from the Command Line. From the MATLAB command line, you can use the set_param function to select or clear the C API check boxes on the Interface pane of the Configuration Parameters dialog box. At the MATLAB command line, enter one or more of the following commands, where modelname is the name of your model. To select Generate C API for: signals, enter: set_param('modelname','RTWCAPISignals','on') To clear Generate C API for: signals, enter: set_param('modelname','RTWCAPISignals','off') To select Generate C API for: parameters, enter: set_param('modelname','RTWCAPIParams','on') To clear Generate C API for: parameters, enter: set_param('modelname','RTWCAPIParams','off') To select Generate C API for: states, enter: set_param('modelname','RTWCAPIStates','on') To clear Generate C API for: states, enter: set_param('modelname','RTWCAPIStates','off') To select Generate C API for: root-level I/O, enter: set_param('modelname','RTWCAPIRootIO','on') To clear Generate C API for: root-level I/O, enter: set_param('modelname','RTWCAPIRootIO','off') 15-140 Data Exchange Generate C API and ASAP2 Files. The C API and ASAP2 interfaces are not mutually exclusive. Although the Interface option on the Code Generation > Interface pane of the Configuration Parameters dialog box allows you to select either the ASAP2 or C API interface, you can instruct the Simulink Coder code generator to generate files for both interfaces. For details, see “Generate ASAP2 and C API Files” on page 15-188. Description of C API Files • “About C API Files” on page 15-141 • “Structure Arrays Generated in C API Files” on page 15-144 • “Generate Example C API Files” on page 15-146 • “C API Signals” on page 15-149 • “C API States” on page 15-153 • “C API Root-Level Inputs and Outputs” on page 15-154 • “C API Parameters” on page 15-156 • “Map C API Data Structures to rtModel” on page 15-158 About C API Files. The model_capi.c (or .cpp) file provides external applications with a consistent interface to model data. Depending on your configuration settings, the data could be a signal, state, root-level input or output, or parameter. In this document, the term data item refers to either a signal, a state, a root-level input or output, or a parameter. The C API uses structures that provide an interface to the data item properties. The interface packages the properties of each data item in a data structure. If the model contains multiple data items, the interface generates an array of data structures. The members of a data structure map to data properties. To interface with data items, an application requires the following properties for each data item: • Name • Block path • Port number (for signals and root-level inputs/outputs only) 15-141 15 Program Building, Interaction, and Debugging • Address • Data type information: native data type, data size, complexity, and other attributes • Dimensions information: number of rows, number of columns, and data orientation (scalar, vector, matrix, or n-dimensional) • Fixed-point information: slope, bias, scale type, word length, exponent, and other attributes • Sample-time information (for signals, states, and root-level inputs/outputs only): sample time, task identifier, frames As illustrated in the next figure, the properties of data item A, for example, are located in data structure DS_A. The properties of data item B are located in data structure DS_B. DS_A Property 1 Property 2 Pointer Property 3 ... DS_B Property 1 Property 2 Pointer Property 3 ... Unique value located here Shared value located in DS_C Pointer value located here Unique value located here Unique value located here Shared value located in DS_C Pointer value located here Unique value located here DS_C Shared value of Property 2 Shared values of other properties ... Some property values can be unique to each data item, and there are some property values that several data items can share in common. Name, for example, has a unique value for each data item. The interface places the unique property values directly in the structure for the data item. The name value of data item A is in DS_A, and the name value of data item B is in DS_B. But data type could be a property whose value several data items have in common. The ability of some data items to share a property allows the C API to have a reuse feature. In this case, the interface places only an index value 15-142 Data Exchange in DS_A and an index value in DS_B. These indices point to a different data structure, DS_C, that contains the actual data type value. The next figure shows this scheme with more detail. Array of Signal Structures rtwCapi_Signals rtBlockSignals[] { Array of Data Type Structures { rtwCAPI_DataTypeMap rtDataTypeMap[] ... blockPath sys/blk1 signalName signal1 portNumber 0 dataTypeIndex 0 ... }, { ... blockPath sys/blk2 signalName signal2 portNumber 1 dataTypeIndex 0 { { These indices of 0 point to the first element in the rtDataTypeMap array. { ... signalName signal3 portNumber 0 dataTypeIndex 1 ... } }; "real_T" numElements 0 elemMapIndex 0 dataSize sizeof(real_T) slDataId SS_DOUBLE isComplex 0 isPointer 0 { }, sys/blk3 "double" mwName }; ... blockPath cName cName "int" mwName "int32_T" numElements 0 elemMapIndex 0 dataSize sizeof(int32_T) slDataId SS_INT32 ... } The index of 1 points to the second element in the rtDataTypeMap array. }; 15-143 15 Program Building, Interaction, and Debugging The figure shows three signals. signal1 and signal2 share the same data type, double. Instead of specifying this data type value in each signal data structure, the interface provides only an index value, 0, in the structure. "double" is described by entry 0 in the rtDataTypeMap array, which is referenced by both signals. Additionally, property values can be shared between signals, states, root-level inputs/outputs, and parameters, so states, root-level inputs/outputs, and parameters also might reference the double entry in the rtDataTypeMap array. This reuse of information reduces the memory size of the generated interface. Structure Arrays Generated in C API Files. As with data type, the interface maps other common properties (such as address, dimension, fixed-point scaling, and sample time) into separate structures and provides an index in the structure for the data item. For a complete list of structure definitions, refer to the file matlabroot/rtw/c/src/rtw_capi.h (where matlabroot represents the root of your MATLAB installation folder). This file also describes each member in a structure. The structure arrays generated in the model_capi.c (or .cpp) file are of structure types defined in the rtw_capi.h file. Here is a brief description of the structure arrays generated in model_capi.c (or .cpp): • rtBlockSignals is an array of structures that contains information about global block output signals in the model. Each element in the array is of type struct rtwCAPI_Signals. The members of this structure provide the signal name, block path, block port number, address, and indices to the data type, dimension, fixed-point, and sample-time structure arrays. • rtBlockParameters is an array of structures that contains information about the tunable block parameters in the model by block name and parameter name. Each element in the array is of type struct rtwCAPI_BlockParameters. The members of this structure provide the parameter name, block path, address, and indices to data type, dimension, and fixed-point structure arrays. • rtBlockStates is an array of structures that contains information about discrete and continuous states in the model. Each element in the array is of type struct rtwCAPI_States. The members of this structure provide the state name, block path, type (continuous or discrete), and indices to the address, data type, dimension, fixed-point, and sample-time structure arrays. 15-144 Data Exchange • rtRootInputs is an array of structures that contains information about root-level inputs in the model. Each element in the array is of type struct rtwCAPI_Signals. The members of this structure provide the root-level input name, block path, block port number, address, and indices to the data type, dimension, fixed-point, and sample-time structure arrays. • rtRootOutputs is an array of structures that contains information about root-level outputs in the model. Each element in the array is of type struct rtwCAPI_Signals. The members of this structure provide the root-level output name, block path, block port number, address, and indices to the data type, dimension, fixed-point, and sample-time structure arrays. • rtModelParameters is an array of structures that contains information about all workplace variables that one or more blocks or Stateflow charts in the model reference as block parameters. Each element in the array is of data type rtwCAPI_ModelParameters. The members of this structure provide the variable name, address, and indices to data type, dimension, and fixed-point structure arrays. • rtDataAddrMap is an array of base addresses of signals, states, root-level inputs/outputs, and parameters that appear in the rtBlockSignals, rtBlockParameters, rtBlockStates, and rtModelParameters arrays. Each element of the rtDataAddrMap array is a pointer to void (void*). • rtDataTypeMap is an array of structures that contains information about the various data types in the model. Each element of this array is of type struct rtwCAPI_DataTypeMap. The members of this structure provide the data type name, size of the data type, and information on whether or not the data is complex. • rtDimensionMap is an array of structures that contains information about the various data dimensions in the model. Each element of this array is of type struct rtwCAPI_DimensionMap. The members of this structure provide information on the number of dimensions in the data, the orientation of the data (whether it is scalar, vector, or a matrix), and the actual dimensions of the data. • rtFixPtMap is an array of structures that contains fixed-point information about the signals, states, root-level inputs/outputs, and parameters. Each element of this array is of type struct rtwCAPI_FixPtMap. The members of this structure provide information about the data scaling, bias, exponent, and whether or not the fixed-point data is signed. If the model does not have fixed-point data (signal, state, root-level input/output, or parameter), 15-145 15 Program Building, Interaction, and Debugging the Simulink Coder software assigns NULL or zero values to the elements of the rtFixPtMap array. • rtSampleTimeMap is an array of structures that contains sampling information about the global signals, states, and root-level inputs/outputs in the model. (This array contains no information about parameters.) Each element of this array is of type struct rtwCAPI_SampleTimeMap. The members of this structure provide information about the sample period, offset, and whether or not the data is frame-based or sample-based. Generate Example C API Files. The next three sections, “C API Signals” on page 15-149, “C API States” on page 15-153, “C API Root-Level Inputs and Outputs” on page 15-154, and “C API Parameters” on page 15-156, discuss generated C API structures using the example model rtwdemo_capi as an example. To generate code from the example model, do the following: 1 Open the model by clicking the rtwdemo_capi link above or by typing rtwdemo_capi on the MATLAB command line. The model appears as shown in the next figure. 15-146 Data Exchange 2 If you want to generate C API structures for root-level inputs/outputs in rtwdemo_capi, open the Configuration Parameters dialog box, go to the Code Generation > Interface pane, and make sure that the option Generate C API for: root-level I/O is selected. 15-147 15 Program Building, Interaction, and Debugging Note The setting of Generate C API for: root-level I/O must match between the top model and the referenced model. 3 Generate code for the model by double-clicking Generate Code Using Simulink Coder. Note The C API code examples in the next four sections are generated with C as the target language. This model has three global block output signals that will appear in C API generated code: • top_sig1, which is a test point at the output of the Gain1 block in the top model • sig2_eg, which appears in the top model and is defined in the base workspace as a Simulink.Signal object having storage class ExportedGlobal • bot_sig1, which appears in the submodel rtwdemo_capi_bot and is defined as a Simulink.Signal object having storage class SimulinkGlobal The model also has two discrete states that will appear in the C API generated code: • top_state, which is defined for the Delay1 block in the top model • bot_state, which is defined for the Discrete Filter block in the submodel The model has root-level inputs/outputs that will appear in the C API generated code if you select the option Generate C API for: root-level I/O: • Four root-level inputs, In1 through In4 • Six root-level outputs, Out1 through Out6 Additionally, the model has five global block parameters that will appear in C API generated code: 15-148 Data Exchange • Kp (top model Gain1 block and submodel Gain2 block share) • Ki (submodel Gain3 block) • p1 (lookup table lu1d) • p2 (lookup table lu2d) • p3 (lookup table lu3d) C API Signals. The rtwCAPI_Signals structure captures signal information including the signal name, address, block path, output port number, data type information, dimensions information, fixed-point information, and sample-time information. Here is the section of code in rtwdemo_capi_capi.c that provides information on C API signals for the top model in rtwdemo_capi: /* Block output signal information */ static const rtwCAPI_Signals rtBlockSignals[] = { /* addrMapIndex, sysNum, blockPath, * signalName, portNumber, dataTypeIndex, dimIndex, fxpIndex, sTimeIndex */ { 0, 0, "rtwdemo_capi/Gain1", "top_sig1", 0, 0, 0, 0, 0 }, { 1, 0, "rtwdemo_capi/lu2d", "sig2_eg", 0, 0, 1, 0, 0 }, { 0, 0, (NULL), (NULL), 0, 0, 0, 0, 0 } }; 15-149 15 Program Building, Interaction, and Debugging Note To better understand the code, read the comments in the file. For example, notice the comment that begins on the third line in the preceding code. This comment lists the members of the rtwCAPI_Signals structure, in order. This tells you the order in which the assigned values for each member appear for a signal. In this example, the comment tells you that signalName is the fourth member of the structure. The following lines describe the first signal: { 0, 0, "rtwdemo_capi/Gain1", "top_sig1", 0, 0, 0, 0, 0 }, From these lines you infer that the name of the first signal is top_sig1. Each array element, except the last, describes one output port for a block signal. The final array element is a sentinel, with all elements set to null values. For example, examine the second signal, described by the following code: { 1, 0, "rtwdemo_capi/lu2d", "sig2_eg", 0, 0, 1, 0, 0 }, This signal, named sig2_eg, is the output signal of the first port of the block rtwdemo_capi/lu2d. (This port is the first port because the zero-based index for portNumber displayed on the second line is assigned the value 0.) The address of this signal is given by addrMapIndex, which, in this example, is displayed on the first line as 1. This provides an index into the rtDataAddrMap array, found later in rtwdemo_capi_capi.c: /* Declare Data Addresses statically */ static void* rtDataAddrMap[] = { &rtwdemo_capi_B.top_sig1, 15-150 /* 0: Signal */ &sig2_eg[0], /* 1: Signal */ &rtwdemo_capi_DWork.top_state, /* 2: Discrete State */ &rtP_Ki, /* 3: Model Parameter */ &rtP_Kp, /* 4: Model Parameter */ &rtP_p1[0], /* 5: Model Parameter */ &rtP_p2[0], /* 6: Model Parameter */ &rtP_p3[0], /* 7: Model Parameter */ Data Exchange }; The index of 1 points to the second element in the rtDataAddrMap array. From the rtDataAddrMap array, you can infer that the address of this signal is &sig2_eg[0]. This level of indirection supports multiple code instances of the same model. For multiple instances, the signal information remains constant, except for the address. In this case, the model is a single instance. Therefore, the rtDataAddrMap is declared statically. If you choose to generate reusable code, an initialize function is generated that initializes the addresses dynamically per instance. (For details on generating reusable code, see “Set Up Support for Code Reuse” and “Entry Point Functions and Scheduling” in the Embedded Coder documentation.) The dataTypeIndex provides an index into the rtDataTypeMap array, found later in rtwdemo_capi_capi.c, indicating the data type of the signal: /* Data Type Map - use dataTypeMapIndex to access this structure */ static const rtwCAPI_DataTypeMap rtDataTypeMap[] = { /* cName, mwName, numElements, elemMapIndex, dataSize, slDataId, * * isComplex, isPointer */ { "double", "real_T", 0, 0, sizeof(real_T), SS_DOUBLE, 0, 0 } }; Because the index is 0 for sig2_eg, the index points to the first structure element in the array. You can infer that the data type of the signal is double. The value of isComplex is 0, indicating that the signal is not complex. Rather than providing the data type information directly in the rtwCAPI_Signals structure, a level of indirection is introduced. The indirection allows multiple signals that share the same data type to point to one map structure, saving memory for each signal. The dimIndex (dimensions index) provides an index into the rtDimensionMap array, found later in rtwdemo_capi_capi.c, indicating the dimensions of the signal. Because this index is 1 for sig2_eg, the index points to the second element in the rtDimensionMap array: /* Dimension Map - use dimensionMapIndex to access elements of ths structure*/ static const rtwCAPI_DimensionMap rtDimensionMap[] = { /* dataOrientation, dimArrayIndex, numDims, vardimsIndex */ 15-151 15 Program Building, Interaction, and Debugging { rtwCAPI_SCALAR, 0, 2, 0 }, { rtwCAPI_VECTOR, 2, 2, 0 }, ... }; From this structure, you can infer that this is a nonscalar signal having a dimension of 2. The dimArrayIndex value, 2, provides an index into rtDimensionArray, found later in rtwdemo_capi_capi.c: /* Dimension Array- use dimArrayIndex to access elements of this array */ static const uint_T rtDimensionArray[] = { 1, /* 0 */ 1, /* 1 */ 2, /* 2 */ ... }; The fxpIndex (fixed-point index) provides an index into the rtFixPtMap array, found later in rtwdemo_capi_capi.c, indicating any fixed-point information about the signal. Your code can use the scaling information to compute the real-world value of the signal, using the equation V=SQ+B, where V is “real-world” (that is, base-10) value, S is user-specified slope, Q is “quantized fixed-point value” or “stored integer,” and B is user-specified bias. (For details, see “Scaling” in the Fixed-Point Toolbox™ documentation.) Because this index is 0 for sig2_eg, the signal has no fixed-point information. A fixed-point map index of zero always means that the signal has no fixed-point information. The sTimeIndex (sample-time index) provides the index to the rtSampleTimeMap array, found later in rtwdemo_capi_capi.c, indicating task information about the signal. If you log multirate signals or conditionally executed signals, the sampling information can be useful. Note model_capi.c (or .cpp) includes rtw_capi.h. Any source file that references the rtBlockSignals array also must include rtw_capi.h. 15-152 Data Exchange C API States. The rtwCAPI_States structure captures state information including the state name, address, block path, type (continuous or discrete), data type information, dimensions information, fixed-point information, and sample-time information. Here is the section of code in rtwdemo_capi_capi.c that provides information on C API states for the top model in rtwdemo_capi: /* Block states information */ static const rtwCAPI_States rtBlockStates[] = { /* addrMapIndex, contStateStartIndex, blockPath, * stateName, pathAlias, dWorkIndex, dataTypeIndex, dimIndex, * fixPtIdx, sTimeIndex, isContinuous */ { 2, -1, "rtwdemo_capi/Delay1", "top_state", "", 0, 0, 0, 0, 0, 0 }, { 0, -1, (NULL), (NULL), (NULL), 0, 0, 0, 0, 0, 0 } }; Each array element, except the last, describes a state in the model. The final array element is a sentinel, with all elements set to null values. In this example, the C API code for the top model displays one state: { 2, -1, "rtwdemo_capi/Delay1", "top_state", "", 0, 0, 0, 0, 0, 0 }, This state, named top_state, is defined for the block rtwdemo_capi/Delay1. The value of isContinuous is zero, indicating that the state is discrete rather than continuous. The other fields correspond to the like-named signal equivalents described in “C API Signals” on page 15-149, as follows: • The address of the signal is given by addrMapIndex, which, in this example, is 2. This is an index into the rtDataAddrMap array, found later in rtwdemo_capi_capi.c. Because the index is zero based, 2 corresponds to the third element in rtDataAddrMap, which is &rtwdemo_capi_DWork.top_state. 15-153 15 Program Building, Interaction, and Debugging • The dataTypeIndex provides an index into the rtDataTypeMap array, found later in rtwdemo_capi_capi.c, indicating the data type of the parameter. The value 0 corresponds to a double, noncomplex parameter. • The dimIndex (dimensions index) provides an index into the rtDimensionMap array, found later in rtwdemo_capi_capi.c. The value 0 corresponds to the first entry, which is { rtwCAPI_SCALAR, 0, 2, 0 }. • The fixPtIndex (fixed-point index) provides an index into the rtFixPtMap array, found later in rtwdemo_capi_capi.c, indicating any fixed-point information about the parameter. As with the corresponding signal attribute, a fixed-point map index of zero always means that the parameter has no fixed-point information. C API Root-Level Inputs and Outputs. The rtwCAPI_Signals structure captures root-level input/output information including the input/output name, address, block path, port number, data type information, dimensions information, fixed-point information, and sample-time information. (This structure also is used for block output signals, as previously described in “C API Signals” on page 15-149.) Here is the section of code in rtwdemo_capi_capi.c that provides information on C API root-level inputs/outputs for the top model in rtwdemo_capi: /* Root Inputs information */ static const rtwCAPI_Signals rtRootInputs[] = { /* addrMapIndex, sysNum, blockPath, * signalName, portNumber, dataTypeIndex, dimIndex, fxpIndex, sTimeIndex */ { 3, 0, "rtwdemo_capi/In1", "", 1, 0, 0, 0, 0 }, { 4, 0, "rtwdemo_capi/In2", "", 2, 0, 0, 0, 0 }, { 5, 0, "rtwdemo_capi/In3", "", 3, 0, 0, 0, 0 }, { 6, 0, "rtwdemo_capi/In4", "", 4, 0, 0, 0, 0 }, 15-154 Data Exchange { 0, 0, (NULL), (NULL), 0, 0, 0, 0, 0 } }; /* Root Outputs information */ static const rtwCAPI_Signals rtRootOutputs[] = { /* addrMapIndex, sysNum, blockPath, * signalName, portNumber, dataTypeIndex, dimIndex, fxpIndex, sTimeIndex */ { 7, 0, "rtwdemo_capi/Out1", "", 1, 0, 0, 0, 0 }, { 8, 0, "rtwdemo_capi/Out2", "", 2, 0, 0, 0, 0 }, { 9, 0, "rtwdemo_capi/Out3", "", 3, 0, 0, 0, 0 }, { 10, 0, "rtwdemo_capi/Out4", "", 4, 0, 0, 0, 0 }, { 11, 0, "rtwdemo_capi/Out5", "sig2_eg", 5, 0, 1, 0, 0 }, { 12, 0, "rtwdemo_capi/Out6", "", 6, 0, 1, 0, 0 }, { 0, 0, (NULL), (NULL), 0, 0, 0, 0, 0 } }; For information about interpreting the values in the rtwCAPI_Signals structure, see the previous section “C API Signals” on page 15-149. 15-155 15 Program Building, Interaction, and Debugging C API Parameters. The rtwCAPI_BlockParameters and rtwCAPI_ModelParameters structures capture parameter information including the parameter name, block path (for block parameters), address, data type information, dimensions information, and fixed-point information. Each element in an rtBlockParameters or rtModelParameters array (except the last element) corresponds to a tunable parameter in the model. The setting of the Inline parameters option on the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box determines how information is generated into the rtBlockParameters and rtModelParameters arrays in model_capi.c (or .cpp), as follows: • If you clear Inline parameters: - The rtBlockParameters array contains an entry for every modifiable parameter of every block in the model. - The rtModelParameters array contains only Stateflow data of machine scope. The Simulink Coder software assigns its elements only NULL or zero values in the absence of such data. • If you select Inline parameters: - The rtBlockParameters array is empty. The Simulink Coder software assigns its elements only NULL or zero values. - The rtModelParameters array contains entries for all workspace variables that are referenced as tunable Simulink block parameters or Stateflow data of machine scope. Here is the rtBlockParameters array that is generated by default in rtwdemo_capi_capi.c: /* Individual block tuning is not valid when inline parameters is * * selected. An empty map is produced to provide a consistent * * interface independent * of inlining parameters. */ static const rtwCAPI_BlockParameters rtBlockParameters[] = { /* addrMapIndex, blockPath, * paramName, dataTypeIndex, dimIndex, fixPtIdx */ { 0, (NULL), (NULL), 0, 0, 0 15-156 Data Exchange } }; In this example, only the final, sentinel array element is generated, with all members of the structure rtwCAPI_BlockParameters set to NULL and zero values. This is because the Inline parameters option is selected by default for the rtwdemo_capi example model. If you clear this check box, the block parameters are generated in the rtwCAPI_BlockParameters structure. Here is the rtModelParameters array that is generated by default in rtwdemo_capi_capi.c: /* Tunable variable parameters */ static const rtwCAPI_ModelParameters rtModelParameters[] = { /* addrMapIndex, varName, dataTypeIndex, dimIndex, fixPtIndex */ { 3, "Ki", 0, 0, 0 }, { 4, "Kp", 0, 0, 0 }, { 5, "p1", 0, 2, 0 }, { 6, "p2", 0, 3, 0 }, { 7, "p3", 0, 4, 0 }, { 0, (NULL), 0, 0, 0 } }; In this example, the rtModelParameters array contains entries for each variable that is referenced as a tunable Simulink block parameter. For example, the varName (variable name) of the fourth parameter is p2. The other fields correspond to the like-named signal equivalents described in “C API Signals” on page 15-149, as follows: • The address of the fourth parameter is given by addrMapIndex, which, in this example, is 6. This is an index into the rtDataAddrMap array, found later in rtwdemo_capi_capi.c. Because the index is zero based, 6 corresponds to the seventh element in rtDataAddrMap, which is &rtwP_p2[0]. 15-157 15 Program Building, Interaction, and Debugging • The dataTypeIndex provides an index into the rtDataTypeMap array, found later in rtwdemo_capi_capi.c, indicating the data type of the parameter. The value 0 corresponds to a double, noncomplex parameter. • The dimIndex (dimensions index) provides an index into the rtDimensionMap array, found later in rtwdemo_capi_capi.c. The value 3 corresponds to the fourth entry, which is { rtwCAPI_MATRIX_COL_MAJOR, 6, 2, 0 }. • The fixPtIndex (fixed-point index) provides an index into the rtFixPtMap array, found later in rtwdemo_capi_capi.c, indicating any fixed-point information about the parameter. As with the corresponding signal attribute, a fixed-point map index of zero always means that the parameter has no fixed-point information. Map C API Data Structures to rtModel. The real-time model data structure encapsulates model data and associated information that describes the model fully. When you select the C API feature and generate code, the Simulink Coder code generator adds another member to the real-time model data structure generated in model.h: /* * DataMapInfo: * The following substructure contains information regarding * structures generated in the model's C API. */ struct { rtwCAPI_ModelMappingInfo mmi; } DataMapInfo; This member defines mmi (for model mapping information) of type struct rtwCAPI_ModelMappingInfo. The structure is located in matlabroot/rtw/c/src/rtw_modelmap.h (where matlabroot represents the root of your MATLAB installation folder). The mmi substructure defines the interface between the model and the C API files. More specifically, members of mmi map the real-time model data structure to the structures in model_capi.c (or .cpp). Initializing values of mmi members to the arrays accomplishes the mapping, as shown in Map Model to C API Arrays of Structures on page 15-160. Each member points to one of the arrays of structures in the generated C API 15-158 Data Exchange file. For example, the address of the rtBlockSignals array of structures is allocated to the first member of the mmi substructure in model.c (or .cpp), using the following code in the rtw_modelmap.h file: /* signals */ struct { rtwCAPI_Signals const *signals; /* uint_T numSignals; /* rtwCAPI_Signals const *rootInputs; /* uint_T numRootInputs; /* rtwCAPI_Signals const *rootOutputs; /* uint_T numRootOutputs;/* } Signals; Signals Array */ Num Signals */ Root Inputs array */ Num Root Inputs */ Root Outputs array */ Num Root Outputs */ The model initialize function in model.c (or .cpp) performs the initializing by calling the C API initialize function. For example, the following code is generated in the model initialize function for example model rtwdemo_capi: /* Initialize DataMapInfo substructure containing ModelMap for C API */ rtwdemo_capi_InitializeDataMapInfo(rtwdemo_capi_M); 15-159 15 Program Building, Interaction, and Debugging model_capi.c matlabroot/rtw/c/src/rtw_modelmap.h model.h struct rtModel_model { . . . rtwCAPI_Signals const *signals; rtwCAPI_Signals const *rootInputs; rtwCAPI_Signals const *rootOutputs; . rtBlockSignals rtRootInputs rtRootOutputs . rtwCAPI_BlockParameters const *blockParameters; rtBlockParameters . . rtwCAPI_ModelParameters const *modelParameters; rtModelParameters . . struct { rtwCAPI_States const *states; rtBlockStates rtwCAPI_ModelMappingInfo mmi; . . } DataMapInfo: rtwCAPI_DataTypeMap const *dataTypeMap; rtDataTypeMap . . rtwCAPI_DimensionMap const *dimensionMap; rtDimensionMap . . rtwCAPI_FixPtMap const *fixPtMap; rtFixPtMap . . rtwCAPI_SampleTimeMap const *sampleTimeMap; rtSampleTimeMap . . void** dataAddrMap; rtDataAddrMap . . . . . } Map Model to C API Arrays of Structures Note This figure lists the arrays in the order that their structures appear in rtw_modelmap.h, which differs slightly from their generated order in model_capi.c. Use the C API in an Application The C API provides you with the flexibility of writing your own application code to interact with model signals, states, root-level inputs/outputs, and parameters. Your target-based application code is compiled with the Simulink Coder generated code into an executable. The target-based application code accesses the C API structure arrays in model_capi.c (or .cpp). You 15-160 Data Exchange might have host-based code that interacts with your target-based application code. Or, you might have other target-based code that interacts with your target-based application code. The files rtw_modelmap.h and rtw_capi.h, located in matlabroot/rtw/c/src (where matlabroot represents the root of your MATLAB installation folder), provide macros for accessing the structures in these arrays and their members. This section provides examples to help you get started writing application code to interact with model signals, states, root-level inputs/outputs, and parameters. • “Use C API to Access Model Signals and States” on page 15-161 • “Use C API to Access Model Parameters” on page 15-168 Use C API to Access Model Signals and States. Here is an example application that logs global signals and states in a model to a text file. This code is intended as a starting point for accessing signal and state addresses. You can extend the code to perform signal logging and monitoring, state logging and monitoring, or both. This example uses the following macro and function interfaces: • rtmGetDataMapInfo macro Accesses the model mapping information (MMI) substructure of the real-time model structure. In the following macro call, rtM is the pointer to the real-time model structure in model.c (or .cpp): rtwCAPI_ModelMappingInfo* mmi = &(rtmGetDataMapInfo(rtM).mmi); • rtmGetTPtr macro Accesses the absolute time information for the base rate from the timing substructure of the real-time model structure. In the following macro call, rtM is the pointer to the real-time model structure in model.c (or .cpp): rtmGetTPtr(rtM) • Custom functions capi_StartLogging, capi_UpdateLogging, and capi_TerminateLogging, provided via the files rtwdemo_capi_datalog.h and rtwdemo_capi_datalog.c. These files are located in 15-161 15 Program Building, Interaction, and Debugging matlabroot/toolbox/rtw/rtwdemos, where matlabroot represents the root of your MATLAB installation folder. - capi_StartLogging initializes signal and state logging. capi_UpdateLogging logs a signal and state value at each time step. capi_TerminateLogging terminates signal and state logging and writes the logged values to a text file. You can integrate these custom functions into generated model code using any or all of the following methods: - Code Generation > Custom Code pane of the Configuration Parameters dialog box - Custom Code library blocks TLC custom code functions This tutorial uses the Code Generation > Custom Code pane and the System Outputs block from the Custom Code library to insert calls to the custom functions into model.c (or .cpp), as follows: - capi_StartLogging is called in the MdlStart function (or if an ert.tlc target is selected for the model, in the model_initialize function). - capi_UpdateLogging is called in the model_output function. capi_TerminateLogging is called in the model_terminate function. The following excerpts of generated code from model.c (rearranged to reflect their order of execution) show how the function interfaces are used. void MdlStart(void) { /* user code (Start function Trailer) */ /* C API Custom Logging Function: Start Signal and State logging via C-API. * capi_StartLogging: Function prototype in rtwdemo_capi_datalog.h */ { rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo(rtwdemo_capi_M).mmi); printf("** Started state/signal logging via C API **\n"); capi_StartLogging(MMI, MAX_DATA_POINTS); } 15-162 Data Exchange ... } ... /* Model output function */ static void rtwdemo_capi_output(int_T tid) { ... /* user code (Output function Trailer) */ /* C API Custom Logging Function: Update Signal and State logging buffers. * capi_UpdateLogging: Function prototype in rtwdemo_capi_datalog.h */ { rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo(rtwdemo_capi_M).mmi); capi_UpdateLogging(MMI, rtmGetTPtr(rtwdemo_capi_M)); } ... } ... /* Model terminate function */ void rtwdemo_capi_terminate(void) { /* user code (Terminate function Trailer) */ /* C API Custom Logging Function: Dump Signal and State buffers into a text file. * capi_TerminateLogging: Function prototype in rtwdemo_capi_datalog.h */ { capi_TerminateLogging("rtwdemo_capi_ModelLog.txt"); printf("** Finished state/signal logging. Created rtwdemo_capi_ModelLog.txt **\n"); } } The following procedure illustrates how you can use the C API macro and function interfaces to log global signals and states in a model to a text file. 1 At the MATLAB command line, enter rtwdemo_capi to open the example model. 2 Open the Configuration Parameters dialog box and go to the Code Generation pane. 15-163 15 Program Building, Interaction, and Debugging 3 For the System target file parameter, select grt.tlc. (Alternatively, if you are licensed for Embedded Coder software, you can select ert.tlc. Make sure that you also select ert.tlc for the referenced model rtwdemo_capi_bot.) Note Selecting a system target file other than grt.tlc or disabling some C API options (signals, parameters, or states) in the top model requires corresponding changes in the referenced model. Because the example models have read-only access, you must save the updated referenced model with a different name and modify the top model to reference the renamed model. 4 Go to the Interface pane. a In the Data exchange subpane, for the Interface parameter, verify that C API is selected. b Additionally, verify that the options Generate C API for: signals and Generate C API for: states are selected. This example also leaves Generate C API for: parameters selected. If you clear any of the options, make sure that the settings match between the top model and the referenced model. c If you are using the ert.tlc target, verify that the options MAT-file logging and Support: complex numbers are selected. d If you modified any option settings in this step, click Apply. 5 Use the Custom Code pane to embed your custom application code in the generated code. Select the Custom Code pane, and then click Include directories. The Include directories input field is displayed. 15-164 Data Exchange 6 In the Include directories field, type matlabroot/toolbox/rtw/rtwdemos, where matlabroot represents the root of your MATLAB installation folder. 7 In the Include list of additional subpane, click Source files, and type rtwdemo_capi_datalog.c, as shown below. 15-165 15 Program Building, Interaction, and Debugging 8 In the Include custom C code in generated subpane, click Source file, and type or copy and paste the following include statement: #include "rtwdemo_capi_datalog.h" 9 In the Initialize function field, type or copy and paste the following application code: /* C API Custom Logging Function: Start Signal and State logging via C-API. * capi_StartLogging: Function prototype in rtwdemo_capi_datalog.h */ { rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo(rtwdemo_capi_M).mmi); printf("** Started state/signal logging via C API **\n"); capi_StartLogging(MMI, MAX_DATA_POINTS); } 10 In the Terminate function field, type or copy and paste the following application code: /* C API Custom Logging Function: Dump Signal and State buffers into a text file. * capi_TerminateLogging: Function prototype in rtwdemo_capi_datalog.h */ { capi_TerminateLogging("rtwdemo_capi_ModelLog.txt"); printf("** Finished state/signal logging. Created rtwdemo_capi_ModelLog.txt **\n"); } 11 Click Apply. 12 In the MATLAB Command Window, enter custcode to open the Simulink Coder Custom Code library. At the top level of the rtwdemo_capi model, add a System Outputs block. 13 Double-click the System Outputs block to open the System Outputs Function Custom Code dialog box. In the System Outputs Function Exit Code field, type or copy and paste the following application code: /* C API Custom Logging Function: Update Signal and State logging buffers. * capi_UpdateLogging: Function prototype in rtwdemo_capi_datalog.h */ { 15-166 Data Exchange rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo(rtwdemo_capi_M).mmi); capi_UpdateLogging(MMI, rtmGetTPtr(rtwdemo_capi_M)); } Click OK. 14 On the Code Generation pane, verify that the Build button is visible. If it is not visible, clear the option Generate code only and click Apply. Click Build to build the model and generate an executable file. For example, on a Windows system, the build generates the executable file rtwdemo_capi.exe. 15 In the MATLAB Command Window, enter the command !rtwdemo_capi to run the executable file. During execution, signals and states are logged using the C API and then written to the text file rtwdemo_capi_ModelLog.txt in your working folder. >> !rtwdemo_capi ** starting the model ** ** Started state/signal logging via C API ** ** Logging 2 signal(s) and 2 state(s). In this example, only scalar named signals/states are logged ** ** Finished state/signal logging. Created rtwdemo_capi_ModelLog.txt ** 16 Examine the text file in the MATLAB editor or any text editor. Here is an excerpt of the signal and state logging output. ******** Signal Log File ******** Number of Signals Logged: 2 Number of points (time steps) logged: 51 Time bot_sig1 (Referenced Model) 0 70 top_sig1 4 0.2 70 4 0.4 70 4 0.6 70 4 0.8 70 4 1 70 4 15-167 15 Program Building, Interaction, and Debugging 1.2 70 4 1.4 70 4 1.6 70 4 1.8 70 4 2 70 4 ... ******** State Log File ******** Number of States Logged: 2 Number of points (time steps) logged: 51 Time bot_state (Referenced Model) 0 0 top_state 0 0.2 70 4 0.4 35 4 0.6 52.5 4 0.8 43.75 4 1 48.13 4 1.2 45.94 4 1.4 47.03 4 1.6 46.48 4 1.8 46.76 4 2 46.62 4 ... Use C API to Access Model Parameters. Here is an example application that prints the parameter values of all tunable parameters in a model to the standard output. This code is intended as a starting point for accessing parameter addresses. You can extend the code to perform parameter tuning. The application: • Uses the rtmGetDataMapInfo macro to access the mapping information in the mmi substructure of the real-time model structure rtwCAPI_ModelMappingInfo* mmi = &(rtmGetDataMapInfo(rtM).mmi); where rtM is the pointer to the real-time model structure in model.c (or .cpp). • Uses rtwCAPI_GetNumModelParameters to get the number of model parameters in mapped C API: 15-168 Data Exchange uint_T nModelParams = rtwCAPI_GetNumModelParameters(mmi); • Uses rtwCAPI_GetModelParameters to access the array of all model parameter structures mapped in C API: rtwCAPI_ModelParameters* capiModelParams = \ rtwCAPI_GetModelParameters(mmi); • Loops over the capiModelParams array to access individual parameter structures. A call to the function capi_PrintModelParameter displays the value of the parameter. The example application code is provided below: { /* Get CAPI Mapping structure from Real-Time Model structure */ rtwCAPI_ModelMappingInfo* capiMap = \ &(rtmGetDataMapInfo(rtwdemo_capi_M).mmi); /* Get number of Model Parameters from capiMap */ uint_T nModelParams = rtwCAPI_GetNumModelParameters(capiMap); printf("Number of Model Parameters: %d\n", nModelParams); /* If the model has Model Parameters, print them using the application capi_PrintModelParameter */ if (nModelParams == 0) { printf("No Tunable Model Parameters in the model \n"); } else { unsigned int idx; for (idx=0; idx < nModelParams; idx++) { /* call print utility function */ capi_PrintModelParameter(capiMap, idx); } } } The print utility function is located in matlabroot/rtw/c/src/rtw_capi_examples.c (where matlabroot 15-169 15 Program Building, Interaction, and Debugging represents the root of your MATLAB installation folder). This file contains utility functions for accessing the C API structures. To become familiar with the example code, try building a model that displays all the tunable block parameters and MATLAB variables. You can use rtwdemo_capi, the C API example model. The following steps apply to both grt.tlc and ert.tlc targets, unless otherwise indicated. 1 At the MATLAB command line, enter rtwdemo_capi to open the example model. 2 Open the Configuration Parameters dialog box and go to the Optimization > Signals and Parameters pane. 3 Verify that the Inline parameters option is selected. 4 If you are licensed for Embedded Coder software and you want to use the ert.tlc target instead of the default grt.tlc, go to the Code Generation pane and use the System target file field to select an ert.tlc target. 5 Use the Custom Code pane to embed your custom application code in the generated code. Select the Custom Code pane, and then click Initialize function. The Initialize function input field is displayed. 6 In the Initialize function input field, type or copy and paste the example application code shown above step 1. This embeds the application code in the MdlStart function. (If you are using ert.tlc, the code appears in the model_initialize function.) 7 Click Include directories, and type matlabroot/rtw/c/src, where matlabroot represents the root of your MATLAB installation folder. 8 In the Include list of additional subpane, click Source files, and type rtw_capi_examples.c. 15-170 Data Exchange Click Apply. 9 If you are using the ert.tlc target, go to the Code Generation > Interface pane, select the following options, and then click Apply. • In the Interface list, C API 15-171 15 Program Building, Interaction, and Debugging • MAT-file logging • Support: complex numbers 10 Go to the Code Generation pane and clear the Generate code only check box if it is not already cleared. 11 Click Build. The Simulink Coder code generator generates the executable file rtwdemo_capi.exe in your current working folder. 12 At the MATLAB command line, enter !rtwdemo_capi to run the executable file. Running the program displays parameter information in the Command Window. >> !rtwdemo_capi ** starting the model ** Number of Model Parameters: 5 Ki = 7 Kp = 4 p1 = 0.8147 0.9058 0.127 p2 = 0.9649 0.9706 0.4854 0.1576 0.9572 0.8003 p3 = ans(:,:,1) = 0.1419 0.9157 0.9595 0.03571 0.4218 0.7922 0.6557 0.8491 ans(:,:,2) = 0.934 0.7577 0.3922 0.1712 0.6787 0.7431 0.6555 0.706 >> 15-172 Data Exchange C API Limitations The C API feature has the following limitations. • The following code formats are not supported: - S-function Accelerated simulation • For ERT-based targets, the C API requires that support for floating-point code be enabled. • Local block output signals are not supported. • Local Stateflow parameters are not supported. • The following custom storage class objects are not supported: - Objects without the package csc_registration file BitPackBoolean objects, grouped custom storage classes, and objects defined by using macros • Customized data placement is disabled when you are using the C API. The interface looks for global data declaration in model.h and model_private.h. Declarations placed in any other file by customized data placement result in code that does not compile. Note Custom Storage Class objects take effect in code generation only if you use the ERT target and clear the Ignore custom storage classes check box in the Configuration Parameters dialog box. 15-173 15 Program Building, Interaction, and Debugging ASAP2 Data Measurement and Calibration ASAP2 is a data definition standard proposed by the Association for Standardization of Automation and Measuring Systems (ASAM). ASAP2 is a non-object-oriented description of the data used for measurement, calibration, and diagnostic systems. For more information on ASAM and the ASAP2 standard, see the ASAM Web site at http://www.asam.net. • “About ASAP2 Data Measurement and Calibration” on page 15-174 • “Targets Supporting ASAP2” on page 15-175 • “Define ASAP2 Information” on page 15-175 • “Generate an ASAP2 File” on page 15-182 • “Structure of the ASAP2 File” on page 15-187 • “Generate ASAP2 and C API Files” on page 15-188 About ASAP2 Data Measurement and Calibration The Simulink Coder product lets you export an ASAP2 file containing information about your model during the code generation process. To make use of ASAP2 file generation, you should become familiar with the following topics: • ASAM and the ASAP2 standard and terminology. See the ASAM Web site at http://www.asam.net. • Simulink data objects. Data objects are used to supply information not contained in the model. For an overview, see “Data Objects”. • Storage and representation of signals and parameters in generated code. See “Data Representation”. • If you are licensed for Embedded Coder, see also the Embedded Coder topic “Data Representation ”. You can run an interactive example of ASAP2 file generation. To open the example at the MATLAB command prompt, enter the following command: rtwdemo_asap2 15-174 Data Exchange Note Simulink Coder support for ASAP2 file generation is version-neutral. By default, the software generates ASAP2 version 1.31 format, but the generated model information is generally compatible with all ASAP2 versions. ASAP2 file generation also is neutral with respect to the specific needs of ASAP2 measurement and calibration tools. The software provides customization APIs that you can use to customize ASAP2 file generation to generate any ASAP2 version and to meet the specific needs of your ASAP2 tools. Targets Supporting ASAP2 ASAP2 file generation is available to all Simulink Coder target configurations. You can select these target configurations from the System Target File Browser. For example, • The Generic Real-Time Target (grt.tlc) lets you generate an ASAP2 file as part of the code generation and build process. • Any of the Embedded Coder (ert.tlc) target selections also lets you generate an ASAP2 file as part of the code generation and build process. • The ASAM-ASAP2 Data Definition Target (asap2.tlc) lets you generate only an ASAP2 file, without building an executable. Procedures for generating ASAP2 files by using these target configurations are given in “Generate an ASAP2 File” on page 15-182. Define ASAP2 Information • “Define ASAP2 Information for Parameters and Signals” on page 15-176 • “Memory Address Attribute” on page 15-177 • “Automatic ECU Address Replacement for ASAP2 Files (Embedded Coder)” on page 15-178 • “Define ASAP2 Information for Lookup Tables” on page 15-180 15-175 15 Program Building, Interaction, and Debugging Define ASAP2 Information for Parameters and Signals. The ASAP2 file generation process requires information about your model’s parameters and signals. Some of this information is contained in the model itself. You must supply the rest by using Simulink data objects and corresponding properties. You can use built-in Simulink data objects to provide the information. For example, you can use Simulink.Signal objects to provide MEASUREMENT information and Simulink.Parameter objects to provide CHARACTERISTIC information. Also, you can use data objects from data classes that are derived from Simulink.Signal and Simulink.Parameter to provide the information. For details, see “Data Objects”. The following table contains the minimum set of data attributes required for ASAP2 file generation. Some data attributes are defined in the model; others are supplied in the properties of objects. For attributes that are defined in Simulink.Signal or Simulink.Parameter objects, the table gives the associated property name. 15-176 Data Attribute Defined In Property Name Name (symbol) Data object Inherited from the handle of the data object to which parameter or signal name resolves Description Data object Description Data type Model Not applicable Scaling (if fixed-point data type) Model Data type (for signals) Minimum allowable value Data object Min Maximum allowable value Data object Max Inherited from value (for parameters) Data Exchange Data Attribute Defined In Property Name Units Data object DocUnits Memory address (optional) Data object MemoryAddress_ASAP2 (optional; see “Memory Address Attribute” on page 15-177.) Memory Address Attribute. If the memory address attribute is unknown before code generation, the code generator inserts an ECU Address placeholder string in the generated ASAP2 file. You can substitute an actual address for the placeholder by postprocessing the generated file. See the file matlabroot/toolbox/rtw/targets/asap2/asap2/asap2post.m for an example. asap2post.m parses through the linker map file that you provide and replaces the placeholder strings in the ASAP2 file with the actual memory addresses. Since linker map files vary from compiler to compiler, you might need to modify the regular expression code in asap2post.m to match the format of the linker map you use. Note If Embedded Coder is licensed and installed on your system, and if you are generating ELF (Executable and Linkable Format) files for your embedded target, you can use the rtw.asap2SetAddress function to automate ECU address replacement. For more information, see “Automatic ECU Address Replacement for ASAP2 Files (Embedded Coder)” on page 15-178. If the memory address attribute is known before code generation, it can be defined in the data object. By default, the MemoryAddress_ASAP2 property does not exist in the Simulink.Signal or Simulink.Parameter data object classes. If you want to add the attribute, add a property called MemoryAddress_ASAP2 to a custom class that is a subclass of the Simulink or ASAP2 class. For information on subclassing Simulink data classes, see “Define Level-1 Data Classes” in the Simulink documentation. 15-177 15 Program Building, Interaction, and Debugging Note In previous releases, for ASAP2 file generation, you had to define objects explicitly as ASAP2.Signal and ASAP2.Parameter. This is no longer a limitation. As explained above, you can use built-in Simulink objects for generating an ASAP2 file. If you have been using an earlier release, you can continue to use the ASAP2 objects. If one of these ASAP2 objects was created in the previous release, and you use it in this release, the MATLAB Command Window displays a warning the first time the objects are loaded. The following table indicates the Simulink object properties that have replaced the ASAP2 object properties of the previous release: Differences Between ASAP2 and Simulink Parameter and Signal Object Properties ASAP2 Object Properties (Previous) Simulink Object Properties (Current) LONGIG_ASAP2 Description PhysicalMin_ASAP2 Min PhysicalMax_ASAP2 Max Units_ASAP2 DocUnits Automatic ECU Address Replacement for ASAP2 Files (Embedded Coder). If Embedded Coder is licensed and installed on your system, and if you are generating ELF (Executable and Linkable Format) files for your embedded target, you can use the rtw.asap2SetAddress function to automate the replacement of ECU Address placeholder memory address values with actual addresses in the generated ASAP2 file. If the memory address attribute is unknown before code generation, the code generator inserts an ECU Address placeholder string in the generated ASAP2 file, as shown in the example below. /begin CHARACTERISTIC /* Name */ Ki /* Long Identifier */ "" /* Type */ VALUE 15-178 Data Exchange /* ECU Address */ 0x0 /*ECU_Address@Ki@ */ To substitute actual addresses for the ECU Address placeholders, postprocess the generated ASAP2 file using the rtw.asap2SetAddress function. The general syntax is as follows: rtw.asap2SetAddress(ASAP2File, InfoFile) where the arguments are strings specifying the name of the generated ASAP2 file and the name of the generated executable ELF file or DWARF debug information file for the model. When called, rtw.asap2SetAddress extracts the actual ECU address from the specified ELF or DWARF file and replaces the placeholder in the ASAP2 file with the actual address, for example: /begin CHARACTERISTIC /* Name */ /* Long Identifier */ /* Type */ /* ECU Address */ Ki "" VALUE 0x40009E60 15-179 15 Program Building, Interaction, and Debugging Define ASAP2 Information for Lookup Tables. Simulink Coder software generates ASAP2 descriptions for lookup table data and its breakpoints. The software represents 1-D table data as CURVE information, 2-D table data as MAP information, and breakpoints as AXIS_DESCR and AXIS_PTS information. You can model lookup tables using any of the following Simulink Lookup Table blocks: • Direct Lookup Table (n-D) — 1 and 2 dimensions • Interpolation Using Prelookup — 1 and 2 dimensions • 1–D Lookup Table • 2–D Lookup Table • n-D Lookup Table — 1 and 2 dimensions The software supports the following types of lookup table breakpoints (axis points): Breakpoint Type Generates Tunable and shared among multiple table axes (common axis) COM_AXIS Fixed and nontunable (fixed axis) One of these variants of FIX_AXIS: • FIX_AXIS_PAR if breakpoints are integers with equidistant spacing • FIX_AXIS_PAR_DIST if breakpoints are integers with equidistant spacing and the equidistant spacing is a power of two • FIX_AXIS_PAR_LIST if breakpoints are integers with non-equidistant spacing Tunable but not shared among multiple tables (standard axis) 15-180 STD_AXIS Data Exchange When you configure the blocks for ASAP2 code generation: • For table data, use a Simulink.Parameter data object with a non-Auto storage class. • For tunable breakpoint data that is shared among multiple table axes (COM_AXIS), use a Simulink.Parameter data object with a non-Auto storage class. • For fixed, nontunable breakpoint data (FIX_AXIS), use workspace variables or arrays specified in the block parameters dialog box. The breakpoints should be stored as integers in the code, so the data type should be a built-in integer type (int8, int16, int32, uint8, uint16, or uint32), a fixed-point data type, or an equivalent alias type. • For tunable breakpoint data that is not shared among multiple tables (STD_AXIS): 1 Create a Simulink.Bus object to define the struct packaging (names and order of the fields). The fields of the parameter structure must correspond to the lookup table data and each axis of the lookup table block. For example, in an n-D Lookup Table block with 2 dimensions, the structure must contain only three fields. This bus object describes the record layout for the lookup characteristic. 2 Create a Simulink.Parameter object to represent a tunable parameter. 3 Create table and axis values. 4 Optionally, specify the Units, Minimum, and Maximum properties for the parameter object. The properties will be applied to table data only. Here is an example of an n-D Lookup Table record generated into an ASAP2 file in Standard Axis format: /begin CHARACTERISTIC /* Name */ STDAxisParam ... /* Record Layout */ Lookup1D_X_WORD_Y_FLOAT32_IEEE ... begin AXIS_DESCR /* Description of X-Axis Points */ /* Axis Type */ STD_AXIS ... 15-181 15 Program Building, Interaction, and Debugging /end AXIS_DESCR /end CHARACTERISTIC /begin RECORD_LAYOUT Lookup1D_X_WORD_Y_FLOAT32_IEEE AXIS_PTS_X 1 WORD INDEX_INCR DIRECT FNC_VALUES 2 FLOAT32_IEEE COLUMN_DIR DIRECT /end RECORD_LAYOUT Note The example model rtwdemo_asap2 illustrates ASAP2 file generation for Lookup Table blocks, including both tunable (COM_AXIS) and fixed (FIX_AXIS) lookup table breakpoints. Generate an ASAP2 File • “About Generating ASAP2 Files” on page 15-182 • “Use GRT or ERT Target” on page 15-182 • “Use the ASAM-ASAP2 Data Definition Target” on page 15-184 • “Generate ASAP2 Files for Referenced Models” on page 15-186 • “Merge ASAP2 Files for Top and Referenced Models” on page 15-186 About Generating ASAP2 Files. You can generate an ASAP2 file from your model in one of the following ways: • Use the Generic Real-Time Target or a Embedded Coder target to generate an ASAP2 file as part of the code generation and build process. • Use the ASAM-ASAP2 Data Definition Target to generate only an ASAP2 file, without building an executable. This section discusses how to generate an ASAP2 file by using the targets that have built-in ASAP2 support. For an example, see the ASAP2 example model rtwdemo_asap2. Use GRT or ERT Target. The procedure for generating a model’s data definition in ASAP2 format using the Generic Real-Time Target or an Embedded Coder target is as follows: 15-182 Data Exchange 1 Create the desired model. Use parameter names and signal labels to refer to corresponding CHARACTERISTIC records and MEASUREMENT records , respectively. 2 Define the desired parameters and signals in the model to be Simulink.Parameter and Simulink.Signal objects in the MATLAB workspace. A convenient way of creating multiple signal and parameter data objects is to use the Data Object Wizard. Alternatively, you can create data objects one at a time from the MATLAB command line. For details on how to use the Data Object Wizard, see “Data Object Wizard” in the Simulink documentation. 3 For each data object, configure the Storage class property to a setting other than Auto or SimulinkGlobal. This declares the data object as global in the generated code. For example, a storage class setting of ExportedGlobal configures the data object as unstructured global in the generated code. Note If you set the storage class to Auto or SimulinkGlobal, or if you set the storage class to Custom and custom storage class settings cause the Simulink Coder code generator to generate a macro or non-addressable variable, the data object is not represented in the ASAP2 file. 4 Configure the remaining properties as desired for each data object. 5 On the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box, select the Inline parameters check box. You should not configure the parameters associated with your data objects as Simulink global (tunable) parameters in the Model Parameter Configuration dialog box. If a parameter that resolves to a Simulink data object is configured using the Model Parameter Configuration dialog box, the dialog box configuration is ignored. You can, however, use the Model Parameter Configuration dialog box to configure other parameters in your model. 15-183 15 Program Building, Interaction, and Debugging 6 On the Code Generation pane, click Browse to open the System Target File Browser. In the browser, select Generic Real-Time Target or any embedded real-time target and click OK. 7 In the Interface field on the Interface pane, select ASAP2. 8 Select the Generate code only check box on the Code Generation pane. 9 Click Apply. 10 Click Generate code. The Simulink Coder code generator writes the ASAP2 file to the build folder. By default, the file is named model.a2l, where model is the name of the model. The ASAP2 filename is controlled by the ASAP2 setup file. For details see “Customize an ASAP2 File” on page 23-2. Use the ASAM-ASAP2 Data Definition Target. The procedure for generating a model’s data definition in ASAP2 format using the ASAM-ASAP2 Data Definition Target is as follows: 1 Create the desired model. Use parameter names and signal labels to refer to corresponding CHARACTERISTIC records and MEASUREMENT records , respectively. 2 Define the desired parameters and signals in the model to be Simulink.Parameter and Simulink.Signal objects in the MATLAB workspace. A convenient way of creating multiple signal and parameter data objects is to use the Data Object Wizard. Alternatively, you can create data objects one at a time from the MATLAB command line. For details on how to use the Data Object Wizard, see “Data Object Wizard” in the Simulink documentation. 3 For each data object, configure the Storage class property to a setting other than Auto or SimulinkGlobal. This causes the data object to be declared as global in the generated code. For example, a storage class 15-184 Data Exchange setting of ExportedGlobal configures the data object as unstructured global in the generated code. Note If you set the storage class to Auto or SimulinkGlobal, or if you set the storage class to Custom and custom storage class settings cause the Simulink Coder code generator to generate a macro or non-addressable variable, the data object is not represented in the ASAP2 file. 4 Configure the remaining properties as desired for each data object. 5 On the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box, select the Inline parameters check box. You should not configure the parameters associated with your data objects as Simulink global (tunable) parameters in the Model Parameter Configuration dialog box. If a parameter that resolves to a Simulink data object is configured using the Model Parameter Configuration dialog box, the dialog box configuration is ignored. You can, however, use the Model Parameter Configuration dialog box to configure other parameters in your model. 6 On the Code Generation pane, click Browse to open the System Target File Browser. In the browser, select ASAM-ASAP2 Data Definition Target and click OK. 7 Select the Generate code only check box on the Code Generation pane. 8 Click Apply. 9 Click Generate code. The Simulink Coder code generator writes the ASAP2 file to the build folder. By default, the file is named model.a2l, where model is the name of the model. The ASAP2 filename is controlled by the ASAP2 setup file. For details see “Customize an ASAP2 File” on page 23-2. 15-185 15 Program Building, Interaction, and Debugging Generate ASAP2 Files for Referenced Models. The build process can generate an ASAP2 file for each referenced model in a model reference hierarchy. In the generated ASAP2 file, MEASUREMENT records represent signals and states inside the referenced model. To generate ASAP2 files for referenced models, select ASAP2 file generation for the top model and for each referenced model in the reference hierarchy. For example, if you are using the Generic Real-Time Target or an Embedded Coder target, follow the procedure described in “Use GRT or ERT Target” on page 15-182 for the top model and each referenced model. Merge ASAP2 Files for Top and Referenced Models. Use function rtw.asap2MergeMdlRefs to merge the ASAP2 files generated for top and referenced models. The function has the following syntax: [status,info]=rtw.asap2MergeMdlRefs(topModelName,asap2FileName) • topModelName is the name of the model containing one or more referenced models. • asap2FileName is the name you specify for the merged ASAP2 file. • Optional:: status returns false (logical 0) if the merge completes and true (logical 1) otherwise. • Optional:: info returns additional information about merge failure if status is true. Otherwise, it returns an empty string. Consider the following example. [status,info]=rtw.asap2MergeMdlRefs('myTopMdl','merged.a2l') This command merges the ASAP2 files generated for the top model myTopMdl and its referenced models in the file merged.a2l. The example model rtwdemo_asap2 includes an example of merging ASAP2 files. 15-186 Data Exchange Structure of the ASAP2 File The following table outlines the basic structure of the ASAP2 file and describes the Target Language Compiler (TLC) functions and files used to create each part of the file: • Static parts of the ASAP2 file are shown in bold. • Function calls are indicated by % . File Section Contents of asap2main.tlc TLC File Containing Function Definition File header % asap2userlib.tlc /begin PROJECT "" /begin PROJECT "% " asap2setup.tlc /begin HEADER "" HEADER contents /begin HEADER"% " % asap2setup.tlc asap2userlib.tlc /end HEADER /end HEADER /begin MODULE "" MODULE contents: /begin MODULE "% "} - A2ML - MOD_PAR - MOD_COMMON % asap2setup.tlc asap2userlib.tlc ... Model-dependent MODULE contents: % - ...WriteRecordLayout_TemplateName() RECORD_LAYOUT CHARACTERISTIC ParameterGroups ModelParameters asap2lib.tlc Calls user-defined functions: user/templates/... ...WriteCharacteristic_TemplateName() ...WriteCharacteristic_Scalar() - MEASUREMENT - ExternalInputs - BlockOutputs ...WriteMeasurement() asap2userlib.tlc - COMPU_METHOD ...WriteCompuMethod() asap2userlib.tlc 15-187 15 Program Building, Interaction, and Debugging File Section Contents of asap2main.tlc /end MODULE /end MODULE File footer/tail % TLC File Containing Function Definition asap2userlib.tlc Generate ASAP2 and C API Files The ASAP2 and C API interfaces are not mutually exclusive. Although the Interface option on the Code Generation > Interface pane of the Configuration Parameters dialog box allows you to select either the ASAP2 or C API interface, you can instruct the Simulink Coder product to generate files for both interfaces by doing the following: 1 On the Code Generation > Interface pane of the Configuration Parameters dialog box, select C API for the Interface option. 2 In the MATLAB Command Window, with the model open, specify the following command: >> set_param(gcs,'GenerateASAP2','on') Note If you select both the C API and ASAP2 data interfaces, only the C API options are displayed in the Configuration Parameters dialog box. 3 Click Generate or Build. The code generator generates the following ASAP2 and C API files: • model.a2l — ASAP2 description file • model_capi.c — C API source file 15-188 Data Exchange • model_capi.h — C API header file For more information about using the C API interface, see “Data Interchange Using the C API” on page 15-137. Direct Memory Access to Generated Code The Simulink Coder product provides a TLC function library that lets you create a global data map record. The global data map record, when generated, is added to the CompiledModel structure in the model.rtw file. The global data map record is a database containing all information required for accessing memory in the generated code, including • Signals (Block I/O) • Parameters • Data type work vectors (DWork) • External inputs • External outputs Use of the global data map requires knowledge of the Target Language Compiler and of the structure of the model.rtw file. See “Target Language Compiler Overview” for information on these topics. The TLC functions that are required to generate and access the global data map record are contained in matlabroot/rtw/c/tlc/mw/globalmaplib.tlc. The comments in the source code fully document the global data map structures and the library functions. The global data map structures and functions might be modified or enhanced in future releases. 15-189 15 Program Building, Interaction, and Debugging 15-190 Performance • Chapter 16, “Optimizations for Generated Code” • Chapter 17, “Defensive Programming” • Chapter 18, “Data Copy Reduction” • Chapter 19, “Execution Speed” • Chapter 20, “Memory Usage” 16 Optimizations for Generated Code • “Optimization Parameters” on page 16-2 • “Advice About Optimizing Models for Code Generation” on page 16-5 • “Control Compiler Optimizations” on page 16-6 • “Optimization Tools and Techniques” on page 16-7 • “Control Memory Allocation for Time Counters” on page 16-9 • “Optimization Dependencies” on page 16-10 16 Optimizations for Generated Code Optimization Parameters Many options on the Optimization and Optimization > Signals and Parameters panes of the Configuration Parameters dialog box affect generated code. The following figures shows the default optimization settings, except that Inline parameters and Inline invariant signals, which are cleared by default, are selected. Some basic optimization suggestions are given below, cross-referenced to more extensive relevant discussions in the documentation. • Selecting the Signal storage reuse check box directs the Simulink Coder code generator to store signals in reusable memory locations. It also enables 16-2 Optimization Parameters the Enable local block outputs, Reuse block outputs, Eliminate superfluous local variables (expression folding), and Minimize data copies between local and global variables options (see below). Disabling Signal storage reuse makes all block outputs global and unique, which in many cases significantly increases RAM and ROM usage. See “Reduce Memory Requirements for Signals” on page 20-4 for more details. • Selecting the Inline parameters check box reduces global RAM usage, because parameters are not declared in the global parameters structure. You can override the inlining of individual parameters by using the Model Parameter Configuration dialog box. You tune parameters used in referenced models differently, by declaring them as Model block parameter arguments, rather than using the Model Parameter Configuration dialog box. See “Inline Parameters” on page 19-2 and “Using Model Arguments” in the Simulink documentation for more details. • Selecting the Enable local block outputs check box declares block signals locally in functions instead of being declared globally (when possible). You must select Signal storage reuse to enable Enable local block outputs. See “Declare Signals as Local Function Data” on page 18-17. • Selecting the Reuse block outputs check box reduces stack size where signals are buffered in local variables. You must select Signal storage reuse to enable Reuse block outputs. See “Reuse Memory Allocated for Signals” on page 20-5. • Selecting the Inline invariant signals check box makes the Simulink Coder code generator not generate code for blocks with a constant (invariant) sample time. You must select Inline parameters to enable Inline invariant signals. See “Inline Invariant Signals” on page 18-18. • Selecting the Eliminate superfluous local variables (expression folding) check box minimizes the computation of intermediate results at block outputs and the storage of such results in temporary buffers or variables. See “Minimize Computations and Storage for Intermediate Results” on page 18-11. • Selecting the Minimize data copies between local and global variables check box reuses existing global variables to store temporary results. You must select Signal storage reuse to enable Minimize 16-3 16 Optimizations for Generated Code data copies between local and global variables. See “Reuse Memory Allocated for Signals” on page 20-5. • Set a Loop unrolling threshold. The loop unrolling threshold determines when a wide signal should be wrapped into a for loop and when it should be generated as a separate statement for each element of the signal. See “Configure Loop Unrolling Threshold” on page 19-4 for details on this feature. • Specifying a Maximum stack size (bytes) provides control of the number of local and global variables, which determine the amount of stack space required for an application. See “Use Stack Space Allocation” on page 20-6 for more information. • If your target environment supports the memcpy function, and if your model uses signal vector assignments to move large amounts of data, selecting the Use memcpy for vector assignment check box can improve the execution speed of vector assignments by replacing for loops with memcpy function calls in the generated code. Set a Memcpy threshold (bytes). See “Optimize Code Generated for Vector Assignments” on page 19-6 for details. Note The rtwdemos example suite includes a set of models that illustrate optimization settings and techniques. To access these examples, type rtwdemos or click the above command. The MATLAB Help browser opens the Simulink Coder examples page. Click Optimizations in the navigation pane. Use the examples to learn about the specific effects that optimization parameters and techniques have on models. 16-4 Advice About Optimizing Models for Code Generation Advice About Optimizing Models for Code Generation Using the Model Advisor, you can quickly analyze a model for code generation and identify aspects of your model that impede production deployment or limit code efficiency. You can select from a set of checks to run on a model’s current configuration. The Model Advisor analyzes the model and generates check results providing suggestions for improvements in each area. Most Model Advisor diagnostics do not require the model to be in a compiled state; those that do are noted. Before running the Model Advisor, select the target you plan to use for code generation. The Model Advisor works most effectively with ERT and ERT-based targets (targets based on the Embedded Coder software). Use the following Model Advisor examples to investigate optimizing models for code generation using the Model Advisor: • rtwdemo_advisor1 • rtwdemo_advisor2 • rtwdemo_advisor3 Note Example models rtwdemo_advisor2 and rtwdemo_advisor3 require Stateflow and Fixed-Point Toolbox software. For more information on using the Model Advisor, see “Consult the Model Advisor” in the Simulink documentation. For more information about the checks in the Model Advisor, see “Embedded Coder Checks” in the Simulink Coder documentation. 16-5 16 Optimizations for Generated Code Control Compiler Optimizations To control compiler optimizations for your Simulink Coder makefile build at the Simulink GUI level, use the Compiler optimization level parameter. The Compiler optimization level parameter provides • Target-independent values Optimizations on (faster runs) and Optimizations off (faster builds), which allow you to easily toggle compiler optimizations on and off during code development • The value Custom for entering custom compiler optimization flags at the Simulink GUI level, rather than editing compiler flags into template makefiles (TMFs) or supplying compiler flags to Simulink Coder make commands The default setting is Optimizations off (faster builds). Selecting the value Custom enables the Custom compiler optimization flags field, in which you can enter custom compiler optimization flags (for example, -O2). Note If you specify compiler options for your Simulink Coder makefile build using OPT_OPTS, MEX_OPTS (except MEX_OPTS="-v"), or MEX_OPT_FILE, the value of Compiler optimization level is ignored and a warning is issued about the ignored parameter. For more information about the Compiler optimization level parameter and its values, see “Compiler optimization level” and “Custom compiler optimization flags”. 16-6 Optimization Tools and Techniques Optimization Tools and Techniques In addition to analyzing models with Model Advisor (see “Advice About Optimizing Models for Code Generation” on page 16-5), you can use a variety of other tools and techniques that work with any code format. Here are some particularly useful ones: • Run the slupdate command to automatically convert older models (saved by prior versions or by the current one) to use current features. For details about what slupdate does, type help slupdate • Before building, set optimization flags for the compiler (for example, -O2 for gcc, -Ot for the Microsoft Visual C++ compiler). • Directly inline C/C++ S-functions into the generated code by writing a TLC file for the S-function. See “Generated S-Function Block” on page 12-34 and the Target Language Compiler documentation for more information on inlining S-functions. • Use a Simulink data type other than double when possible. The available data types are Boolean, signed and unsigned 8-, 16-, and 32-bit integers, and 32- and 64-bit floats (a double is a 64-bit float). For more information, see “Data Types”. For a block-by-block summary, click showblockdatatypetable or type the command in the MATLAB Command Window. • Remove repeated values in lookup table data. • Use the Merge block to merge the output of signals wherever possible. This block is particularly helpful when you need to control the execution of function-call subsystems with a Stateflow chart. The following model shows an example of how to use the Merge block. 16-7 16 Optimizations for Generated Code When more than one signal connected to a Merge block has a non-Auto storage class, all non-Auto signals connected to that block must be identically labeled and have the same storage class. When Merge blocks connect directly to one another, these rules apply to all signals connected to any of the Merge blocks in the group. If you are licensed to use the Embedded Coder product, see also “Configure Code Optimizations” in the Embedded Coder documentation. 16-8 Control Memory Allocation for Time Counters Control Memory Allocation for Time Counters The Application lifespan (days) parameter lets you control the allocation of memory for absolute and elapsed time counters. Such counters exist in the code for blocks that use absolute or elapsed time. For a list of such blocks, see “Limitations on the Use of Absolute Time” on page 1-88. The size of the time counters in generated code is 8, 16, 32, or 64 bits. The size is set automatically to the minimum that can accommodate the duration value specified by Application lifespan (days) given the step size specified in the Configuration Parameters Solver pane. To minimize the amount of RAM used by time counters, specify the smallest lifespan possible and the largest step size possible. An application runs to its specified lifespan. It may be able to run longer. For example, running a model with a step size of one millisecond (0.001 seconds) for one day requires a 32-bit timer, which could continue running without overflow for 49 days more. To maximize application lifespan, specify Application lifespan (days) as inf. This value allocates 64 bits (two uint32 words) for each timer. Using 64 bits to store timing data would allow a model with a step size of 0.001 microsecond (10E-09 seconds) to run for more than 500 years, which would rarely be required. 64-bit counters do not violate the usual Simulink Coder length limitation of 32 bits because the value of a time counter never provides the value of a signal, state, or parameter. For information about the allocation and operation of absolute and elapsed time counters, see “Timers” on page 1-79. For information about asynchronous timing, see “Use Timers in Asynchronous Tasks” on page 1-58. For information about the effect of the Application lifespan (days) parameter on simulation, see “Application lifespan (days)” in the Simulink documentation. 16-9 16 Optimizations for Generated Code Optimization Dependencies Several parameters available on the Optimization panes have dependencies on settings of other options. The following table summarizes the dependencies. 16-10 Option Dependencies? Block reduction No Conditional input branch execution No Implement logic signals as Boolean data (versus double) Yes Signal storage reuse No Inline parameters Yes Application lifespan (days) No Parameter structure (ERT targets only) Yes Enabled by Inline parameters Enable local block outputs Yes Enabled by Signal storage reuse Reuse block outputs Yes Enabled by Signal storage reuse Inline invariant signals Yes Enabled by Inline parameters Eliminate superfluous local variables (expression folding) Yes Enabled by Signal storage reuse Pack Boolean data into bitfields (ERT targets only) No Bitfield declarator type specifier (ERT targets only) Yes Enabled by Pack Boolean data into bitfields Minimize data copies between local and global variables Yes Enabled by Signal storage reuse Simplify array indexing (ERT targets only) No Loop unrolling threshold No Dependency Details Disable for models created with a Simulink version that supports only signals of type double Disable for referenced models in a model reference hierarchy Optimization Dependencies Option Dependencies? Maximum stack size (bytes) No Use memcpy for vector assignment No Memcpy threshold (bytes) Yes Pass reusable subsystem output as (ERT targets only) No Remove root level I/O zero initialization (ERT targets only) No Use memset to initialize floats and doubles to 0.0 No Remove internal data zero initialization (ERT targets only) No Optimize initialization code for model reference (ERT targets only) Yes Remove code from floating-point to integer conversions that wrap out-of-range values No Remove code from floating-point to integer conversions with saturation that maps NaN to zero Yes (ERT targets) No (GRT targets) Remove code that protects against division arithmetic exceptions (ERT targets only) No Dependency Details Enabled by Use memcpy for vector assignment Disable if model includes an enabled subsystem and the model is referred to from another model with a Model block For ERT targets, enabled by Support floating-point numbers and Support non-finite numbers in the Code Generation > Interface pane 16-11 16 16-12 Optimizations for Generated Code 17 Defensive Programming • “Optimize Code for Floating-Point to Integer Conversions” on page 17-2 • “Disable Nonfinite Checks or Inlining for Math Functions” on page 17-4 17 Defensive Programming Optimize Code for Floating-Point to Integer Conversions In this section... “Remove Code That Wraps Out-of-Range Values” on page 17-2 “Remove Code That Maps NaN to Integer Zero” on page 17-3 Remove Code That Wraps Out-of-Range Values Selecting the Remove code from floating-point to integer conversions that wraps out-of-range values check box in the Integer and fixed-point section of the Optimization pane causes the code generator to remove code that produces the same results as simulation when out-of-range conversions occur. This action reduces the size and increases the speed of generated code at the cost of potentially producing results that do not match simulation in the case of out-of-range values. For more information, see “Optimization Pane: General”. The code generated for a conversion when you select the check box follows: cg_in_0_20_0[i1] = (int32_T)((rtb_Switch[i1] + 9.0) / 0.09375); The code generated for a conversion when you clear the check box follows: _fixptlowering0 = (rtb_Switch[i1] + 9.0) / 0.09375; _fixptlowering1 = fmod(_fixptlowering0 >= 0.0 ? floor(_fixptlowering0) : ceil(_fixptlowering0), 4.2949672960000000E+009); if(_fixptlowering1 < -2.1474836480000000E+009) { _fixptlowering1 += 4.2949672960000000E+009; } else if(_fixptlowering1 >= 2.1474836480000000E+009) { _fixptlowering1 -= 4.2949672960000000E+009; } cg_in_0_20_0[i1] = (int32_T)_fixptlowering1; The code generator applies the fmod function to handle out-of-range conversion results. 17-2 Optimize Code for Floating-Point to Integer Conversions Remove Code That Maps NaN to Integer Zero Selecting the Remove code from floating-point to integer conversions with saturation that maps NaN to zero check box in the Integer and fixed-point section of the Optimization pane causes the code generator to remove code that produces the same results as simulation when mapping from NaN to integer zero occurs. This action reduces the size and increases the speed of generated code at the cost of producing results that do not match simulation in the case of NaN values. For more information, see “Optimization Pane: General”. The code generated for a conversion when you select the check box follows: if (tmp < 2.147483648E+09) { if (tmp >= -2.147483648E+09) { tmp_0 = (int32_T)tmp; } else { tmp_0 = MIN_int32_T; } } else { tmp_0 = MAX_int32_T; } The code generated for a conversion when you clear the check box follows: if (tmp < 2.147483648E+09) { if (tmp >= -2.147483648E+09) { tmp_0 = (int32_T)tmp; } else { tmp_0 = MIN_int32_T; } } else if (tmp >= 2.147483648E+09) { tmp_0 = MAX_int32_T; } else { tmp_0 = 0; } 17-3 17 Defensive Programming Disable Nonfinite Checks or Inlining for Math Functions When Simulink Coder software generates code for math functions, • If the model option Support non-finite numbers is selected, nonfinite number checking is generated uniformly for math functions, without the ability to specify that nonfinite number checking should be generated for some functions, but not for others. • By default, inlining is applied uniformly for math functions, without the ability to specify that inlining should be generated for some functions, while invocations should be generated for others. You can use code replacement library (CRL) customization entries to: • Selectively disable nonfinite checks for math functions. This can improve the execution speed of the generated code. • Selectively disable inlining of math functions. This can increase code readability and decrease code size. The functions for which these customizations are supported include the following: • Floating-point only: atan2, ceil, copysign, fix, floor, hypot, log, log10, round, sincos, and sqrt • Floating-point and integer: abs, max, min, mod, rem, saturate, and sign The general workflow for disabling nonfinite number checking and/or inlining is as follows: 1 If you can disable nonfinite number checking for a particular math function, or if you want to disable inlining for a particular math function and instead generate a function invocation, you can copy the following MATLAB function code into a MATLAB file with an .m file name extension, for example, crl_table_customization.m. function hTable = crl_table_customization % Create an instance of the Code Replacement Library table for controlling 17-4 Disable Nonfinite Checks or Inlining for Math Functions % function intrinsic inlining and nonfinite support hTable = RTW.TflTable; % Inline - true (if function needs to be inline) % false (if function should not be inlined) % SNF (support nonfinite) - ENABLE (if non-finite checking should be performed) % DISABLE (if non-finite checking should NOT be performed) % UNSPECIFIED (Default behavior) % registerCustomizationEntry(hTable, ... % Priority, numInputs, key, inType, outType, Inline, SNF); registerCustomizationEntry(hTable, ... 100, 2, 'atan2', 'double', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'atan2', 'single', 'single', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sincos', 'double', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sincos', 'single', 'single', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'abs', 'double', 'double', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'abs', 'single', 'single', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'abs', 'int32', 'int32', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'abs', 'int16', 'int16', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'abs', 'int8', 'int8', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'abs', 'integer','integer',true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'abs', 'uint32', 'uint32', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'abs', 'uint16', 'uint16', true, 'UNSPECIFIED'); 17-5 17 Defensive Programming registerCustomizationEntry(hTable, ... 100, 1, 'abs', 'uint8', 'uint8', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'hypot', 'double', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'hypot', 'single', 'single', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'log', 'double', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'log', 'single', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'log10', 'double', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'log10', 'single', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'min', 'double', 'double', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'min', 'single', 'single', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'min', 'int32', 'int32', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'min', 'int16', 'int16', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'min', 'int8', 'int8', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'min', 'uint32', 'uint32', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'min', 'uint16', 'uint16', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'min', 'uint8', 'uint8', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'min', 'integer','integer',true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'max', 'double', 'double', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 17-6 Disable Nonfinite Checks or Inlining for Math Functions 100, 2, 'max', 'single', 'single', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'max', 'int32', 'int32', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'max', 'int16', 'int16', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'max', 'int8', 'int8', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'max', 'uint32', 'uint32', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'max', 'uint16', 'uint16', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'max', 'uint8', 'uint8', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'max', 'integer','integer',true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'mod', 'double', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'mod', 'single', 'single', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'mod', 'int32', 'int32', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'mod', 'int16', 'int16', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'mod', 'int8', 'int8', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'mod', 'uint32', 'uint32', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'mod', 'uint16', 'uint16', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'mod', 'uint8', 'uint8', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'rem', 'double', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'rem', 'single', 'single', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'rem', 'int32', 'int32', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 17-7 17 Defensive Programming 100, 2, 'rem', 'int16', 'int16', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'rem', 'int8', 'int8', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'rem', 'uint32', 'uint32', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'rem', 'uint16', 'uint16', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 2, 'rem', 'uint8', 'uint8', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'round', 'double', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'round', 'single', 'single', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 3, 'saturate', 'double', 'double', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 3, 'saturate', 'single', 'single', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 3, 'saturate', 'int32', 'int32', true, 'UNSPECIFIED'); 'int16', true, 'UNSPECIFIED'); 'int8', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 3, 'saturate', 'int16', registerCustomizationEntry(hTable, ... 100, 3, 'saturate', 'int8', registerCustomizationEntry(hTable, ... 100, 3, 'saturate', 'uint32', 'uint32', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 3, 'saturate', 'uint16', 'uint16', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 3, 'saturate', 'uint8', 'uint8', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 3, 'saturate', 'integer','integer',true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sign', 'double', 'double', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sign', 'single', 'single', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sign', 'int32', 17-8 'integer', true, 'UNSPECIFIED'); Disable Nonfinite Checks or Inlining for Math Functions registerCustomizationEntry(hTable, ... 100, 1, 'sign', 'int16', 'integer', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sign', 'int8', 'integer', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sign', 'uint32', 'uint32', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sign', 'uint16', 'uint16', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sign', 'uint8', 'uint8', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sign', 'integer','integer', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sqrt', 'double', 'double', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'sqrt', 'single', 'single', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'ceil', 'double', 'double', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'ceil', 'single', 'single', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'floor', 'double', 'double', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'floor', 'single', 'single', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'fix', 'double', 'double', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'fix', 'single', 'single', false, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'copysign', 'double', 'double', true, 'UNSPECIFIED'); registerCustomizationEntry(hTable, ... 100, 1, 'copysign', 'single', 'single', true, 'UNSPECIFIED'); 17-9 17 Defensive Programming 2 To reduce the size of the file, you can delete the registerCustomizationEntry lines for functions for which the default nonfinite number checking and inlining behavior is acceptable. 3 For each remaining entry, • Set the Inline argument to true if the function should be inlined or false if it should not be inlined. • Set the SNF argument to ENABLE if nonfinite checking should be generated, DISABLE if nonfinite checking should not be generated, or UNSPECIFIED to accept the default behavior based on the model option settings. Save the file. 4 Optionally, perform a quick check of the syntactic validity of the customization table entries by invoking the table definition file at the MATLAB command line (>> tbl = crl_table_customization). Fix syntax errors that are flagged. 5 Optionally, view the customization table entries in the Code Replacement Viewer (>> RTW.viewTfl(crl_table_customization)). For more information about viewing CRL tables, see “Selecting and Viewing Code Replacement Libraries” on page 9-61. 6 To register these changes and make them appear in the Code replacement library drop-down list located on the Code Generation > Interface pane of the Configuration Parameters dialog box, first copy the following MATLAB function code into an instance of the file sl_customization.m. Note For the RTW.TflRegistry instantiation shown below, specify the argument 'RTW' if a GRT target is selected for your model, otherwise omit the argument. function sl_customization(cm) % sl_customization function to register a code replacement library (CRL) % Register the CRL defined in local function locCrlRegFcn cm.registerTargetInfo(@locCrlRegFcn); 17-10 Disable Nonfinite Checks or Inlining for Math Functions end % End of SL_CUSTOMIZATION % Local function to define a CRL containing crl_table_customization function thisCrl = locCrlRegFcn % Instantiate a CRL registry entry - specify 'RTW' for GRT thisCrl = RTW.TflRegistry('RTW'); % Define the CRL properties thisCrl.Name = 'CRL Customization Example'; thisCrl.Description = 'Example of CRL Customization'; thisCrl.TableList = {'crl_table_customization'}; thisCrl.BaseTfl = 'C89/C90 (ANSI)'; thisCrl.TargetHWDeviceType = {'*'}; end % End of LOCCRLREGFCN You can edit the Name field to determine what CRL name will appear in the Code replacement library drop-down list. Also, the file name in the TableList field must match the name of the file you created in step 1. To register your changes, with both of the MATLAB files you created present in the MATLAB path, enter the following command in the MATLAB Command Window: sl_refresh_customizations 7 Create or open a model that will generate function code corresponding to one of the math functions for which you specified a change in nonfinite number checking or inlining behavior. 8 Open the Configuration Parameters dialog box, go to the Code Generation > Interface pane, and use the Code replacement library drop-down list to select the CRL entry you registered in step 6, for example, CRL Customization Example. 9 Generate code for the model and examine the generated code to verify that the math functions are generated as expected. 17-11 17 17-12 Defensive Programming 18 Data Copy Reduction • “Optimizing Generated Code” on page 18-2 • “Generate Code Without Buffer Optimization” on page 18-4 • “Generate Code With Buffer Optimization” on page 18-9 • “Minimize Computations and Storage for Intermediate Results” on page 18-11 • “Declare Signals as Local Function Data” on page 18-17 • “Inline Invariant Signals” on page 18-18 18 Data Copy Reduction Optimizing Generated Code In this section... “About Optimizing Generated Code” on page 18-2 “Setting Up the Model” on page 18-2 About Optimizing Generated Code This section shows how to configure optimizations and generate code for a model. It shows the generated code before and after the optimizations are applied. Note You can view the code generated from this example using the MATLAB editor or by generating an HTML code generation report. For more information, see “Generate a Code Generation Report” on page 11-5. The example model used, example, is shown below. Setting Up the Model First, create the model from Simulink library blocks, and set up basic Simulink and Simulink Coder parameters as follows: 1 Create a folder, example_codegen, and make it your working folder: !mkdir example_codegen cd example_codegen 2 Create a new model and save it as example. 3 Add Sine Wave, Gain, and Out1 blocks to your model and connect them as shown in the preceding diagram. Label the signals as shown. 18-2 Optimizing Generated Code 4 Open Model Explorer by selecting Model Explorer from the model’s View menu. 5 In the Model Hierarchy pane, click the symbol preceding the model name to reveal its components. 6 Click Configuration (Active) in the left pane. 7 Select Solver in the center pane. The Solver pane appears at the right. 8 In the Solver Options pane: a Select Fixed-step in the Type field. b Select discrete (no continuous states) in the Solver field. c Specify 0.1 in the Fixed-step size field. (Otherwise, the Simulink Coder code generator posts a warning and supplies a default value when you generate code.) 9 Click Apply. 10 Click Data Import/Export in the center pane and make sure all check boxes in the right pane are cleared. Click Apply if you made any changes. 11 Select Code Generation in the center pane. Under Target Selection in the right pane, select the default generic real-time (GRT) target grt.tlc. 12 Select Generate code only at the bottom of the right pane. This option causes the Simulink Coder software to generate code and a make file, then stop at that point, rather than proceeding to invoke make to compile and link the code. Note that the label on the Build button changes to Generate code. 13 Click Apply. 14 Save the model. 18-3 18 Data Copy Reduction Generate Code Without Buffer Optimization With buffer optimizations Simulink Coder software generates code that reduces memory consumption and execution time. In this example, you disable the buffer optimizations to see what the nonoptimized generated code looks like: 1 Select Optimization in the center pane and click the Signals and Parameters tab in the right pane. The Signals and Parameters pane appears at the right. Clear the Signal storage reuse option, as shown below. Change other attributes to match the figure. Note Clearing the Signal storage reuse option disables the following options: • Enable local block outputs • Reuse block outputs • Eliminate superfluous local variables (expression folding) • Minimize data copies between local and global variables 2 Click Apply. 3 Select Code Generation in the center pane and click the Report tab on the right pane. The Report pane appears at the right. 18-4 Generate Code Without Buffer Optimization 4 Select the Create code generation report and Open report automatically check boxes. Selecting these check boxes makes the code generation report display after the build process completes. 5 Click Apply. 6 Select the General tab in the right pane and select Generate code only. 7 Click Generate code. Because you selected the Generate code only option, the Simulink Coder build process does not invoke your make utility. The code generation process ends with this message: ### Successful completion of build procedure for model: example 8 The generated code is in the build folder, example_grt_rtw. The file example_grt_rtw/example.c contains the output computation for the model. You can view this file in the code generation report by clicking the example.c link in the left pane. 9 In example.c, find the function example_output near the top of the file. The generated C code consists of procedures that implement the algorithms defined by your Simulink block diagram. The execution engine calls the procedures in succession as time moves forward. The modules that implement the execution engine and other capabilities are referred to collectively as the run-time interface modules. See the Simulink Coder User’s Guide for a complete discussion of how the Simulink Coder software interfaces and executes application, system-dependent, and system-independent modules, in each of the two styles of generated code. 18-5 18 Data Copy Reduction In code generated for example, the generated example_output function implements the actual algorithm for multiplying a sine wave by a gain. The example_output function computes the model’s block outputs. The run-time interface must call example_output at every time step. With buffer optimizations turned off, example_output assigns unique buffers to each block output. These buffers (rtB.sin_out, rtB.gain_out) are members of a global block I/O data structure, called in this code example_B and declared as follows: /* Block signals (auto storage) */ BlockIO_example example_B; The data type BlockIO_example is defined in example.h as follows: /* Block signals (auto storage) */ extern BlockIO_example example_B; The output code accesses fields of this global structure, as shown below: /* Model output function */ static void example_output(int_T tid) { /* Sin: ' /Sine Wave' */ example_B.sin_out = sin(example_P.SineWave_Freq * example_M->Timing.t[0] + example_P.SineWave_Phase) * example_P.SineWave_Amp + example_P.SineWave_Bias; /* Gain: ' /Gain' */ example_B.gain_out = example_P.Gain_Gain * example_B.sin_out; /* Outport: ' /Out1' */ example_Y.Out1 = example_B.gain_out; /* tid is required for a uniform function interface. * Argument tid is not used in the function. */ UNUSED_PARAMETER(tid); } 18-6 Generate Code Without Buffer Optimization 10 In GRT targets such as this, the function example_output is called by a wrapper function, MdlOutputs. In example.c, find the function MdlOutputs near the end. It looks like this: void MdlOutputs(int_T tid) { example_output(tid); } Note In previous releases, MdlOutputs was the actual output function for code generated by all GRT-configured models. It is now implemented as a wrapper function to provide greater compatibility among different target configurations. 18-7 18 18-8 Data Copy Reduction Generate Code With Buffer Optimization Generate Code With Buffer Optimization With buffer optimizations, Simulink Coder software generates code that reduces memory consumption and execution time. In this example, you turn buffer optimizations on and observe how they improve the code. Enable signal buffer optimizations and regenerate the code as follows: 1 Change your current working folder to example_codegen if you have not already done so. 2 In Model Explorer, select Optimization in the center pane and click the Signals and Parameters tab on the right pane. The Signals and Parameters pane appears at the right. Select the Signal storage reuse option. 3 Note that the following parameters become enabled in the Code generation section: • Enable local block outputs • Reuse block outputs • Eliminate superfluous local variables (expression folding) • Minimize data copies between local and global variables Make sure that Enable local block outputs, Reuse block outputs, and Minimize data copies between local and global variables are selected, and that Eliminate superfluous local variables (expression folding) is cleared, as shown below. 18-9 18 Data Copy Reduction You will observe the effects of expression folding later in this example. Not performing expression folding allows you to see the effects of the buffer optimizations. 4 Click Apply to apply the new settings. 5 Select Code Generation in the center pane, and click Generate code on the right. As before, the Simulink Coder software generates code in the example_grt_rtw folder. The previously generated code is overwritten. 6 View example.c and examine the example_output function. With buffer optimizations enabled, the code in example_output reuses the example_Y.Out1 global buffer. /* Model output function */ static void example_output(int_T tid) { /* Sin: ' /Sine Wave' */ example_Y.Out1 = sin(example_P.SineWave_Freq * example_M->Timing.t[0] + example_P.SineWave_Phase) * example_P.SineWave_Amp + example_P.SineWave_Bias; /* Gain: ' /Gain' */ example_Y.Out1 = example_P.Gain_Gain * example_Y.Out1; /* tid is required for a uniform function interface. * Argument tid is not used in the function. */ UNUSED_PARAMETER(tid); } This code is more efficient in terms of memory usage and execution speed. By eliminating a global variable and a data copy instruction, the data section is smaller and the code is smaller and faster. The efficiency improvement gained by selecting Enable local block outputs, Reuse block outputs, and Minimize data copies between local and global variables is more significant in a large model with many signals. 18-10 Minimize Computations and Storage for Intermediate Results Minimize Computations and Storage for Intermediate Results In this section... “About Expression Folding” on page 18-11 “Expression Folding Example” on page 18-12 “Enable Expression Folding” on page 18-15 About Expression Folding Expression folding is a code optimization technique that minimizes the computation of intermediate results at block outputs and the storage of such results in temporary buffers or variables. Eliminate superfluous local variables (expression folding) is used to enable expression folding. When expression folding is on, the Simulink Coder code generator collapses, or “folds,” block computations into a single expression, instead of generating separate code statements and storage declarations for each block in the model. Expression folding can dramatically improve the efficiency of generated code, frequently achieving results that compare favorably to hand-optimized code. In many cases, entire groups of model computations fold into a single highly optimized line of code. By default, expression folding is on. The Simulink Coder code generation options are configured to use expression folding wherever possible. Most Simulink blocks support expression folding. You can also take advantage of expression folding in your own inlined S-function blocks. See “Write S-Functions That Support Expression Folding” on page 14-91 for information on how to do this. In the code generation examples that follow, the Signal storage reuse optimizations (Enable local block outputs, Reuse block outputs, Eliminate superfluous local variables (expression folding) and Minimize data copies between local and global variables) are all turned on. 18-11 18 Data Copy Reduction Expression Folding Example As a simple example of how expression folding affects the code generated from a model, consider the following model. With expression folding on, this model generates a single-line output computation, as shown in this model_output function. static void exprfld_output(int_T tid) { /* Outport: ' /Out1' incorporates: * Gain: ' /k1' * Gain: ' /k2' * Inport: ' /In1 * Inport: ' /In2 * Product: ' /Product' */ exprfld_Y.Out1 = exprfld_U.i1 * exprfld_P.k1_Gain * (exprfld_U.i2 * exprfld_P.k2_Gain); } The generated comments indicate the block computations that were combined into a single expression. The comments also document the block parameters that appear in the expression. With expression folding off, the same model computes temporary results for both Gain blocks before the final output, as shown in this output function: static void exprfld_output(int_T tid) 18-12 Minimize Computations and Storage for Intermediate Results { real_T rtb_S2; /* Gain: ' /k1' incorporates: * Inport: ' /In1' */ exprfld_Y.Out1 = exprfld_U.i1 * exprfld_P.k1_Gain /* Gain: ' /k2' incorporates: * Inport: ' /In2' */ rtb_S2 = exprfld_U.i2 * exprfld_P.k2_Gain; /* Product: ' /Product' */ exprfld_Y.Out1 = exprfld_Y.Out1 * rtb_S2; } Turn on expression folding, a code optimization technique that minimizes the computation of intermediate results and the use of temporary buffers or variables. Enable expression folding and regenerate the code as follows: 1 Change your current working folder to example_codegen if you have not already done so. 2 In Model Explorer, select Optimization in the center pane and click the Signals and Parameters tab on the right pane. The Signals and Parameters pane appears at the right. 18-13 18 Data Copy Reduction 3 Select the Eliminate superfluous local variables (expression folding) option. 4 Click Apply. 5 Select Code Generation in the center pane, and click Generate code on the right. The Simulink Coder software generates code as before. 6 View example.c and examine the function example_output. In the previous examples, the Gain block computation was computed in a separate code statement and the result was stored in a temporary location before the final output computation. With Eliminate superfluous local variables (expression folding) selected, there is a subtle but significant difference in the generated code: the gain computation is incorporated (or folded) directly into the Outport computation, eliminating the temporary location and separate code statement. This computation is on the last line of the example_output function. /* Model output function */ static void example_output(int_T tid) { /* Outport: ' /Out1' incorporates: 18-14 * Gain: ' /Gain' * Sin: ' /Sine Wave' Minimize Computations and Storage for Intermediate Results */ example_Y.Out1 = (sin(example_P.SineWave_Freq * example_M->Timing.t[0] + example_P.SineWave_Phase) * example_P.SineWave_Amp + example_P.SineWave_Bias) * example_P.Gain_Gain; /* tid is required for a uniform function interface. * Argument tid is not used in the function. */ UNUSED_PARAMETER(tid); } In many cases, expression folding can incorporate entire model computations into a single, highly optimized line of code. Expression folding is turned on by default. Using this option will improve the efficiency of generated code. For an example of expression folding in the context of a more complex model, click rtwdemo_slexprfold , or type the following command at the MATLAB prompt. rtwdemo_slexprfold Enable Expression Folding Expression folding operates only on expressions involving local variables. Expression folding is therefore available only when the Signal storage reuse code generation option is on. For a new model, default code generation options are set to use expression folding. If you are configuring an existing model, enable expression folding as follows: 1 Open the Configuration Parameters dialog box and select the Optimization > Signals and Parameters pane. 2 Select the Signal storage reuse check box. 3 Select the Enable local block outputs check box. 4 Select the Reuse block outputs check box. 5 Select the Minimize data copies between local and global variables check box. 18-15 18 Data Copy Reduction 6 Enable expression folding by selecting Eliminate superfluous local variables (expression folding). All expression folding related options are now selected. 7 Click Apply. 18-16 Declare Signals as Local Function Data Declare Signals as Local Function Data To declare block signals locally in functions instead of being declared globally (when possible), select the Enable local block outputs configuration parameter. This parameter is available only when you select Signal storage reuse. For more information on the use of the Enable local block outputs option, see “Signals” on page 7-52. 18-17 18 Data Copy Reduction Inline Invariant Signals An invariant signal is a block output signal that does not change during Simulink simulation. For example, the signal S3 in this block diagram is an invariant signal. For the previous model, if you select Inline invariant signals on the Optimization > Signals and Parameters pane, the Simulink Coder code generator inlines the invariant signal S3 in the generated code. Note that an invariant signal is not the same as an invariant constant. In the preceding example, the two constants (1 and 2) and the gain value of 3 are invariant constants. To inline these invariant constants, select Inline parameters. Note If your model contains Model blocks, Inline parameters must be on for all referenced models. If a referenced model does not have Inline Parameters set to on, the Simulink engine temporarily enables this option while generating code for the referenced model, then turns it off again when the build completes. Thus the referenced model is left in its previous state and need not be resaved. For the top model, Inline parameters can be either on or off. 18-18 19 Execution Speed • “Inline Parameters” on page 19-2 • “Configure Loop Unrolling Threshold” on page 19-4 • “Optimize Code Generated for Vector Assignments” on page 19-6 • “Generate Target Optimizations Within Algorithm Code” on page 19-10 19 Execution Speed Inline Parameters When you select the Inline parameters configuration parameter: • The Simulink Coder code generator uses the numerical values of model parameters, instead of their symbolic names, in generated code. If the value of a parameter is a workspace variable, or an expression including one or more workspace variables, the variable or expression is evaluated at code generation time. The hard-coded result value appears in the generated code. An inlined parameter, because it has in effect been transformed into a constant, is no longer tunable. That is, it is not visible to externally written code, and its value cannot be changed at runtime. • The Configure button becomes enabled. Clicking the Configure button opens the Model Parameter Configuration dialog box. The Model Parameter Configuration dialog box lets you remove individual parameters from inlining and declare them to be tunable variables (or global constants). When you declare a parameter tunable, the Simulink Coder product generates a storage declaration that allows the parameter to be interfaced to externally written code. This enables your hand-written code to change the value of the parameter at run-time. The Model Parameter Configuration dialog box lets you improve overall efficiency by inlining most parameters, while at the same time retaining the flexibility of run-time tuning for selected parameters. See “Parameters” on page 7-10 for more information on interfacing parameters to externally written code. Inline parameters also instructs the Simulink engine to propagate constant sample times. The engine computes the output signals of blocks that have constant sample times once during model startup. This improves performance because such blocks do not compute their outputs at every time step of the model. You can select the Inline invariant signals code generation option (which also places constant values in generated code) only when Inline parameters is on. See “Inline Invariant Signals” on page 18-18. 19-2 Inline Parameters Referenced Models When a top model uses referenced models or if a model is referenced by another model: • All referenced models must specify Inline parameters to be on • The top model can specify Inline parameters to be on or off. When the top model specifies Inline parameters to be on, you cannot use the Model Parameter Configuration dialog box to tune parameters that are passed to referenced models. To tune such parameters, you must declare them in the referenced model’s workspace, and then pass run-time values (or expressions) for them in argument lists specified for each Model block that references that model. For more information, see “Using Model Arguments”. 19-3 19 Execution Speed Configure Loop Unrolling Threshold The Loop unrolling threshold parameter on the Optimization > Signals and Parameters pane determines when a wide signal or parameter should be wrapped into a for loop and when it should be generated as a separate statement for each element of the signal. The default threshold value is 5. For example, consider the model below: The gain parameter of the Gain block is the vector myGainVec. Assume that the loop unrolling threshold value is set to the default, 5. If myGainVec is declared as myGainVec = [1:10]; 19-4 Configure Loop Unrolling Threshold an array of 10 elements, myGainVec_P.Gain_Gain[], is declared within the Parameters_model data structure. The size of the gain array exceeds the loop unrolling threshold. Therefore, the code generated for the Gain block iterates over the array in a for loop, as shown in the following code: { int32_T i1; /* Gain: ' /Gain' */ for(i1=0; i1<10; i1++) { myGainVec_B.Gain_f[i1] = rtb_foo * myGainVec_P.Gain_Gain[i1]; } } If myGainVec is declared as myGainVec = [1:3]; an array of three elements, myGainVec_P.Gain_Gain[], is declared within the Parameters data structure. The size of the gain array is below the loop unrolling threshold. The generated code consists of inline references to each element of the array, as in the code below. /* Gain: ' /Gain' */ myGainVec_B.Gain_f[0] = rtb_foo * myGainVec_P.Gain_Gain[0]; myGainVec_B.Gain_f[1] = rtb_foo * myGainVec_P.Gain_Gain[1]; myGainVec_B.Gain_f[2] = rtb_foo * myGainVec_P.Gain_Gain[2]; See “Explore Variable Names and Loop Rolling” for more information on loop rolling. Note When a model includes Stateflow charts or MATLAB Function blocks, you can apply a set of Stateflow optimizations on the Optimization > Stateflow pane. The settings you select for the Stateflow options also apply to all MATLAB Function blocks in the model. This is because the MATLAB Function blocks and Stateflow charts are built on top of the same technology and share a code base. You do not need a Stateflow license to use MATLAB Function blocks. 19-5 19 Execution Speed Optimize Code Generated for Vector Assignments In this section... “Configure Model to Optimize Code Generated for Vector Assignments” on page 19-6 “Optimize Code Generated for Vector Assignments Using memcpy” on page 19-7 Configure Model to Optimize Code Generated for Vector Assignments The Use memcpy for vector assignment option lets you optimize generated code for vector assignments by replacing for loops with memcpy function calls. The memcpy function can be more efficient than for-loop controlled element assignment for large data sets. Where memcpy offers improved execution speed, you can also use this model option to specify that the generated code use memcpy when assigning a vector signal. Selecting the Use memcpy for vector assignment option enables the associated parameter Memcpy threshold (bytes), which allows you to specify the minimum array size in bytes for which memcpy function calls should replace for loops in the generated code. For more information, see “Use memcpy for vector assignment” and “Memcpy threshold (bytes)”. In considering whether to use this optimization, • Verify that your target supports the memcpy function. • Determine whether your model uses signal vector assignments (such as Y=expression) to move large amounts of data, for example, using the Selector block. To apply this optimization, 1 Consider first generating code without this optimization and measuring its execution, to establish a baseline for evaluating the optimized assignment. 2 Select Use memcpy for vector assignment and examine the setting of Memcpy threshold (bytes), which by default specifies 64 bytes as the 19-6 Optimize Code Generated for Vector Assignments minimum array size for which for loops are replaced with memcpy function calls. Based on the array sizes used in your application’s signal vector assignments, and any target environment considerations that might bear on the threshold selection, accept the default or specify another array size. 3 Generate code, and measure its execution speed against your baseline or previous iterations. Iterate on steps 2 and 3 until you achieve an optimal result. Note The memcpy optimization may not occur under certain conditions, including when other optimizations have a higher precedence than the memcpy optimization, or when the generated code is originating from Target Language Compiler (TLC) code, such as a TLC file associated with an S-function block. Note If you are licensed for Embedded Coder software, you can use a code replacement library (CRL) to provide your own custom implementation of the memcpy function to be used in generated model code. For more information, see “Map memcpy Function to Target-Specific Implementations”. Optimize Code Generated for Vector Assignments Using memcpy To examine the effect on generated vector assignment code of using the Use memcpy for vector assignment option, perform the following steps: 1 Create a model that generates signal vector assignments. For example, a Use In, Out, and Mux blocks to create the following model. b Select the diagram and use Edit > Subsystem to make it a subsystem. 19-7 19 Execution Speed c Open Model Explorer and configure the Signal Attributes for the In1, In2, and In3 source blocks. For each, set Port dimensions to [1,100], and set Data type to int32. Apply the changes. d Go to the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box and clear the Use memcpy for vector assignment option. Apply the changes and save the model. In this example, the model is saved to the name vectorassign. 2 Go to the Code Generation > Report pane of the Configuration Parameters dialog box and select the Create code generation report. Then go to the Code Generation pane, select the Generate code only option, and generate code for the model. When code generation completes, the HTML code generation report is displayed. 3 In the HTML code generation report, click on the vectorassign.c section and inspect the model output function. Notice that the vector assignments are implemented using for loops. /* Model output function */ static void vectorassign_output(void) { int32_T i; /* Outport: ' /Out1' incorporates: * Inport: ' /In1' * Inport: ' /In2' * Inport: ' /In3' */ for (i = 0; i < 100; i++) { vectorassign_Y.Out1[i] = vectorassign_U.In2[i]; } for (i = 0; i < 100; i++) { vectorassign_Y.Out1[i + 100] = vectorassign_U.In3[i]; 19-8 Optimize Code Generated for Vector Assignments } for (i = 0; i < 100; i++) { vectorassign_Y.Out1[i + 200] = vectorassign_U.In1[i]; } /* End of Outport: ' /Out1' */ 4 Go to the Optimization > Signals and Parameters pane of the Configuration Parameters dialog box and select the Use memcpy for vector assignment option. Leave the Memcpy threshold (bytes) option at its default setting of 64 Apply the changes and regenerate code for the model. When code generation completes, the HTML code generation report again is displayed. 5 In the HTML code generation report, click on the vectorassign.c section and inspect the model output function. Notice that the vector assignments now are implemented using memcpy function calls. /* Model output function */ static void vectorassign_output(void) { int32_T i; /* Outport: ' /Out1' incorporates: * Inport: ' /In1' * Inport: ' /In2' * Inport: ' /In3' */ memcpy(&vectorassign_Y.Out1[0], &vectorassign_U.In2[0], 100U * sizeof(int32_T)); memcpy(&vectorassign_Y.Out1[100], &vectorassign_U.In3[0], 100U * sizeof(int32_T)); memcpy(&vectorassign_Y.Out1[200], &vectorassign_U.In1[0], 100U * sizeof(int32_T)); } 19-9 19 Execution Speed Generate Target Optimizations Within Algorithm Code Some application components are hardware-specific and cannot simulate on a host system. For example, consider a component that includes pragmas and assembly code for enabling hardware instructions for saturate on add operations or a Fast Fourier Transform (FFT) function. The following table lists integration options to customize generated algorithm code with target-specific optimizations. Note Solutions marked with EC only require an Embedded Coder license. 19-10 If... Then... For More Information, See You want to optimize target performance (speed and memory) of model code by replacing default math functions and operators with target-specific code EC only— Implement function and operator replacements by using the code replacement library (CRL) API, Code Replacement Tool, and Code Replacement Viewer to create, examine, validate, and register hardware-specific replacement tables • rtwdemo_crl_script You want to control how code generation technology declares, stores, and represents signals, tunable parameters, block states, and data objects in generated code EC only—Design (create) and apply custom storage classes • “Introduction to Code Replacement Libraries” • rtwdemo_cscpredef • rtwdemo_importstruct • rtwdemo_advsc • “Custom Storage Classes” Generate Target Optimizations Within Algorithm Code Note To simulate an algorithm that includes target-specific elements in a host environment, you must create code that is equivalent to the target code and can run in the host environment. 19-11 19 19-12 Execution Speed 20 Memory Usage • “Minimize Memory Requirements During Code Generation” on page 20-2 • “Implement Logic Signals as Boolean Data” on page 20-3 • “Reduce Memory Requirements for Signals” on page 20-4 • “Reuse Memory Allocated for Signals” on page 20-5 • “Use Stack Space Allocation” on page 20-6 20 Memory Usage Minimize Memory Requirements During Code Generation When the Simulink Coder product generates code, it creates an intermediate representation of your model (called model.rtw), which the Target Language Compiler parses to transform block computations, parameters, signals, and constant data into a high-level language, (for example, C). Parameters and data are normally copied into the model.rtw file, whether they originate in the model itself or come from variables or objects in a workspace. Models which have large amounts of parameter and constant data (such as lookup tables) can tax memory resources and slow down code generation because of the need to copy their data to model.rtw. You can improve code generation performance by limiting the size of data that is copied by using a set_param command, described below. Data vectors such as those for parameters, lookup tables, and constant blocks whose sizes exceed a specified value are not copied into the model.rtw file. In place of the data vectors, the code generator places a special reference key in the intermediate file that enables the Target Language Compiler to access the data directly from the Simulink software and format it directly into the generated code. This results in maintaining only one copy of large data vectors in memory. You can specify the maximum number of elements that a parameter or other data source can have for the Simulink Coder code generator to represent it literally in the model.rtw file. Whenever this threshold size is exceeded, the product writes a reference to the data to the model.rtw file, rather than its values. The default threshold value is 10 elements, which you can verify with get_param(0, 'RTWDataReferencesMinSize') To set the threshold to a different value, type the following set_param function in the MATLAB Command Window: set_param(0, 'RTWDataReferencesMinSize', ) Provide an integer value for size that specifies the number of data elements above which reference keys are to be used in place of actual data values. 20-2 Implement Logic Signals as Boolean Data Implement Logic Signals as Boolean Data When you select the Implement logic signals as Boolean data (vs. double) check box, blocks that generate logic signals output Boolean signals. When you clear this check box, blocks that generate logic signals output double signals. The check box is selected by default because it reduces memory requirements (a Boolean signal typically requires one byte in memory while a double signal requires eight bytes in memory). Clear this check box for compatibility with models created using earlier versions of Simulink that support only double signals. For details about this check box, see “Implement logic signals as Boolean data (vs. double)”. 20-3 20 Memory Usage Reduce Memory Requirements for Signals To instruct the Simulink Coder code generator to reuse signal memory, which can reduce memory requirements of your real-time program, select the configuration parameter Signal storage reuse. Disabling Signal storage reuse makes all block outputs global and unique, which in many cases significantly increases RAM and ROM usage. For more details on the Signal storage reuse option, see “Signals” on page 7-52. Note Selecting Signal storage reuse also enables the Enable local block outputs, Reuse block outputs, Eliminate superfluous local variables (expression folding), and Minimize data copies between local and global variables options on the Optimization > Signals and Parameters pane. See “Declare Signals as Local Function Data” on page 18-17 and “Reuse Memory Allocated for Signals” on page 20-5. 20-4 Reuse Memory Allocated for Signals Reuse Memory Allocated for Signals Two parameters provide the capability to reuse memory allocated for signals: Reuse block output and Minimize data copies between local and global variables. Selecting Reuse block output directs the code generator to reuse signal memory. When Reuse block output is cleared, signals are stored in unique locations. Reuse block output is enabled only when you select Signal storage reuse. Selecting Minimize data copies between local and global variables reuses existing global variables to store temporary results. Clearing Minimize data copies between local and global variables writes data for block outputs to local variables. You must select Signal storage reuse to enable Minimize data copies between local and global variables. See “Signals” on page 7-52 for more information (including generated code example) on Reuse block output, Minimize data copies between local and global variables, and other signal storage options. 20-5 20 Memory Usage Use Stack Space Allocation Your application might be constrained by limited memory. Controlling the maximum allowable size for the stack is one way to modify whether data is defined as local or global in the generated code. You can limit the use of stack space by specifying a positive integer value for the “Maximum stack size (bytes)” parameter, on the Optimization > Signals and Parameters pane of the Configuration parameter dialog box. Specifying the maximum allowable stack size provides control over the number of local and global variables in the generated code. Specifically, lowering the maximum stack size might generate more variables into global structures. The number of local and global variables help determine the required amount of stack space for execution of the generated code. The default setting for “Maximum stack size (bytes)” is Inherit from target. In this case, the value of the maximum stack size is the smaller value of the following: the default value set by the Simulink Coder software (200,000 bytes) or the value of the TLC variable MaxStackSize found in the system target file (ert.tlc). To specify a smaller stack size for your application, select the Specify a value option of the Maximum stack size (bytes) parameter and enter a positive integer value. To specify a smaller stack size at the command line, use: set_param(model_name, 'MaxStackSize', 65000); Note For overall executable stack usage metrics, you might want to do a target-specific measurement, such as using runtime (empirical) analysis or static (code path) analysis with object code. It is recommended that you use the Maximum stack size (bytes) parameter to control stack space allocation instead of modifying the TLC variable, MaxStackSize, in the system target file. However, a target author might want to set the TLC variable, MaxStackSize, for a target. To set MaxStackSize, use assign statements in the system target file (ert.tlc), as in the following example. 20-6 Use Stack Space Allocation %assign MaxStackSize = 4096 Write your %assign statements in the Configure RTW code generation settings section of the system target file. The %assign statement is described in “Target Language Compiler”. 20-7 20 20-8 Memory Usage Verification 21 Simulation and Code Comparison • “Comparing Output Data” on page 21-2 • “Configure Signal Data for Logging” on page 21-3 • “Log Simulation Data” on page 21-5 • “Log Data from the Generated Program” on page 21-7 • “Compare Numerical Results” on page 21-9 21 Simulation and Code Comparison Comparing Output Data This example shows you how to verify the answers computed by code generated from the sldemo_f14 model. It shows how to capture two sets of output data and compare the sets. Simulating the model produces one set of output data. Executing the generated code produces a second set of output data. Note To obtain a valid comparison between the outputs of the model and the generated code , use the same Solver options and the same Step size for both the simulation run and the build process. You must configure the model to save simulation time. For an example, see “Configure Signal Data for Logging” on page 21-3. 21-2 Configure Signal Data for Logging Configure Signal Data for Logging Configure the model for logging and recording signal data. 1 Make sure that sldemo_f14 is closed. Clear the MATLAB workspace to eliminate the results of previous simulation runs. At the MATLAB prompt, type: clear The clear operation clears variables created during previous simulations and all workspace variables, some of which are standard variables that the sldemo_f14 model requires. 2 Open the model by entering sldemo_f14 at the MATLAB command line. 3 In the model window, choose File > Save As, navigate to the working folder, and save a copy of the sldemo_f14 model as myf14. 4 Set up your model to log signal data for signals: Stick, alpha,rad, and NzPilot,g. For each signal, follow these steps. a Right-click the signal and select Properties from the context menu. b In the Signal Properties dialog box, select Log signal Data. c In the Logging name section, in the drop-down list, select Custom. In the field, enter the logging name for the corresponding signal. Signal Name Logging Name Stick Stick_input alpha,rad Angle_of_attack NzPilot,g Pilot_G_force d Click Apply and OK. For information on how to log signal data, see “Export Signal Data Using Signal Logging”. 5 Select Simulation > Model Configuration Parameters to open the Configuration Parameters dialog box. 21-3 21 Simulation and Code Comparison 6 Select the Solver pane. In the Solver options section, specify the Type parameter as Fixed-step. 7 On the Data Import/Export pane: • Specify the Format parameter as Structure with time. • Select the Signal logging parameter. • Select the Record and inspect simulation output parameter. When you select this parameter, on the Simulink Editor window, the Record button is now on. 8 Save the model. Proceed to “Log Simulation Data” on page 21-5. 21-4 Log Simulation Data Log Simulation Data Run the simulation, log the signal data, and view the data in the Simulation Data Inspector. 1 Run the model. When the simulation is done, the Simulation Data Inspector opens. You can also open the Simulation Data Inspector from the Simulink Editor toolbar. Click the Record button arrow, and select Simulation Data Inspector. 2 Right-click Run1: myf14. In the context menu, select Group Signals. Specify the Group Signals settings. myf14 expander to view the logged variables. Then click the logsout expander and then the expanders for each logged signal. 3 Click the Run1: 4 On the right pane, on the View toolbar, click Show Details. 5 In the Layout column, click the field that displays 1x1. A plot matrix opens. To create a view of 4 plots, select the 2x2 matrix. 6 Select Hide Details. 7 For each signal: a Click a plot, which will then show a blue border. b Select the check box next to a logged signal name. 21-5 21 Simulation and Code Comparison The next task is to “Log Data from the Generated Program” on page 21-7. 21-6 Log Data from the Generated Program Log Data from the Generated Program Because you have modified the model, you must rebuild and run the myf14 executable to obtain a valid data file. 1 Select Simulation > Model Configuration Parameters to open the Configuration Parameters dialog box. 2 Select the Code Generation > Interface pane. 3 Set the MAT-file variable name modifier menu to rt_. Doing so prefixes rt_ to each variable that you selected to be logged in the first part of this example. 4 Click Apply and OK. 5 Save the model. 6 To generate code, on the Simulink Editor toolbar, click the Build Model button. Status messages in the MATLAB Command Window track the build process. 7 When the build is finished, run the standalone program from MATLAB. !myf14 The executing program writes the following messages to the MATLAB Command Window. ** starting the model ** ** created myf14.mat ** 8 Load the data file myf14.mat. load myf14 9 To view the two execution outputs, alpha,rad and NzPilot,g, import the data into the Simulation Data Inspector: a In the Simulation Data Inspector, select File > Import Data to open the Data Import dialog box. 21-7 21 Simulation and Code Comparison b Specify Import from as Base workspace. Specify Import to as New run. c Click Clear All to clear all of the check boxes. Select the check box for data where the Time Series Root is rt_yout and the Block Path is myf14/alpha,rad and myf14/NzPilot,g. d Click OK. The selected data is now under Run2: Imported_Data. 10 On the Inspect Signals tab, you can view this data by selecting the Plot button for each output. Proceed to “Compare Numerical Results” on page 21-9. 21-8 Compare Numerical Results Compare Numerical Results You have now obtained data from a Simulink run of the model and from a run of the program generated from the model. In the Simulation Data Inspector, select the Compare Signals tab. Your comparison results might differ from these results. To compare alpha, rad, under Run 1, in the Sig 1 column, select Angle_of_attack. Under Run 2, in the Sig 2 column, select alpha, rad. The Signals plot shows the data. The difference is calculated and plotted in the Difference plot. To compare NzPilot,g, under Run 1, in the Sig 1 column, select Pilot_G_force. Under Run 2, in the Sig 2 column, select NzPilot,g. The Signals plot shows the data. 21-9 21 Simulation and Code Comparison Overall agreement is within 10-16. The means of residuals are an order of magnitude smaller. This slight error can be caused by many factors, including: • Different compiler optimizations • Statement ordering • Run-time libraries For example, a function call such as sin(2.0) might return a slightly different value depending on which C library you are using. Such variations can also cause differences between your results and these results. 21-10 Customization • Chapter 22, “Build Process Integration” • Chapter 23, “Run-Time Data Interface Extensions” • Chapter 24, “Custom Target Development” 22 Build Process Integration • “Control Build Process Compiling and Linking” on page 22-2 • “Cross-Compile Code Generated on Microsoft Windows” on page 22-4 • “Control Library Location and Naming During Build” on page 22-7 • “Recompile Precompiled Libraries” on page 22-12 • “Customize Post-Code-Generation Build Processing” on page 22-13 • “Configure Generated Code with TLC” on page 22-18 • “Customize Build Process with STF_make_rtw_hook File” on page 22-21 • “Customize Build Process with sl_customization.m” on page 22-28 • “Replace the STF_rtw_info_hook Mechanism” on page 22-33 • “Customize Build to Use Shared Utility Code” on page 22-34 22 Build Process Integration Control Build Process Compiling and Linking After generating code for a model, the Simulink Coder build process determines whether or not to compile and link an executable program. This decision is governed by the following: • Generate code only option When you select this option, the Simulink Coder software generates code for the model, including a makefile. • Generate makefile option When you clear this option, the Simulink Coder software does not generate a makefile for the model. You must specify any post code generation processing, including compilation and linking, as a user-defined command, as explained in “Customize Post-Code-Generation Build Processing” on page 22-13. • Makefile-only target The Microsoft Visual C++ Project Makefile versions of the grt, grt_malloc, and Embedded Coder target configurations generate a Visual C++ project makefile (model.mak). To build an executable, you must open model.mak in the Visual C++ IDE and compile and link the model code. • HOST template makefile variable The template makefile variable HOST identifies the type of system upon which your executable is intended to run. The variable can be set to one of three possible values: PC, UNIX, or ANY. By default, HOST is set to UNIX in template makefiles designed for use with The Open Group UNIX platforms (such as grt_unix.tmf), and to PC in the template makefiles designed for use with development systems for the PC (such as grt_vc.tmf). If the Simulink software is running on the same type of system as that specified by the HOST variable, then the executable is built. Otherwise, - 22-2 If HOST = ANY, an executable is still built. This option is useful when you want to cross-compile a program for a system other than the one the Simulink software is running on. Control Build Process Compiling and Linking - Otherwise, processing stops after generating the model code and the makefile; the following message is displayed on the MATLAB command line. ### Make will not be invoked - template makefile is for a different host • TGT_FCN_LIB template makefile variable The template makefile variable TGT_FCN_LIB specifies compiler command line options. The line in the makefile is TGT_FCN_LIB = |>TGT_FCN_LIB<|. By default, the Simulink Coder software expands the |>TGT_FCN_LIB<| token to match the setting of the Code replacement library option on the Code Generation > Interface pane of the Configuration Parameters dialog box. Possible values for this option include ANSI_C, C99 (ISO), GNU99 (GNU), and C++ (ISO). You can use this token in a makefile conditional statement to specify compiler options to be used. For example, if you set the token to C99 (ISO), the compiler might need an additional option set to support C99 library functions. 22-3 22 Build Process Integration Cross-Compile Code Generated on Microsoft Windows If you need to generate code with the Simulink Coder software on a Microsoft Windows system but compile the generated code on a different supported platform, you can do so by modifying your TMF and model configuration parameters. For example, you would need to do this if you develop applications with the MATLAB and Simulink products on a Windows system, but you run your generated code on a Linux system. To set up a cross-compilation development environment, do the following (here a Linux system is the destination platform): 1 On your Windows system, copy the UNIX TMF for your target to a local folder. This will be your working folder for initiating code generation. For example, you might copy matlabroot/rtw/c/grt/grt_unix.tmf to D:/work/my_grt_unix.tmf. 2 Make the following changes to your copy of the TMF: • Add the following line near the SYS_TARGET_FILE = line: MAKEFILE_FILESEP = / • Search for the line 'ifeq ($(OPT_OPTS),$(DEFAULT_OPT_OPTS))' and, for each occurrence, remove the conditional logic and retain only the 'else' code. That is, remove everything from the 'if' to the 'else', inclusive, as well as the closing 'endif'. Only the lines from the 'else' portion should remain. This forces the run-time libraries to build for a Linux system. 3 Open your model and make the following changes in the Code Generation pane of the Configuration Parameters dialog: • Specify the name of your new TMF in the Template makefile text box (for example, my_grt_unix.tmf). • Select Generate code only and click Apply. 4 Generate the code. 5 If the build folder (folder from which the model was built) is not already Linux accessible, copy it to a Linux accessible path. For example, if your 22-4 Cross-Compile Code Generated on Microsoft® Windows® build folder for the generated code was D:\work\mymodel_grt_rtw, copy that entire folder tree to a path such as /home/user/mymodel_grt_rtw. 6 If the MATLAB folder tree on the Windows system is Linux accessible, skip this step. Otherwise, you must copy all the include and source folders to a Linux accessible drive partition, for example, /home/user/myinstall. These folders appear in the makefile after MATLAB_INCLUDES = and ADD_INCLUDES = and can be found by searching for $(MATLAB_ROOT). Any path that contains $(MATLAB_ROOT) must be copied. Here is an example list (your list will vary depending on your model): $(MATLAB_ROOT)/rtw/c/grt $(MATLAB_ROOT)/extern/include $(MATLAB_ROOT)/simulink/include $(MATLAB_ROOT)/rtw/c/src $(MATLAB_ROOT)/rtw/c/tools Additionally, paths containing $(MATLAB_ROOT) in the build rules (lines with %.o :) must be copied. For example, based on the build rule %.o : $(MATLAB_ROOT)/rtw/c/src/ext_mode/tcpip/%.c the following folder should be copied: $(MATLAB_ROOT)/rtw/c/src/ext_mode/tcpip Note The path hierarchy relative to the MATLAB root must be maintained. For example, c:\MATLAB\rtw\c\tools\* would be copied to /home/user/mlroot/rtw/c/tools/*. For some blocksets, it is easiest to copy a higher-level folder that includes the subfolders listed in the makefile. For example, the DSP System Toolbox product requires the following folders to be copied: $(MATLAB_ROOT)/toolbox/dspblks $(MATLAB_ROOT)/toolbox/rtw/dspblks 7 Make the following changes to the generated makefile: 22-5 22 Build Process Integration • Set both MATLAB_ROOT and ALT_MATLAB_ROOT equal to the Linux accessible path to matlabroot (for example, home/user/myinstall). • Set COMPUTER to the computer value for your platform, such as GLNX86. Enter help computer in the MATLAB Command Window for a list of computer values. • In the ADD_INCLUDES list, change the build folder (designating the location of the generated code on the Windows system) and parent folders to Linux accessible include folders. For example, change D:\work\mymodel_grt_rtw\ to /home/user/mymodel_grt_rtw. Additionally, if matlabroot is a UNC path, such as \\my-server\myapps\matlab, replace the hard-coded MATLAB root with $(MATLAB_ROOT). 8 From a Linux shell, compile the code you generated on the Windows system. You can do this by running the generated model.bat file or by typing the make command line as it appears in the .bat file. Note If errors occur during makefile execution, you may need to run the dos2unix utility on the makefile (for example, dos2unix mymodel.mk). 22-6 Control Library Location and Naming During Build Control Library Location and Naming During Build Two configuration parameters, TargetPreCompLibLocation and TargetLibSuffix, are available for you to use to control values placed in Simulink Coder generated makefiles during the token expansion from template makefiles (TMFs). You can use these parameters to • Specify the location of precompiled libraries, such as blockset libraries or the Simulink Coder library. Typically, a target has cross-compiled versions of these libraries and places them in a target-specific folder. • Control the suffix applied to library file names (for example, _target.a or _target.lib). Targets can set the parameters inside the system target file (STF) select callback. For example: function mytarget_select_callback_handler(varargin) hDig=varargin{1}; hSrc=varargin{2}; slConfigUISetVal(hDig, hSrc,... 'TargetPreCompLibLocation', 'c:\mytarget\precomplibs'); slConfigUISetVal(hDig, hSrc, 'TargetLibSuffix',... '_diab.library'); The TMF has corresponding expansion tokens: |>EXPAND_LIBRARY_LOCATION<| |>EXPAND_LIBRARY_SUFFIX<| Alternatively, you can use a call to the set_param function. For example: set_param(model,'TargetPreCompLibLocation',... 'c:\mytarget\precomplibs'); Note If your model contains referenced models, you can use the make option USE_MDLREF_LIBPATHS to control whether libraries used by the referenced models are copied to the parent model’s build folder. For more information, see “Control the Location of Model Reference Libraries” on page 22-9. 22-7 22 Build Process Integration Specify the Location of Precompiled Libraries Use the TargetPreCompLibLocation configuration parameter to: • Override the precompiled library location specified in the rtwmakecfg.m file (see “Use rtwmakecfg.m API to Customize Generated Makefiles” on page 14-124 for details) • Precompile and distribute target-specific versions of product libraries (for example, the DSP System Toolbox product) For a precompiled library, such as a blockset library or the Simulink Coder library, the location specified in rtwmakecfg.m is typically a location specific to the blockset or the Simulink Coder product. It is expected that the library will exist in this location and it is linked against during Simulink Coder builds. However, for some applications, such as custom targets, it is preferable to locate the precompiled libraries in a target-specific or other alternate location rather than in the location specified in rtwmakecfg.m. For a custom target, the library is expected to be created using the target-specific cross-compiler and placed in the target-specific location for use during the Simulink Coder build process. All libraries intended to be supported by the target should be compiled and placed in the target-specific location. You can set up the TargetPreCompLibLocation parameter in its select callback. The path that you specify for the parameter must be a fully qualified absolute path to the library location. Relative paths are not supported. For example: slConfigUISetVal(hDlg, hSrc, 'TargetPreCompLibLocation',... 'c:\mytarget\precomplibs'); Alternatively, you set the parameter with a call to the set_param function. For example: set_param(model,'TargetPreCompLibLocation',... 'c:\mytarget\precomplibs'); During the TMF-to-makefile conversion, the Simulink Coder build process replaces the token |>EXPAND_LIBRARY_LOCATION<| with the specified location in the rtwmakecfg.m file. For example, if the library name specified in the rtwmakecfg.m file is 'rtwlib', the TMF expands from: 22-8 Control Library Location and Naming During Build LIBS += |>EXPAND_LIBRARY_LOCATION<|\|>EXPAND_LIBRARY_NAME<|\ |>EXPAND_LIBRARY_SUFFIX<| to: LIBS += c:\mytarget\precomplibs\rtwlib_diab.library By default, TargetPreCompLibLocation is an empty string and the Simulink Coder build process uses the location specified in rtwmakecfg.m for the token replacement. Control the Location of Model Reference Libraries On platforms other than the Apple Macintosh platform, when building a model that uses referenced models, the Simulink Coder build process by default: • Copies libraries used by the referenced models to the parent model’s build folder • Assigns the filenames of the libraries to MODELREF_LINK_LIBS in the generated makefile For example, if a model includes a referenced model sub, the Simulink Coder build process assigns the library name sub_rtwlib.lib to MODELREF_LINK_LIBS and copies the library file to the parent model’s build folder. This definition is then used in the final link line, which links the library into the final product (usually an executable). This technique minimizes the length of the link line. On the Macintosh platform, and optionally on other platforms, the Simulink Coder build process: • Does not copy libraries used by the referenced models to the parent model’s build folder • Assigns the relative paths and filenames of the libraries to MODELREF_LINK_LIBS in the generated makefile When using this technique, the Simulink Coder build process assigns a relative path such as ../slprj/grt/sub/sub_rtwlib.lib to MODELREF_LINK_LIBS and uses the path to gain access to the library file at link time. 22-9 22 Build Process Integration To change to the non-default behavior on platforms other than the Macintosh platform, enter the following command in the Make command field of the Code Generation pane of the Configuration Parameters dialog box: make_rtw USE_MDLREF_LIBPATHS=1 If you specify other Make command arguments, such as OPTS="-g", you can specify the multiple arguments in any order. To return to the default behavior, set USE_MDLREF_LIBPATHS to 0, or remove it. Control the Suffix Applied to Library File Names Use the TargetLibSuffix configuration parameter to control the suffix applied to library names (for example, _target.lib or _target.a). The specified suffix string must include a period (.). You can apply TargetLibSuffix to the following libraries: • Libraries on which a target depends, as specified in the rtwmakecfg.m API. You can use TargetLibSuffix to affect the suffix of both precompiled and non-precompiled libraries configured from the rtwmakecfg API. For details, see “Use rtwmakecfg.m API to Customize Generated Makefiles” on page 14-124. In this case, a target can set the parameter in its select callback. For example: slConfigUISetVal(hDlg, hSrc, 'TargetLibSuffix',... '_diab.library'); Alternatively, you can use a call to the set_param function. For example: set_param(model,'TargetLibSuffix','_diab.library'); During the TMF-to-makefile conversion, the Simulink Coder build process replaces the token |>EXPAND_LIBRARY_SUFFIX<| with the specified suffix. For example, if the library name specified in the rtwmakecfg.m file is 'rtwlib', the TMF expands from: LIBS += |>EXPAND_LIBRARY_LOCATION<|\|>EXPAND_LIBRARY_NAME<|\ |>EXPAND_LIBRARY_SUFFIX<| 22-10 Control Library Location and Naming During Build to: LIBS += c:\mytarget\precomplibs\rtwlib_diab.library By default, TargetLibSuffix is set to an empty string. In this case, the Simulink Coder build process replaces the token |>EXPAND_LIBRARY_SUFFIX<| with an empty string. • Shared utility library and the model libraries created with model reference. For these cases, associated makefile variables do not require the |>EXPAND_LIBRARY_SUFFIX<| token. Instead, the Simulink Coder build process includes TargetLibSuffix implicitly. For example, for a top model named topmodel with submodels named submodel1 and submodel2, the top model’s TMF is expanded from: SHARED_LIB = |>SHARED_LIB<| MODELLIB = |>MODELLIB<| MODELREF_LINK_LIBS = |>MODELREF_LINK_LIBS<| to: SHARED_LIB = \ ..\slprj\ert\_sharedutils\rtwshared_diab.library MODELLIB = topmodellib_diab.library MODELREF_LINK_LIBS = \ submodel1_rtwlib_diab.library submodel2_rtwlib_diab.library By default, the TargetLibSuffix parameter is an empty string. In this case, the Simulink Coder build process chooses a default suffix for these three tokens using a file extension of .lib on Windows hosts and .a on UNIX hosts. (For model reference libraries, the default suffix additionally includes _rtwlib.) For example, on a Windows host, the expanded makefile values would be: SHARED_LIB = ..\slprj\ert\_sharedutils\rtwshared.lib MODELLIB = topmodellib.lib MODELREF_LINK_LIBS = submodel1_rtwlib.lib submodel2_rtwlib.lib 22-11 22 Build Process Integration Recompile Precompiled Libraries You can recompile precompiled libraries included as part of the Simulink Coder product, such as rtwlib or dsplib, by using a supplied MATLAB function, rtw_precompile_libs. You might consider doing this if you need to customize compiler settings for various platforms or environments. For details on using rtw_precompile_libs, see “Precompile S-Function Libraries” on page 14-129. 22-12 Customize Post-Code-Generation Build Processing Customize Post-Code-Generation Build Processing The Simulink Coder product provides a set of tools, including a build information object, you can use to customize build processing that occurs after code generation. You might use such customizations for target development or the integration of third-party tools into your application development environment. The next figure and the steps that follow show the general workflow for setting up such customizations. Program post code generation command Define post code generation command Generate a makefile? No Suppress makefile generation Yes Modify post code generation command Build model No Results OK? Yes Done 1 Program the post code generation command. 2 Define the post code generation command. 3 Suppress makefile generation, if applicable.. 4 Build the model. 22-13 22 Build Process Integration 5 Modify the command and rebuild the model until the build results are acceptable. Build Information Object At the start of a model build, the Simulink Coder build process logs the following build option and dependency information to a temporary build information object: • Compiler options • Preprocessor identifier definitions • Linker options • Source files and paths • Include files and paths • Precompiled external libraries You can retrieve information from and add information to this object by using an extensive set of functions. For a list of available functions and detailed function descriptions, see “Build Process”. “Program a Post Code Generation Command” on page 22-14 explains how to use the functions to control post code generation build processing. Program a Post Code Generation Command For certain applications, you might want to control aspects of the build process after the code generation. For example, you might do this if you develop your own target, or you want to apply an analysis tool to the generated code before continuing with the build process. You can apply this level of control to the build process by programming and then defining a post code generation command. A post code generation command is a MATLAB language file that typically calls functions that get data from or add data to the model’s build information object. You can program the command as a script or function. 22-14 Customize Post-Code-Generation Build Processing If You Program the Command as a... Then the... Script Script can gain access to the model name and the build information directly Function Function can pass the model name and the build information as arguments If your post code generation command calls user-defined functions, make sure the functions are on the MATLAB path. If the Simulink Coder build process cannot find a function you use in your command, the build process errors out. You can then call any combination of build information functions, as listed in “Build Process”, to customize the model’s post code generation build processing. The following example shows a fragment of a post code generation command that gets the filenames and paths of the source and include files generated for a model for analysis. function analyzegencode(buildInfo) % Get the names and paths of all source and include files % generated for the model and then analyze them. % buildInfo - build information for my model. % Define cell array to hold data. MyBuildInfo={}; % Get source file information. MyBuildInfo.srcfiles=getSourceFiles(buildInfo, true, true); MyBuildInfo.srcpaths=getSourcePaths(buildInfo, true); % Get include (header) file information. MyBuildInfo.incfiles=getIncludeFiles(buildInfo, true, true); MyBuildInfo.incpaths=getIncludePaths(buildInfo, true); % Analyze generated code. . . 22-15 22 Build Process Integration . Define a Post Code Generation Command After you program a post code generation command, you need to inform the Simulink Coder build process that the command exists and to add it to the model’s build processing. You do this by defining the command with the PostCodeGenCommand model configuration parameter. When you define a post code generation command, the Simulink Coder build process evaluates the command after generating and writing the model’s code to disk and before generating a makefile. As the following syntax lines show, the arguments that you specify when setting the configuration parameter varies depending on whether you program the command as a script, function, or set of functions. Note When defining the command as a function, you can specify an arbitrary number of input arguments. To pass the model’s name and build information to the function, specify identifiers modelName and buildInfo as arguments. Script set_param(model, 'PostCodeGenCommand',... 'pcgScriptName'); Function set_param(model, 'PostCodeGenCommand',... 'pcgFunctionName(modelName)'); Multiple Functions pcgFunctions=... 'pcgFunction1Name(modelName);... pcgFunction2Name(buildInfo)'; set_param(model, 'PostCodeGenCommand',... pcgFunctions); The following call to set_param defines PostCodGenCommand to evaluate the function analyzegencode. 22-16 Customize Post-Code-Generation Build Processing set_param(model, 'PostCodeGenCommand',... 'analyzegencode(buildInfo)'); Suppress Makefile Generation The Simulink Coder product provides the ability to suppress makefile generation during the build process. For example, you might do this to integrate tools into the build process that are not driven by makefiles. To instruct the Simulink Coder build process to not generate a makefile, do one of the following: • Clear the Generate makefile option on the Code Generation pane of the Configuration Parameters dialog box. • Set the value of the configuration parameter GenerateMakefile to off. When you suppress makefile generation, • You no longer can explicitly specify a make command or template makefile. • You must specify your own instructions for any post code generation processing, including compilation and linking, in a post code generation command as explained in “Program a Post Code Generation Command” on page 22-14 and “Define a Post Code Generation Command” on page 22-16. 22-17 22 Build Process Integration Configure Generated Code with TLC In this section... “About Configuring Generated Code with TLC” on page 22-18 “Assigning Target Language Compiler Variables” on page 22-18 “Set Target Language Compiler Options” on page 22-20 About Configuring Generated Code with TLC You can use the Target Language Compiler (TLC) to fine tune your generated code. TLC supports extended code generation variables and options in addition to parameters available on the Code Generation pane on the Configuration Parameters dialog box. There are two ways to set TLC variables and options, as described in this section. Note You should not customize TLC files in the folder matlabroot/rtw/c/tlc even though the capability exists to do so. Such TLC customizations might not be applied during the code generation process and can lead to unpredictable results. Assigning Target Language Compiler Variables The %assign statement lets you assign a value to a TLC variable, as in %assign MaxStackSize = 4096 This is also known as creating a parameter name/parameter value pair. For a description of the %assign statement see “Target Language Compiler Directives”. You should write your %assign statements in the Configure RTW code generation settings section of the system target file. The following table lists the code generation variables you can set with the %assign statement. 22-18 Configure Generated Code with TLC Target Language Compiler Optional Variables Variable Description MaxStackSize=N When the Enable local block outputs check box is selected, the total allocation size of local variables that are declared by all block outputs in the model cannot exceed MaxStackSize (in bytes). MaxStackSize can be any positive integer. If the total size of local block output variables exceeds this maximum, the remaining block output variables are allocated in global, rather than local, memory. The default value for MaxStackSize is rtInf, that is, unlimited stack size. Note: Local variables in the generated code from sources other than local block outputs, such as from a Stateflow diagram or MATLAB Function block, and stack usage from sources such as function calls and context switching are not included in the MaxStackSize calculation. For overall executable stack usage metrics, do a target-specific measurement by using run-time (empirical) analysis or static (code path) analysis with object code. MaxStackVariableSize=N When the Enable local block outputs check box is selected, this limits the size of any local block output variable declared in the code to N bytes, where N>0. A variable whose size exceeds MaxStackVariableSize is allocated in global, rather than local, memory. The default is 4096. WarnNonSaturatedBlocks=value Flag to control display of overflow warnings for blocks that have saturation capability, but have it turned off (unchecked) in their dialog. These are the options: • 0 — No warning is displayed. • 1 — Displays one warning for the model during code generation • 2 — Displays one warning that contains a list of all offending blocks 22-19 22 Build Process Integration Set Target Language Compiler Options You can enter TLC options in the TLC options edit field on the Code Generation pane of the Configuration Parameters dialog box. For information about these options, see “Specify TLC Options” on page 15-12 and “Configure TLC”. 22-20 Customize Build Process with STF_make_rtw_hook File Customize Build Process with STF_make_rtw_hook File In this section... “About the STF_make_rtw_hook File” on page 22-21 “Conventions for Using the STF_make_rtw_hook File” on page 22-21 “STF_make_rtw_hook.m Function Prototype and Arguments” on page 22-22 “Applications for STF_make_rtw_hook.m” on page 22-25 “Control Code Regeneration Using STF_make_rtw_hook.m” on page 22-26 “Use STF_make_rtw_hook.m for Your Build Procedure” on page 22-27 About the STF_make_rtw_hook File The build process lets you supply optional hook files that are executed at specified points in the code-generation and make process. You can use hook files to add target-specific actions to the build process. This section describes an important MATLAB hook, generically referred to as STF_make_rtw_hook.m, where STF is the name of a system target file, such as ert or mytarget. This hook file implements a function, STF_make_rtw_hook, that dispatches to a specific action, depending on the hookMethod argument passed in. The build process automatically calls STF_make_rtw_hook, passing in thehookMethod argument (as well as other arguments described below). You need to implement only those hook methods that your build process requires. Conventions for Using the STF_make_rtw_hook File For the build process to call the STF_make_rtw_hook, check that the following conditions are met: • The STF_make_rtw_hook.m file is on the MATLAB path. • The filename is the name of your system target file (STF), appended to the string _make_rtw_hook.m. For example, if you were generating code with a custom system target file mytarget.tlc, you would name your STF_make_rtw_hook.m file to mytarget_make_rtw_hook.m. Likewise, the 22-21 22 Build Process Integration hook function implemented within the file should follow the same naming convention. • The hook function implemented in the file follows the function prototype described in the next section. STF_make_rtw_hook.m Function Prototype and Arguments The function prototype for STF_make_rtw_hook is function STF_make_rtw_hook(hookMethod, modelName, rtwRoot, templateMakefile, buildOpts, buildArgs) The arguments are defined as: • hookMethod: String specifying the stage of build process from which the STF_make_rtw_hook function is called. The flowchart below summarizes the build process, highlighting the hook points. Valid values for hookMethod are 'entry', 'before_tlc', 'after_tlc', 'before_make', 'after_make', 'exit', and 'error'. The STF_make_rtw_hook function dispatches to the relevant code with a switch statement. 22-22 Customize Build Process with STF_make_rtw_hook File Input: modelName,buildArgs Start build process Simulink Coder verification STF entry hook Create build directory STF before_tlc hook Input: buildOpts,templateMakefile Error occurs STF error hook Generate code STF af ter_tlc hook STF before_make hook Invoke post code generation command Make STF after_make hook STF exit hook End build process • modelName: String specifying the name of the model. Valid at all stages of the build process. • rtwRoot: Reserved. • templateMakefile: Name of template makefile. 22-23 22 Build Process Integration • buildOpts: A MATLAB structure containing the fields described in the list below. Valid for the 'before_make', 'after_make', and 'exit' stages only. The buildOpts fields include: - modules: Character array specifying a list of additional files that need to be compiled. - codeFormat: Character array containing code format specified for the target. (ERT-based targets must use the 'Embedded-C' code format.) - noninlinedSFcns: Cell array specifying list of noninlined S-functions in the model. compilerEnvVal: String specifying compiler environment variable value (for example, C:\Applications\Microsoft Visual). • buildArgs: Character array containing the argument to make_rtw. When you invoke the build process, buildArgs is copied from the argument string (if any) following "make_rtw" in the Make command field of the Code Generation pane of the Configuration Parameters dialog box. The make arguments from the Make command field in the figure above, for example, generate the following: % make -f untitled.mk VAR1=0 VAR2=4 22-24 Customize Build Process with STF_make_rtw_hook File Applications for STF_make_rtw_hook.m An enumeration of all possible uses for STF_make_rtw_hook.m is beyond the scope of this document. However, this section provides some suggestions of how you might apply the available hooks. In general, you can use the 'entry' hook to initialize the build process before any code is generated, for example to change or validate settings. One application for the 'entry' hook is to rerun the auto-configuration script that initially ran at target selection time to compare model parameters before and after the script executes for validation purposes. The other hook points, 'before_tlc', 'after_tlc', 'before_make', 'after_make', 'exit', and 'error' are useful for interfacing with external tool chains, source control tools, and other environment tools. For example, you could use the STF_make_rtw_hook.m file at any stage after 'entry' to obtain the path to the build folder. At the 'exit' stage, you could then locate generated code files within the build folder and check them into your version control system. You might use 'error' to clean up static or global data used by the hook function when an error occurs during code generation or the build process. Note that the build process temporarily changes the MATLAB working folder to the build folder for stages 'before_make', 'after_make', 'exit', and 'error'. Your STF_make_rtw_hook.m file should not make incorrect assumptions about the location of the build folder. You can obtain the path to the build folder anytime after the 'entry' stage. In the following code example, the build folder path is returned as a string to the variable buildDirPath. makertwObj = get_param(gcs, 'MakeRTWSettingsObject'); buildDirPath = getfield(makertwObj, 'BuildDirectory'); 22-25 22 Build Process Integration Control Code Regeneration Using STF_make_rtw_hook.m When you rebuild a model, by default, the build process performs checks to determine whether changes to the model or relevant settings require regeneration of the top model code. (For details on the criteria, see “Control Regeneration of Top Model Code” on page 15-27.) If the checks determine that top model code generation is required, the build process fully regenerates and compiles the model code. If the checks indicate that the top model generated code is current with respect to the model, and no model settings require full regeneration, the build process omits regeneration of the top model code. Regardless of whether the top model code is regenerated, the build process subsequently calls all build process hooks, including STF_make_rtw_hook functions and the post code generation command. The following mechanisms allow you to perform actions related to code regeneration in the STF_make_rtw_hook functions: • To force code regeneration, use the following function call from the 'entry' hook: rtw.targetNeedsCodeGen('set', true); • In all hooks from 'before_tlc' through 'exit', the buildOpts structure passed to the hook has a Boolean field codeWasUpToDate, which is set to true if model code was up to date and code was not regenerated, or false if code was not up to date and code was regenerated. You can customize hook actions based on the value of this field. For example: ... case `before_tlc' if buildOpts.codeWasUpToDate %Perform hook actions for up to date model else %Perform hook actions for full code generation end ... 22-26 Customize Build Process with STF_make_rtw_hook File Use STF_make_rtw_hook.m for Your Build Procedure To create a custom STF_make_rtw_hook hook file for your build procedure, copy and edit the example ert_make_rtw_hook.m file (located in the matlabroot/toolbox/rtw/targets/ecoder folder) as follows: 1 Copy ert_make_rtw_hook.m to a folder in the MATLAB path, and rename it in accordance with the naming conventions described in “Conventions for Using the STF_make_rtw_hook File” on page 22-21. For example, to use it with the GRT target grt.tlc, rename it to grt_make_rtw_hook.m. 2 Rename the ert_make_rtw_hook function within the file to match the filename. 3 Implement the hooks that you require by adding code to case statements within the switch hookMethod statement. 22-27 22 Build Process Integration Customize Build Process with sl_customization.m In this section... “About sl_customization.m” on page 22-28 “Register Build Process Hook Functions Using sl_customization.m” on page 22-30 “Variables Available for sl_customization.m Hook Functions” on page 22-31 “Example Build Process Customization Using sl_customization.m” on page 22-31 About sl_customization.m The Simulink customization file sl_customization.m is a mechanism that allows you to use MATLAB to customize the standard Simulink user interface. The Simulink software reads the sl_customization.m file, if present on the MATLAB path, when it starts and the customizations specified in the file are applied to the Simulink session. For more information on the sl_customization.m customization file, see “Registering Customizations”. The sl_customization.m file can be used to register installation-specific hook functions to be invoked during the Simulink Coder build process. The hook functions that you register through sl_customization.m complement System Target File (STF) hooks (described in “Customize Build Process with STF_make_rtw_hook File” on page 22-21) and post-code generation commands (described in “Customize Post-Code-Generation Build Processing” on page 22-13). The following figure shows the relationship between installation-level hooks and the other available mechanisms for customizing the build process. 22-28 Customize Build Process with sl_customization.m Start build process Simulink Coder verification Entry STF 'entry' hook Installation 'entry' hook Before TLC STF 'before_tlc' hook Installation 'before_tlc' hook After TLC STF 'after_tlc' hook Installation 'after_tlc' hook Before Make STF 'before_make' hook Installation 'before_make' hook After Make STF 'after_make' hook Post code generation command Installation 'after_make' hook Exit STF 'exit' hook Installation 'exit' hook End build process 22-29 22 Build Process Integration Register Build Process Hook Functions Using sl_customization.m To register installation-level hook functions that will be invoked during the Simulink Coder build process, you create a MATLAB function called sl_customization.m and include it on the MATLAB path of the Simulink installation that you want to customize. The sl_customization function accepts one argument: a handle to a customization manager object. For example, function sl_customization(cm) As a starting point for your customizations, the sl_customization function must first get the default (factory) customizations, using the following assignment statement: hObj = cm.RTWBuildCustomizer; You then invoke methods to register your customizations. The customization manager object includes the following method for registering Simulink Coder build process hook customizations: • addUserHook(hObj, hookType, hook) Registers the MATLAB hook script or function specified by hook for the build process stage represented by hookType. The valid values for hookType are 'entry', 'before_tlc', 'after_tlc', 'before_make', 'after_make', and 'exit'. Your instance of the sl_customization function should use this method to register installation-specific hook functions. The Simulink software reads the sl_customization.m file when it starts. If you subsequently change the file, you must restart the Simulink session or enter the following command at the MATLAB command line to effect the changes: sl_refresh_customizations 22-30 Customize Build Process with sl_customization.m Variables Available for sl_customization.m Hook Functions The following variables are available for sl_customization.m hook functions to use: • modelName — The name of the Simulink model (valid for all stages) • dependencyObject — An object containing the dependencies of the generated code (valid only for the 'after_make' stage) A hook script can directly access the valid variables. A hook function can pass the valid variables as arguments to the function. For example: hObj.addUserHook('after_make', 'afterMakeFunction(modelName,dependencyObject);'); Example Build Process Customization Using sl_customization.m The sl_customization.m file shown in Example 1: sl_customization.m for Simulink® Coder™ Build Process Customizations on page 22-31 uses the addUserHook method to specify installation-specific build process hooks to be invoked at the 'entry' and 'after_tlc' stages of the Simulink Coder build. For the hook function source code, see Example 2: CustomRTWEntryHook.m on page 22-32 and Example 3: CustomRTWPostProcessHook.m on page 22-32. Example 1: sl_customization.m for Simulink Coder Build Process Customizations function sl_customization(cm) % Register user customizations % Get default (factory) customizations hObj = cm.RTWBuildCustomizer; % Register build process hooks hObj.addUserHook('entry', 'CustomRTWEntryHook(modelName);'); hObj.addUserHook('after_tlc', 'CustomRTWPostProcessHook(modelName);'); end 22-31 22 Build Process Integration Example 2: CustomRTWEntryHook.m function [str, status] = CustomRTWEntryHook(modelName) str =sprintf('Custom entry hook for model ''%s.''',modelName); disp(str) status =1; Example 3: CustomRTWPostProcessHook.m function [str, status] = CustomRTWPostProcessHook(modelName) str =sprintf('Custom post process hook for model ''%s.''',modelName); disp(str) status =1; If you include the above three files on the MATLAB path of the Simulink installation that you want to customize, the coded hook function messages will appear in the displayed output for Simulink Coder builds. For example, if you open the ERT-based model rtwdemo_udt, open the Code Generation pane of the Configuration Parameters dialog box, and click the Build button to initiate a Simulink Coder build, the following messages are displayed: >> rtwdemo_udt ### Starting build procedure for model: rtwdemo_udt Custom entry hook for model 'rtwdemo_udt.' Custom post process hook for model 'rtwdemo_udt.' ### Successful completion of build procedure for model: rtwdemo_udt >> 22-32 Replace the STF_rtw_info_hook Mechanism Replace the STF_rtw_info_hook Mechanism Prior to MATLAB Release 14, custom targets supplied target-specific information with a hook file (referred to as STF_rtw_info_hook.m). The STF_rtw_info_hook specified properties such as word sizes for integer data types (for example, char, short, int, and long), and C implementation-specific properties of the custom target. The STF_rtw_info_hook mechanism has been replaced by the Hardware Implementation pane of the Configuration Parameters dialog box. Using this dialog box, you can specify all properties that were formerly specified in your STF_rtw_info_hook file. For backward compatibility, existing STF_rtw_info_hook files are available. However, you should convert your target and models to use of the Hardware Implementation pane. See “Target” on page 9-9 . 22-33 22 Build Process Integration Customize Build to Use Shared Utility Code The shared utility folders (slprj/target/_sharedutils) typically store generated utility code that is common to a top model and the models it references. You can also force the build process to use a shared utilities folder for a standalone model. See “Logging” on page 15-105 for details. If you want your target to support compilation of code generated in the shared utilities folder, you must modify your template makefile (TMF). The shared utilities folder is required to support model reference builds. See “Support Model Referencing” on page 24-101 to learn about additional updates for supporting model reference builds. The exact syntax of the changes can vary due to differences in the make utility and compiler/archive tools used by your target. The examples below are based on the Free Software Foundation’s GNU make utility. You can find the following updated TMF examples for GNU and Microsoft Visual C++ make utilities in the GRT and ERT target folders: • GRT: matlabroot/rtw/c/grt/ - grt_lcc.tmf grt_vc.tmf grt_unix.tmf • ERT: matlabroot/rtw/c/ert/ - ert_lcc.tmf ert_vc.tmf ert_unix.tmf Use the GRT or ERT examples as a guide to the location, within the TMF, of the changes and additions described below. Note The ERT-based TMFs contain extra code to handle generation of ERT S-functions and model reference simulation targets. Your target does not need to handle these cases. 22-34 Customize Build to Use Shared Utility Code Modify Template Makefiles to Support Shared Utilities Make the following changes to your TMF to support the shared utilities folder: 1 Add the following make variables and tokens to be expanded when the makefile is generated: SHARED_SRC SHARED_SRC_DIR SHARED_BIN_DIR SHARED_LIB = = = = |>SHARED_SRC<| |>SHARED_SRC_DIR<| |>SHARED_BIN_DIR<| |>SHARED_LIB<| SHARED_SRC specifies the shared utilities folder location and the source files in it. A typical expansion in a makefile is SHARED_SRC = ../slprj/ert/_sharedutils/*.c SHARED_LIB specifies the library file built from the shared source files, as in the following expansion. SHARED_LIB = ../slprj/ert/_sharedutils/rtwshared.lib SHARED_SRC_DIR and SHARED_BIN_DIR allow specification of separate folders for shared source files and the library compiled from the source files. In the current release, all TMFs use the same path, as in the following expansions. SHARED_SRC_DIR SHARED_BIN_DIR = ../slprj/ert/_sharedutils = ../slprj/ert/_sharedutils 2 Set the SHARED_INCLUDES variable according to whether shared utilities are in use. Then append it to the overall INCLUDES variable. SHARED_INCLUDES = ifneq ($(SHARED_SRC_DIR),) SHARED_INCLUDES = -I$(SHARED_SRC_DIR) endif INCLUDES = -I. $(MATLAB_INCLUDES) $(ADD_INCLUDES) \ $(USER_INCLUDES) $(SHARED_INCLUDES) 22-35 22 Build Process Integration 3 Update the SHARED_SRC variable to list all shared files explicitly. SHARED_SRC := $(wildcard $(SHARED_SRC)) 4 Create a SHARED_OBJS variable based on SHARED_SRC. SHARED_OBJS = $(addsuffix .o, $(basename $(SHARED_SRC))) 5 Create an OPTS (options) variable for compilation of shared utilities. SHARED_OUTPUT_OPTS = -o $@ 6 Provide a rule to compile the shared utility source files. $(SHARED_OBJS) : $(SHARED_BIN_DIR)/%.o : $(SHARED_SRC_DIR)/%.c $(CC) -c $(CFLAGS) $(SHARED_OUTPUT_OPTS) $< 7 Provide a rule to create a library of the shared utilities. The following example is based on The Open Group UNIX platforms. $(SHARED_LIB) : $(SHARED_OBJS) @echo "### Creating $@ " ar r $@ $(SHARED_OBJS) @echo "### Created $@ " 8 Add SHARED_LIB to the rule that creates the final executable. $(PROGRAM) : $(OBJS) $(LIBS) $(SHARED_LIB) $(LD) $(LDFLAGS) -o $@ $(LINK_OBJS) $(LIBS) $(SHARED_LIB)\ $(SYSLIBS) @echo "### Created executable: $(MODEL)" 9 Remove any explicit reference to rt_nonfinite.c or rt_nonfinite.cpp from your TMF. For example, change ADD_SRCS = $(RTWLOG) rt_nonfinite.c to ADD_SRCS = $(RTWLOG) 22-36 23 Run-Time Data Interface Extensions • “Customize an ASAP2 File” on page 23-2 • “Create a Transport Layer for External Communication” on page 23-14 23 Run-Time Data Interface Extensions Customize an ASAP2 File In this section... “About ASAP2 File Customization” on page 23-2 “ASAP2 File Structure on the MATLAB Path” on page 23-2 “Customize the Contents of the ASAP2 File” on page 23-3 “ASAP2 Templates” on page 23-4 “Use GROUP and SUBGROUP Hierarchies to Organize Signals and Parameters” on page 23-6 “Customize Computation Method Names” on page 23-12 “Suppress Computation Methods for FIX_AXIS” on page 23-13 About ASAP2 File Customization The Embedded Coder product provides a number of Target Language Compiler (TLC) files to enable you to customize the ASAP2 file generated from a Simulink model. ASAP2 File Structure on the MATLAB Path The ASAP2 related files are organized within the folders identified below: • TLC files for generating ASAP2 file The matlabroot/rtw/c/tlc/mw folder contains TLC files that generate ASAP2 files, asamlib.tlc, asap2lib.tlc, asap2main.tlc, and asap2grouplib.tlc. These files are included by the selected System target file. (See “Targets Supporting ASAP2” on page 15-175.) • ASAP2 target files The matlabroot/toolbox/rtw/targets/asap2/asap2 folder contains the ASAP2 system target file and other control files. • Customizable TLC files 23-2 Customize an ASAP2 File The matlabroot/toolbox/rtw/targets/asap2/asap2/user folder contains files that you can modify to customize the content of your ASAP2 files. • ASAP2 templates The matlabroot/toolbox/rtw/targets/asap2/asap2/user/templates folder contains templates that define each type of CHARACTERISTIC in the ASAP2 file. Customize the Contents of the ASAP2 File The ASAP2 related TLC files enable you to customize the appearance of the ASAP2 file generated from a Simulink model. Most customization is done by modifying or adding to the files contained in the matlabroot/toolbox/rtw/targets/asap2/asap2/user folder. This section refers to this folder as the asap2/user folder. The user-customizable files provided are divided into two groups: • The static files define the parts of the ASAP2 file that are related to the environment in which the generated code is used. They describe information specific to the user or project. The static files are not model dependent. • The dynamic files define the parts of the ASAP2 file that are generated based on the structure of the source model. The procedure for customizing the ASAP2 file is as follows: 1 Make a copy of the asap2/user folder before making any modifications. 2 Remove the old asap2/user folder from the MATLAB path, or add the new asap2/user folder to the MATLAB path above the old folder. This ensures that the MATLAB session uses the ASAP2 setup file, asap2setup.tlc (new for Release 14). asap2setup.tlc specifies the folders and files to include in the TLC path during the ASAP2 file generation process. Modify asap2setup.tlc to control the folders and folders included in the TLC path. 3 Modify the static parts of the ASAP2 file. These include 23-3 23 Run-Time Data Interface Extensions • Project and header symbols, which are specified in asap2setup.tlc • Static sections of the file, such as file header and tail, A2ML, MOD_COMMON, and so on These are specified in asap2userlib.tlc. • Specify the appearance of the dynamic contents of the ASAP2 file by modifying the existing ASAP2 templates or by defining new ASAP2 templates. Sections of the ASAP2 file affected include RECORD_LAYOUT: modify parts of the ASAP2 template files. CHARACTERISTIC: modify parts of the ASAP2 template files. For more information on modifying the appearance of CHARACTERISTIC records, see “ASAP2 Templates” on page 23-4. • MEASUREMENT: These are specified in asap2userlib.tlc. • COMPU_METHOD: These are specified in asap2userlib.tlc. ASAP2 Templates The appearance of CHARACTERISTIC records in the ASAP2 file is controlled using a different template for each type of CHARACTERISTIC. The asap2/user folder contains template definition files for scalars, 1-D Lookup Table blocks and 2-D Lookup Table blocks. You can modify these template definition files, or you can create additional templates as required. The procedure for creating a new ASAP2 template is as follows: 1 Create a template definition file. See “Create Template Definition Files” on page 23-4. 2 Include the template definition file in the TLC path. The path is specified in the ASAP2 setup file, asap2setup.tlc. Create Template Definition Files This section describes the components that make up an ASAP2 template definition file. This description is in the form of code examples from asap2lookup1d.tlc, the template definition file for the Lookup1D template. This template corresponds to the Lookup1D parameter group. 23-4 Customize an ASAP2 File Note When creating a new template, use the corresponding parameter group name in place of Lookup1D in the code shown. Template Registration Function The input argument is the name of the parameter group associated with this template: % RECORD_LAYOUT Name Definition Function Record layout names (aliases) can be arbitrarily specified for each data type. This function is used by the other components of this file. %function ASAP2UserFcnRecordLayoutAlias_Lookup1D(dtId) void %switch dtId %case tSS_UINT8 %return "Lookup1D_UBYTE" ... %endswitch %endfunction Function to Write RECORD_LAYOUT Definitions This function writes RECORD_LAYOUT definitions associated with this template. The function is called by the built-in functions involved in the ASAP2 file generation process. The function name must be defined as shown, with the template name after the underscore: %function ASAP2UserFcnWriteRecordLayout_Lookup1D() Output /begin RECORD_LAYOUT % ... /end RECORD_LAYOUT %endfunction 23-5 23 Run-Time Data Interface Extensions Function to Write the CHARACTERISTIC This function writes the CHARACTERISTIC associated with this template. The function is called by the built-in functions involved in the ASAP2 file generation process. The function name must be defined as shown, with the template name after the underscore. The input argument to this function is a pointer to a parameter group record. The example shown is for a Lookup1D parameter group that has two members. The references to the associated x and y data records are obtained from the parameter group record as shown. This function calls a number of built-in functions to obtain the required information. For example, LibASAP2GetSymbol returns the symbol (name) for the specified data record: %function ASAP2UserFcnWriteCharacteristic_Lookup1D(paramGroup) Output %assign xParam = paramGroup.Member[0].Reference %assign yParam = paramGroup.Member[1].Reference %assign dtId = LibASAP2GetDataTypeId(xParam) /begin CHARACTERISTIC /* Name */ % /* Long identifier */ "% " ... /end CHARACTERISTIC %endfunction Use GROUP and SUBGROUP Hierarchies to Organize Signals and Parameters • “Signal and Parameter Grouping Overview” on page 23-7 • “TLC Functions for Defining and Adding Groups” on page 23-7 • “ASAP2 Simple Grouping” on page 23-9 • “ASAP2 Graphical Grouping” on page 23-10 23-6 Customize an ASAP2 File Signal and Parameter Grouping Overview The Simulink Coder product provides TLC functions that allow you to organize signals and parameters in the generated ASAP2 file into groups and subgroups, using the GROUP and SUBGROUP keywords in the ASAP2 standard. Grouping can be done using criteria such as the following: • Graphical location of the signal or parameter in the model • Functionality (I/O or local) • Custom criteria By default, the build process generates ASAP2 parameter and signal descriptions as a flat list. To generate ASAP2 GROUPs and SUBGROUPs, do the following: 1 Use the TLC customization functions that define and add groups. 2 Generate code for your model. The code generator automatically generates the defined groups into the ASAP2 file, using the GROUP and SUBGROUP keywords. TLC Functions for Defining and Adding Groups • “Create Groups” on page 23-7 • “Populate Groups” on page 23-8 • “Group by Graphical Hierarchy” on page 23-8 Create Groups. The software provides the following TLC functions for creating an ASAP2 group and setting its description and annotation. These functions are defined in the file matlabroot/rtw/c/tlc/mw/asap2grouplib.tlc and can be called at any point during the ASAP2 customization process. 23-7 23 Run-Time Data Interface Extensions Function Description LibASAP2CreateGroup(groupName, groupLongIdentifier) Creates a group with the specified groupName and returns the created group. If the group already exists, returns the existing group. LibASAP2SetGroupIsRoot(group) Sets the specified group as a ROOT. LibASAP2SetGroupAnnotation(group, annotation) Sets the annotation for the specified group. If annotation already exists, overwrites it. Populate Groups. The software provides the following TLC functions for adding subgroups, characteristics, and measurements to groups. These functions are defined in the file matlabroot/rtw/c/tlc/mw/asap2grouplib.tlc and can be called at any point during the ASAP2 customization process. Function Description LibASAP2AddSubGroupToGroup(group, subGroup) Adds the specified subGroup as a SUB_GROUP of the specified group. LibASAP2AddCharacteristicToGroup(group, characteristicName) Adds the specified characteristicName as a REF_CHARACTERISTIC of the specified group. LibASAP2AddMeasurementToGroup(group, measurementName) Adds the specified measurementName as a REF_MEASUREMENT of the specified group. Group by Graphical Hierarchy. The software provides the following TLC functions for creating groups based on the graphical hierarchy of signals, states, and parameters in the model. These functions are defined in the file matlabroot/rtw/c/tlc/mw/asap2grouplib.tlc and can be called at any point during the ASAP2 customization process. 23-8 Customize an ASAP2 File Function Description LibASAP2CreateGraphicalGroups() Creates groups and subgroups. A group is created for each graphical subsystem in the model. The graphical hierarchy is reflected in the SUB_GROUPs. LibASAP2AddCharacteristicToGraphical Groups(param) Adds a CHARACTERISTIC to one or more groups reflecting the locations of the specified parameter in the model. LibASAP2AddMeasurementToGraphical Group(signal) Adds a MEASUREMENT to a group and its subgroups reflecting the location of the specified signal or state in the model. ASAP2 Simple Grouping Consider the following model, in which subsystem S1 contains 3 signals and uses 2 parameters: Suppose that you want to do the following: • Create A ROOT group for the model. • Organize all signals in the model in a group called Signals, which is a subgroup of ROOT. • Organize all parameters in the model in a group called Parameters, which is a subgroup of ROOT. To create this simple grouping, you perform the following steps: 23-9 23 Run-Time Data Interface Extensions 1 In your copy of asap2setup.tlc, use the TLC functions to create the root group and subgroups. For example: %% Create a root GROUP %assign ASAP2RootGroup = LibASAP2CreateGroup("% ", ... "% ") % %% -------------------%% Create a group for model signals %assign ASAP2SigGroup = LibASAP2CreateGroup("Signals", ... "Measurements in % ") % %% -------------------------------%% Create a group for model parameters %assign ASAP2ParGroup = LibASAP2CreateGroup("Parameters", ... "Characteristics in % ") % 2 In the template function for MEASUREMENTs, ASAP2UserFcnWriteMeasurementfile, add each signal to ASAP2SigGroup. For example: % 3 In the template function for CHARACTERISTICs, ASAP2UserFcnWriteCharacteristic_Scalar, add each parameter to ASAP2ParGroup. For example: % In the generated ASAP2 file, parameters and signals are separated into groups called Parameters and Signals, under the model root. ASAP2 Graphical Grouping Consider the following model, in which subsystem S1 contains 3 signals and uses 2 parameters, and also contains another subsystem S2: 23-10 Customize an ASAP2 File Suppose that you want to do the following: • Create a ROOT group for the model and create a subgroup for each graphical subsystem in the model. • Add each signal and state to the group for the subsystem that refers to it. • Add each parameter to the groups for the subsystems that refer to it. (A parameter can be referred to in multiple subsystems and added to multiple groups.) To create this graphical grouping, you perform the following steps: 1 In your copy of asap2setup.tlc, use the TLC functions to create the groups according to the graphical hierarchy. For example: % 3 In the template function for CHARACTERISTICs, ASAP2UserFcnWriteCharacteristic_Scalar, add each parameter to its graphical groups. For example: % 23-11 23 Run-Time Data Interface Extensions In the generated ASAP2 file, the group ordering reflects the graphical hierarchy of the model, root > S1 > S2. Customize Computation Method Names In generated ASAP2 files, computation methods translate the electronic control unit (ECU) internal representation of measurement and calibration quantities into a physical model oriented representation. Simulink Coder software provides the ability to customize the names of computation methods. You can provide names that are more intuitive, enhancing ASAP2 file readability, or names that meet organizational requirements. To customize computation method names, use the MATLAB function getCompuMethodName, which is defined in matlabroot/toolbox/rtw/targets/asap2/asap2/user/getCompuMethodName.m. The getCompuMethodName function constructs a computation method name. The function prototype is cmName = getCompuMethodName(dataTypeName, cmUnits) where dataTypeName is the name of the data type associated with the computation method, cmUnits is the units as specified in the DocUnits property of a Simulink.Parameter or Simulink.Signal object (for example, rpm or m/s), and cmName returns the constructed computation method name. The default constructed name returned by the function has the format