Main Content

Generate Code for Atomic Subsystems

This example shows a model designed and configured for deploying embedded system component code that is generated from a model that is partitioned into multiple atomic subsystems. The subsystems execute at different rates. The multirate top model is configured for C data interface code generation. You integrate the generated source code for each subsystem with other code, including an external scheduler, that runs in a target environment.

Atomic Subsystem Model

Open the example model.

open_system("AtomicSubsystem");

The model is configured to display color-coded sample times with annotations. To see them, after opening the model, update the diagram by pressing Ctrl+D. To display the legend, press Ctrl+J.

This model partitions an algorithm into two atomic subsystems: Rate1s and Rate2s. Subsystem Rate1s is configured with a sample time of 1 second. Subsystem Rate2s is configured with a sample time of 2 seconds.

Relevant Model Configuration Parameter Settings

  • Type set to Fixed-step.

  • Solver set to discrete (no continuous states).

  • Treat each discrete rate as a separate task cleared.

Scheduling

Simulink® simulates the model based on the model configuration. Simulink propagates and uses the Inport block sample times to order block execution based on a single-core, single-tasking execution platform.

For this example, the sample time legend shows implicit rate grouping. Red represents the fastest discrete rate. Green represents the second fastest discrete rate.

Based on rate-monotonic scheduling, your application code (execution framework) must transfer data between subsystems Rate2s and Rate1s at a frequency of 2 seconds with the priority of 1 second. That is, the generated function transfers data in the 1 second task every other time prior to executing code for subsystem Rate1s.

Your execution framework must schedule the generated function code and handle the data transfers between them. This is an advantage for multirate models because the generated code does not assume scheduling or data transfer semantics. However, the execution framework must handle data transfers explicitly.

Generate Code and Report

Generate a single callable function for each subsystem without connections between them. Multiple ways are available to generate code for a subsystem, including from the subsystem context menu.

  1. Open the Embedded Coder app.

  2. Right-click a subsystem block.

  3. Click C/C++ Code > Build This Subsystem.

The example model generates a report.

Review Generated Code

Review the generated code in the Code view or the code generation report.

  • ert_main.c is an example main program (execution framework) for the subsystem. This code controls model code execution by calling entry-point function Rate1s_step or Rate2s_step. Use this file as a starting point for coding your execution framework.

  • Rate1s.c and Rate2s.c contain entry points for the code that implements subsystem Rate1s and Rate2s, respectively. This file includes the rate and task scheduling code.

  • Rate1s.h and Rate2s.h declare model data structures and a public interface to subsystem entry points and data structures.

  • rtwtypes.h defines data types, structures, and macros that the generated code requires.

Code Interface

Open and review the Code Interface Report. Use the information in that report to write the interface code for your execution framework:

  1. Include the generated header file by adding directive #include AtomicSubsystem.h.

  2. Write input data to the generated code for model Inport blocks.

  3. Call the generated entry-point functions.

  4. Read data from the generated code for model Outport blocks.

Input ports, Rate1s:

  • rtU.In1 of type real_T with dimension of 1

  • rtU.In2 of type real_T with dimension of 1

Entry-point functions, Rate1s:

  • Initialize entry-point function, void Rate1s_initialize(void). At startup, call this function once.

  • Output and update entry-point (step) function, void Rate1s_step(void). Call this function periodically, every second.

  • Termination function, void Rate1s_terminate(void). Call this function once from your shutdown code.

Output ports, Rate1s:

  • rtY.Out1 of type real_T with dimension of 1

  • rtY.Out2 of type real_T with dimension of 1

Input ports, Rate2s:

  • rtU.In1 of type real_T with dimension of 1

Entry-point functions, Rate2s:

  • Initialize entry-point function, void Rate2s_initialize(void). Call this function once at startup.

  • Output and update entry-point (step), void Rate2s_step(void). Call this function periodically, every 2 seconds.

  • Termination function, void Rate2s_terminate(void). Call this function once from your shutdown code.

Output ports, Rate2s:

  • rtY.Out1 of type real_T with dimension of 1

More About