diff --git a/source/getting-started/control-with-amdc/autogen/images/autogen-model-subsystem.svg b/source/getting-started/control-with-amdc/autogen/images/autogen-model-subsystem.svg new file mode 100644 index 00000000..55df3a8e --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/images/autogen-model-subsystem.svg @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/getting-started/control-with-amdc/autogen/images/autogen-model.svg b/source/getting-started/control-with-amdc/autogen/images/autogen-model.svg new file mode 100644 index 00000000..e71d87cb --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/images/autogen-model.svg @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/getting-started/control-with-amdc/autogen/images/integrator-model.svg b/source/getting-started/control-with-amdc/autogen/images/integrator-model.svg new file mode 100644 index 00000000..6de4fc27 --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/images/integrator-model.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/getting-started/control-with-amdc/autogen/index.md b/source/getting-started/control-with-amdc/autogen/index.md new file mode 100644 index 00000000..9b0a4bb0 --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/index.md @@ -0,0 +1,170 @@ +# Simulink Automatic Code Generation for AMDC + +This article explains how to implement the Simulink automatic code generation (Autogen) by demonstrating an example using a simple integrator. + +## Simulink Autogen Code + +Autogen is the process of converting a user Simulink model for a controller into equivalent C code for an embedded system (such as the AMDC). The Autogen feature in Simulink can be used to conveniently convert complex controller implementations into C-code for implementing it on the AMDC. This article presents a step-by-step process of using Autogen to convert a simle integrator (as shown in the figure below) into C code. + +```{image} images/integrator-model.svg +:alt: Integrator model +:width: 300px +:align: center +``` + +## Procedure + +### Pre-Requisites + +User needs to install at least the following dedicated MATLAB/Simulink toolboxes/features: + +- Simulink +- Embedded coder +- Simulink coders + +### File Organization + +This article assumes that the uses has completed the [Blink tutorial](../../tutorials/blink/index.md), where you set up your repository. To follow this Autogen tutorial, create a new `simulink` folder in your repository and organize the files as shown below: + +```markdown +my-AMDC-workspace/ <= master repo + AMDC-Firmware/ <= AMDC-Firmware as library + ... + my-AMDC-private-C-code/ <= Your private user C code + ... + simulink/ <= Now create this folder +``` + +### Create a Simulink Model + +1. In `simulink` folder, create a new MATLAB file (e.g., `setup.m`). +2. In `setup.m`, define `fs = 10e3`, `Ts = 1/fs`, `Tsim = Ts/10`. + +User can copy-paste the following MATLAB code: + +```MATLAB +fs = 10e3; % sampling frequency (Hz) +Ts = 1/fs; % sampling time (sec) +Tsim = Ts/10; % simulation time (s) +``` + +3. Open a blank model of Simulink, and save as `setupModel.slx` in `simulink` folder. +4. Add a `Step` block with the default setting. +5. Add a `Discrete-Time Integrator` block with the default setting. +6. Add a `Rate Transition` block before the integrator. In this block, put `Ts` as a sampling time. +7. Add a `Rate Transition` block after the integrator. In this block, set the sampling time to `-1`. +8. Add a continuous-time `Transfer Fcn` block as a Plant (= 1). +9. Add a `Sum` function and connect each block as shown below. + +```{image} images/autogen-model.svg +:alt: Autogen model +:width: 600px +:align: center +``` + +### Model Setting + +1. In `Modeling` tab, press `Model Settings` in `TOP MODEL` section. + 1. Under the `Solver`tree, in the `Solver Selection`, press `Fixed-step`. + 2. Set `Fixed-step-size` as `Tsim`. +2. Go to `Code Generation`. + 1. Click `Browse` for the `System target file`. + 2. Select `ert.tlc Embedded coder`. + 3. In the `Build process` section, check `Generate code only`. +3. Go to `Optimization` under `Code Generation`. + 1. Choose `None` for the `Leverage target hardware instruction set extensions` in the `Target specific optimizations`. +4. Go to `Templates` under `Code Generation`. + 1. Uncheck `Generate an example main program` in the `Custom templates` section. +5. Click `Apply` and `OK`. + +### Create a Referenced Model + +1. Select the discrete-time integrator, and right-click. +2. Select `Create Subsystem from Selection`. +3. Right-click on the subsystem created. Select `Block parameters (Subsystem)`, check `Treat as atomic unit`, and click `OK`. +4. Right-click on the subsystem and select `Subsystem & Model Reference`. Select `Convert` and click `Referenced Model ...`. +5. In the `Input Parameters` section, define the `New model name` as `integrator`. +6. Click `Apply` and `Convert`. +7. Rename the referenced model block to be `integrator`. The expected Simulink model is shown below: + +```{image} images/autogen-model-subsystem.svg +:alt: Autogen model subsystem +:width: 600px +:align: center +``` + +### Referenced Model Setting + +1. Double-click the `integrator` referenced model and click `Model Settings` under `Modeling` tab. +2. Click `Model Settings` in the `REFERENCED MODEL` section. + 1. Set `Fixed-step-size` as `Ts`. +3. Save the Simulink file. + +The example of Simulink file along with the referenced model is stored [here](./simulink/). + +### Generate C-code + +1. Open the `setup.m`. +2. Copy and paste the following code. + +```MATLAB +%% Autogen code for the controller +model='integrator'; % name of the controller to be built +slbuild(model); % generates the Autogen code +oldFolder = cd('C:integrator_ert_rtw\'); +% Copy only .c and .h files in autogen folder +command = 'for /r %i in (*.c, *.h) do copy /y %i ..\autogen'; +[status, cmdout] = system(command); +cd(oldFolder); +``` + +3. Run the `setup.m`, and Autogen code are created in `simulink/autogen` folder. + +### Integration with AMDC + +Now, the user needs to update the user C code to incorporate the Autogen code generated from Simulink. To do this, update `task_controller.c` as follows: + +`task_controller.c`: + +```c +// ... + +int task_controller_clear(void) +{ + // ... + + // Clear state struct for Simulink controller + memset(((void *) &integrator_DW_DW), 0, sizeof(DW_integrator_T)); + + // ... +} + +int task_controller_init(void) +{ + // ... + + // Initialize Autogen step + integrator_initialize(); + + // ... +} + +void task_controller_callback(void *arg) +{ + // ... + + // Update controller input parameters + integrator_U.STEP = STEP; + + // Call Autogen code + integrator_step(); + + // ... +} +``` + +## Results + +THIS SECTION WILL BE UPDATED! + +- After running the AMDC, show the input and output value through logging feature. diff --git a/source/getting-started/control-with-amdc/autogen/simulink/.gitignore b/source/getting-started/control-with-amdc/autogen/simulink/.gitignore new file mode 100644 index 00000000..dc3e33f2 --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/simulink/.gitignore @@ -0,0 +1,5 @@ +# ignore MATLAB files + +**/slprj +*.autosave +*.slxc \ No newline at end of file diff --git a/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator.c b/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator.c new file mode 100644 index 00000000..95f41992 --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator.c @@ -0,0 +1,65 @@ +/* + * Academic License - for use in teaching, academic research, and meeting + * course requirements at degree granting institutions only. Not for + * government, commercial, or other organizational use. + * + * File: integrator.c + * + * Code generated for Simulink model 'integrator'. + * + * Model version : 1.2 + * Simulink Coder version : 25.2 (R2025b) 28-Jul-2025 + * C/C++ source code generated on : Fri Dec 12 15:58:48 2025 + * + * Target selection: ert.tlc + * Embedded hardware selection: Intel->x86-64 (Windows64) + * Code generation objectives: Unspecified + * Validation result: Not run + */ + +#include "integrator.h" + +/* Block states (default storage) */ +DW_integrator_T integrator_DW; + +/* External inputs (root inport signals with default storage) */ +ExtU_integrator_T integrator_U; + +/* External outputs (root outports fed by signals with default storage) */ +ExtY_integrator_T integrator_Y; + +/* Real-time model */ +static RT_MODEL_integrator_T integrator_M_; +RT_MODEL_integrator_T *const integrator_M = &integrator_M_; + +/* Model step function */ +void integrator_step(void) +{ + /* Outport: '/Out1' incorporates: + * DiscreteIntegrator: '/Discrete-Time Integrator' + */ + integrator_Y.Out1 = integrator_DW.DiscreteTimeIntegrator_DSTATE; + + /* Update for DiscreteIntegrator: '/Discrete-Time Integrator' incorporates: + * Inport: '/In1' + */ + integrator_DW.DiscreteTimeIntegrator_DSTATE += 0.0001 * integrator_U.In1; +} + +/* Model initialize function */ +void integrator_initialize(void) +{ + /* (no initialization code required) */ +} + +/* Model terminate function */ +void integrator_terminate(void) +{ + /* (no terminate code required) */ +} + +/* + * File trailer for generated code. + * + * [EOF] + */ diff --git a/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator.h b/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator.h new file mode 100644 index 00000000..e48642c4 --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator.h @@ -0,0 +1,98 @@ +/* + * Academic License - for use in teaching, academic research, and meeting + * course requirements at degree granting institutions only. Not for + * government, commercial, or other organizational use. + * + * File: integrator.h + * + * Code generated for Simulink model 'integrator'. + * + * Model version : 1.2 + * Simulink Coder version : 25.2 (R2025b) 28-Jul-2025 + * C/C++ source code generated on : Fri Dec 12 15:58:48 2025 + * + * Target selection: ert.tlc + * Embedded hardware selection: Intel->x86-64 (Windows64) + * Code generation objectives: Unspecified + * Validation result: Not run + */ + +#ifndef integrator_h_ +#define integrator_h_ +#ifndef integrator_COMMON_INCLUDES_ +#define integrator_COMMON_INCLUDES_ +#include "rtwtypes.h" +#include "math.h" +#endif /* integrator_COMMON_INCLUDES_ */ + +#include "integrator_types.h" + +/* Macros for accessing real-time model data structure */ +#ifndef rtmGetErrorStatus +#define rtmGetErrorStatus(rtm) ((rtm)->errorStatus) +#endif + +#ifndef rtmSetErrorStatus +#define rtmSetErrorStatus(rtm, val) ((rtm)->errorStatus = (val)) +#endif + +/* Block states (default storage) for system '' */ +typedef struct { + real_T DiscreteTimeIntegrator_DSTATE;/* '/Discrete-Time Integrator' */ +} DW_integrator_T; + +/* External inputs (root inport signals with default storage) */ +typedef struct { + real_T In1; /* '/In1' */ +} ExtU_integrator_T; + +/* External outputs (root outports fed by signals with default storage) */ +typedef struct { + real_T Out1; /* '/Out1' */ +} ExtY_integrator_T; + +/* Real-time Model Data Structure */ +struct tag_RTM_integrator_T { + const char_T * volatile errorStatus; +}; + +/* Block states (default storage) */ +extern DW_integrator_T integrator_DW; + +/* External inputs (root inport signals with default storage) */ +extern ExtU_integrator_T integrator_U; + +/* External outputs (root outports fed by signals with default storage) */ +extern ExtY_integrator_T integrator_Y; + +/* Model entry point functions */ +extern void integrator_initialize(void); +extern void integrator_step(void); +extern void integrator_terminate(void); + +/* Real-time Model object */ +extern RT_MODEL_integrator_T *const integrator_M; + +/*- + * The generated code includes comments that allow you to trace directly + * back to the appropriate location in the model. The basic format + * is /block_name, where system is the system number (uniquely + * assigned by Simulink) and block_name is the name of the block. + * + * Use the MATLAB hilite_system command to trace the generated code back + * to the model. For example, + * + * hilite_system('') - opens system 3 + * hilite_system('/Kp') - opens and selects block Kp which resides in S3 + * + * Here is the system hierarchy for this model + * + * '' : 'integrator' + */ +#endif /* integrator_h_ */ + +/* + * File trailer for generated code. + * + * [EOF] + */ diff --git a/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator_private.h b/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator_private.h new file mode 100644 index 00000000..836e1446 --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator_private.h @@ -0,0 +1,30 @@ +/* + * Academic License - for use in teaching, academic research, and meeting + * course requirements at degree granting institutions only. Not for + * government, commercial, or other organizational use. + * + * File: integrator_private.h + * + * Code generated for Simulink model 'integrator'. + * + * Model version : 1.2 + * Simulink Coder version : 25.2 (R2025b) 28-Jul-2025 + * C/C++ source code generated on : Fri Dec 12 15:58:48 2025 + * + * Target selection: ert.tlc + * Embedded hardware selection: Intel->x86-64 (Windows64) + * Code generation objectives: Unspecified + * Validation result: Not run + */ + +#ifndef integrator_private_h_ +#define integrator_private_h_ +#include "rtwtypes.h" +#include "integrator_types.h" +#endif /* integrator_private_h_ */ + +/* + * File trailer for generated code. + * + * [EOF] + */ diff --git a/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator_types.h b/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator_types.h new file mode 100644 index 00000000..6e991e41 --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/simulink/autogen/integrator_types.h @@ -0,0 +1,32 @@ +/* + * Academic License - for use in teaching, academic research, and meeting + * course requirements at degree granting institutions only. Not for + * government, commercial, or other organizational use. + * + * File: integrator_types.h + * + * Code generated for Simulink model 'integrator'. + * + * Model version : 1.2 + * Simulink Coder version : 25.2 (R2025b) 28-Jul-2025 + * C/C++ source code generated on : Fri Dec 12 15:58:48 2025 + * + * Target selection: ert.tlc + * Embedded hardware selection: Intel->x86-64 (Windows64) + * Code generation objectives: Unspecified + * Validation result: Not run + */ + +#ifndef integrator_types_h_ +#define integrator_types_h_ + +/* Forward declaration for rtModel */ +typedef struct tag_RTM_integrator_T RT_MODEL_integrator_T; + +#endif /* integrator_types_h_ */ + +/* + * File trailer for generated code. + * + * [EOF] + */ diff --git a/source/getting-started/control-with-amdc/autogen/simulink/autogen/rtmodel.h b/source/getting-started/control-with-amdc/autogen/simulink/autogen/rtmodel.h new file mode 100644 index 00000000..17e57eab --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/simulink/autogen/rtmodel.h @@ -0,0 +1,34 @@ +/* + * Academic License - for use in teaching, academic research, and meeting + * course requirements at degree granting institutions only. Not for + * government, commercial, or other organizational use. + * + * File: rtmodel.h + * + * Code generated for Simulink model 'integrator'. + * + * Model version : 1.2 + * Simulink Coder version : 25.2 (R2025b) 28-Jul-2025 + * C/C++ source code generated on : Fri Dec 12 15:58:48 2025 + * + * Target selection: ert.tlc + * Embedded hardware selection: Intel->x86-64 (Windows64) + * Code generation objectives: Unspecified + * Validation result: Not run + */ + +#ifndef rtmodel_h_ +#define rtmodel_h_ +#include "integrator.h" + +/* Macros generated for backwards compatibility */ +#ifndef rtmGetStopRequested +#define rtmGetStopRequested(rtm) ((void*) 0) +#endif +#endif /* rtmodel_h_ */ + +/* + * File trailer for generated code. + * + * [EOF] + */ diff --git a/source/getting-started/control-with-amdc/autogen/simulink/autogen/rtwtypes.h b/source/getting-started/control-with-amdc/autogen/simulink/autogen/rtwtypes.h new file mode 100644 index 00000000..e074d42d --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/simulink/autogen/rtwtypes.h @@ -0,0 +1,160 @@ +/* + * Academic License - for use in teaching, academic research, and meeting + * course requirements at degree granting institutions only. Not for + * government, commercial, or other organizational use. + * + * File: rtwtypes.h + * + * Code generated for Simulink model 'integrator'. + * + * Model version : 1.2 + * Simulink Coder version : 25.2 (R2025b) 28-Jul-2025 + * C/C++ source code generated on : Fri Dec 12 15:58:48 2025 + * + * Target selection: ert.tlc + * Embedded hardware selection: Intel->x86-64 (Windows64) + * Code generation objectives: Unspecified + * Validation result: Not run + */ + +#ifndef RTWTYPES_H +#define RTWTYPES_H + +/* Logical type definitions */ +#if (!defined(__cplusplus)) +#ifndef false +#define false (0U) +#endif + +#ifndef true +#define true (1U) +#endif +#endif + +/*=======================================================================* + * Target hardware information + * Device type: Intel->x86-64 (Windows64) + * Number of bits: char: 8 short: 16 int: 32 + * long: 32 + * native word size: 64 + * Byte ordering: LittleEndian + * Signed integer division rounds to: Zero + * Shift right on a signed integer as arithmetic shift: on + *=======================================================================*/ + +/*=======================================================================* + * 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; + +/*===========================================================================* + * Generic type definitions: boolean_T, char_T, byte_T, int_T, uint_T, * + * real_T, time_T, ulong_T. * + *===========================================================================*/ +typedef double real_T; +typedef double time_T; +typedef unsigned char boolean_T; +typedef int int_T; +typedef unsigned int uint_T; +typedef unsigned long ulong_T; +typedef char char_T; +typedef unsigned char uchar_T; +typedef char_T byte_T; + +/*===========================================================================* + * Complex number type definitions * + *===========================================================================*/ +#define CREAL_T + +typedef struct { + real32_T re; + real32_T im; +} creal32_T; + +typedef struct { + real64_T re; + real64_T im; +} creal64_T; + +typedef struct { + real_T re; + real_T im; +} creal_T; + +#define CINT8_T + +typedef struct { + int8_T re; + int8_T im; +} cint8_T; + +#define CUINT8_T + +typedef struct { + uint8_T re; + uint8_T im; +} cuint8_T; + +#define CINT16_T + +typedef struct { + int16_T re; + int16_T im; +} cint16_T; + +#define CUINT16_T + +typedef struct { + uint16_T re; + uint16_T im; +} cuint16_T; + +#define CINT32_T + +typedef struct { + int32_T re; + int32_T im; +} cint32_T; + +#define CUINT32_T + +typedef struct { + uint32_T re; + uint32_T im; +} cuint32_T; + +/*=======================================================================* + * Min and Max: * + * 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 * + *=======================================================================*/ +#define MAX_int8_T ((int8_T)(127)) +#define MIN_int8_T ((int8_T)(-128)) +#define MAX_uint8_T ((uint8_T)(255U)) +#define MAX_int16_T ((int16_T)(32767)) +#define MIN_int16_T ((int16_T)(-32768)) +#define MAX_uint16_T ((uint16_T)(65535U)) +#define MAX_int32_T ((int32_T)(2147483647)) +#define MIN_int32_T ((int32_T)(-2147483647-1)) +#define MAX_uint32_T ((uint32_T)(0xFFFFFFFFU)) + +/* Block D-Work pointer type */ +typedef void * pointer_T; + +#endif /* RTWTYPES_H */ + +/* + * File trailer for generated code. + * + * [EOF] + */ diff --git a/source/getting-started/control-with-amdc/autogen/simulink/integrator.slx b/source/getting-started/control-with-amdc/autogen/simulink/integrator.slx new file mode 100644 index 00000000..76a54d7d Binary files /dev/null and b/source/getting-started/control-with-amdc/autogen/simulink/integrator.slx differ diff --git a/source/getting-started/control-with-amdc/autogen/simulink/setup.asv b/source/getting-started/control-with-amdc/autogen/simulink/setup.asv new file mode 100644 index 00000000..68a1dd0e --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/simulink/setup.asv @@ -0,0 +1,4 @@ + + +Ts = 1/(10e3); %Hz +Tsim = diff --git a/source/getting-started/control-with-amdc/autogen/simulink/setup.m b/source/getting-started/control-with-amdc/autogen/simulink/setup.m new file mode 100644 index 00000000..a98dd334 --- /dev/null +++ b/source/getting-started/control-with-amdc/autogen/simulink/setup.m @@ -0,0 +1,15 @@ +clear; clc; + +fs = 10e3; % sampling frequency (Hz) +Ts = 1/fs; % sampling time (sec) +Tsim = Ts/10; % simulation time (s) + +%% Autogen code for the controller +model='integrator'; % name of the controller to be built +slbuild(model); % generates the Autogen code +oldFolder = cd('C:integrator_ert_rtw\'); +% Copy only .c and .h files in autogen folder +command = 'for /r %i in (*.c, *.h) do copy /y %i ..\autogen'; +[status, cmdout] = system(command); +cd(oldFolder); + diff --git a/source/getting-started/control-with-amdc/autogen/simulink/setupModel.slx b/source/getting-started/control-with-amdc/autogen/simulink/setupModel.slx new file mode 100644 index 00000000..67e8f6ca Binary files /dev/null and b/source/getting-started/control-with-amdc/autogen/simulink/setupModel.slx differ