Tool/software: Code Composer Studio
Hi to all,
I'm having troubles to implement a C code generated with Simulink Embedded Coder of a model that contains a Delay Block. To simplify things I created a very simple Simulink model that constains only a delay and a subtraction. The model should run every second so I selected a fixed-step discrete solver with fundamental step-size of 1s.
When I generate C code using the Embedded Coder I get the 3 files to be imported inside the CCS workspace: "Model.c", "Model.h", "rtwtypes.h" (this simply contains the definition of the Simulink data types).
"Prova4.c"
/* * 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: Prova4.c * * Code generated for Simulink model 'Prova4'. * * Model version : 1.11 * Simulink Coder version : 9.2 (R2019b) 18-Jul-2019 * C/C++ source code generated on : Sat Aug 22 11:32:42 2020 * * Target selection: ert.tlc * Embedded hardware selection: ARM Compatible->ARM Cortex * Code generation objectives: Unspecified * Validation result: Not run */ #include "Prova4.h" /*===========* * Constants * *===========*/ #define RT_PI 3.14159265358979323846 #define RT_PIF 3.1415927F #define RT_LN_10 2.30258509299404568402 #define RT_LN_10F 2.3025851F #define RT_LOG10E 0.43429448190325182765 #define RT_LOG10EF 0.43429449F #define RT_E 2.7182818284590452354 #define RT_EF 2.7182817F /* * UNUSED_PARAMETER(x) * Used to specify that a function parameter (argument) is required but not * accessed by the function body. */ #ifndef UNUSED_PARAMETER # if defined(__LCC__) # define UNUSED_PARAMETER(x) /* do nothing */ # else /* * This is the semi-ANSI standard way of indicating that an * unused function parameter is required. */ # define UNUSED_PARAMETER(x) (void) (x) # endif #endif /* Model step function */ void Prova4_step(RT_MODEL_Prova4_T *const Prova4_M, real_T Prova4_U_INPUT, real_T *Prova4_Y_OUTPUT) { DW_Prova4_T *Prova4_DW = ((DW_Prova4_T *) Prova4_M->dwork); /* Outport: '<Root>/OUTPUT' incorporates: * Constant: '<Root>/Constant' * Delay: '<Root>/Delay' * Sum: '<Root>/Subtract' */ *Prova4_Y_OUTPUT = 3.0 - Prova4_DW->Delay_DSTATE; /* Update for Delay: '<Root>/Delay' incorporates: * Inport: '<Root>/INPUT' */ Prova4_DW->Delay_DSTATE = Prova4_U_INPUT; } /* Model initialize function */ void Prova4_initialize(RT_MODEL_Prova4_T *const Prova4_M, real_T *Prova4_U_INPUT, real_T *Prova4_Y_OUTPUT) { DW_Prova4_T *Prova4_DW = ((DW_Prova4_T *) Prova4_M->dwork); /* Registration code */ /* states (dwork) */ (void) memset((void *)Prova4_DW, 0, sizeof(DW_Prova4_T)); /* external inputs */ *Prova4_U_INPUT = 0.0; /* external outputs */ (*Prova4_Y_OUTPUT) = 0.0; } /* Model terminate function */ void Prova4_terminate(RT_MODEL_Prova4_T *const Prova4_M) { /* (no terminate code required) */ UNUSED_PARAMETER(Prova4_M); } /* * File trailer for generated code. * * [EOF] */
"Prova4.h"
/* * 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: Prova4.h * * Code generated for Simulink model 'Prova4'. * * Model version : 1.11 * Simulink Coder version : 9.2 (R2019b) 18-Jul-2019 * C/C++ source code generated on : Sat Aug 22 11:32:42 2020 * * Target selection: ert.tlc * Embedded hardware selection: ARM Compatible->ARM Cortex * Code generation objectives: Unspecified * Validation result: Not run */ #ifndef RTW_HEADER_Prova4_h_ #define RTW_HEADER_Prova4_h_ #include <string.h> #ifndef Prova4_COMMON_INCLUDES_ # define Prova4_COMMON_INCLUDES_ #include "rtwtypes.h" #endif /* Prova4_COMMON_INCLUDES_ */ /* 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 /* Forward declaration for rtModel */ typedef struct tag_RTM_Prova4_T RT_MODEL_Prova4_T; /* Block states (default storage) for system '<Root>' */ typedef struct { real_T Delay_DSTATE; /* '<Root>/Delay' */ } DW_Prova4_T; /* Real-time Model Data Structure */ struct tag_RTM_Prova4_T { const char_T * volatile errorStatus; DW_Prova4_T *dwork; }; /* Model entry point functions */ extern void Prova4_initialize(RT_MODEL_Prova4_T *const Prova4_M, real_T *Prova4_U_INPUT, real_T *Prova4_Y_OUTPUT); extern void Prova4_step(RT_MODEL_Prova4_T *const Prova4_M, real_T Prova4_U_INPUT, real_T *Prova4_Y_OUTPUT); extern void Prova4_terminate(RT_MODEL_Prova4_T *const Prova4_M); /*- * The generated code includes comments that allow you to trace directly * back to the appropriate location in the model. The basic format * is <system>/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('<S3>') - opens system 3 * hilite_system('<S3>/Kp') - opens and selects block Kp which resides in S3 * * Here is the system hierarchy for this model * * '<Root>' : 'Prova4' */ #endif /* RTW_HEADER_Prova4_h_ */ /* * File trailer for generated code. * * [EOF] */
The generation of code from Simulink also generates a file which shows how to implement the code in an external environment, "ert_main.c":
/* * 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: ert_main.c * * Code generated for Simulink model 'Prova4'. * * Model version : 1.11 * Simulink Coder version : 9.2 (R2019b) 18-Jul-2019 * C/C++ source code generated on : Sat Aug 22 11:32:42 2020 * * Target selection: ert.tlc * Embedded hardware selection: ARM Compatible->ARM Cortex * Code generation objectives: Unspecified * Validation result: Not run */ #include <stddef.h> #include <stdio.h> /* This ert_main.c example uses printf/fflush */ #include "Prova4.h" /* Model's header file */ #include "rtwtypes.h" static RT_MODEL_Prova4_T Prova4_M_; static RT_MODEL_Prova4_T *const Prova4_MPtr = &Prova4_M_;/* Real-time model */ static DW_Prova4_T Prova4_DW; /* Observable states */ /* '<Root>/INPUT' */ static real_T Prova4_U_INPUT; /* '<Root>/OUTPUT' */ static real_T Prova4_Y_OUTPUT; /* * Associating rt_OneStep with a real-time clock or interrupt service routine * is what makes the generated code "real-time". The function rt_OneStep is * always associated with the base rate of the model. Subrates are managed * by the base rate from inside the generated code. Enabling/disabling * interrupts and floating point context switches are target specific. This * example code indicates where these should take place relative to executing * the generated code step function. Overrun behavior should be tailored to * your application needs. This example simply sets an error status in the * real-time model and returns from rt_OneStep. */ void rt_OneStep(RT_MODEL_Prova4_T *const Prova4_M); void rt_OneStep(RT_MODEL_Prova4_T *const Prova4_M) { static boolean_T OverrunFlag = false; /* Disable interrupts here */ /* Check for overrun */ if (OverrunFlag) { rtmSetErrorStatus(Prova4_M, "Overrun"); return; } OverrunFlag = true; /* Save FPU context here (if necessary) */ /* Re-enable timer or interrupt here */ /* Set model inputs here */ /* Step the model */ Prova4_step(Prova4_M, Prova4_U_INPUT, &Prova4_Y_OUTPUT); /* Get model outputs here */ /* Indicate task complete */ OverrunFlag = false; /* Disable interrupts here */ /* Restore FPU context here (if necessary) */ /* Enable interrupts here */ } /* * The example "main" function illustrates what is required by your * application code to initialize, execute, and terminate the generated code. * Attaching rt_OneStep to a real-time clock is target specific. This example * illustrates how you do this relative to initializing the model. */ int_T main(int_T argc, const char *argv[]) { RT_MODEL_Prova4_T *const Prova4_M = Prova4_MPtr; /* Unused arguments */ (void)(argc); (void)(argv); /* Pack model data into RTM */ Prova4_M->dwork = &Prova4_DW; /* Initialize model */ Prova4_initialize(Prova4_M, &Prova4_U_INPUT, &Prova4_Y_OUTPUT); /* Attach rt_OneStep to a timer or interrupt service routine with * period 1.0 seconds (the model's base sample time) here. The * call syntax for rt_OneStep is * * rt_OneStep(Prova4_M); */ printf("Warning: The simulation will run forever. " "Generated ERT main won't simulate model step behavior. " "To change this behavior select the 'MAT-file logging' option.\n"); fflush((NULL)); while (rtmGetErrorStatus(Prova4_M) == (NULL)) { /* Perform other application tasks here */ } /* Disable rt_OneStep() here */ /* Terminate model */ Prova4_terminate(Prova4_M); return 0; } /* * File trailer for generated code. * * [EOF] */
In CCS I have a project that samples voltage with an ADC, and generates a interrupt service routine that executes every 1000ms (1s) in which the model should execute and the red LED should toggle. If I follow the example provided in "ert_main.c" to integrate the code.
Then if I run the code it immediately stops and the red LED toggles only once, remaining on. By using breakpoints, it seems that the code stops when it should update the content stored by the delay inside "Prova4.c":
/* Update for Delay: '<Root>/Delay' incorporates: * Inport: '<Root>/INPUT' */ Prova4_DW->Delay_DSTATE = Prova4_U_INPUT;
I believe it's a problem concernig the Simulink delay block and it's implementation in the firmware because if I follow the same procedure with many other Simulink models not containing a delay they all work.
Do you have any idea on how to solve this problem?
Many thanks.