This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMDSCNCD28335: Sampling Time ADC with Matlab Coder

Part Number: TMDSCNCD28335


Hi team,

I am posting this in behalf of the cusotmer. Good day! 

Here it is:

I am trying to program a F28335 V2.2 ControlCard with Simulink Coder. I tried to implement an ADC and now I am struggling to set a correct sampling time.

The issue that occurs is that when I set the sampling time lower than 2us, the program seems not to work on the controller anymore. The code itself seems to be fine as it can still be compiled. 

I tried to attach the Simulink File but i have gotten an error doing it, so in the end i have inserted an image of it.

I have reduced it to a test enviroment for the ADC and an later added RMS. With this program running, i am able to measure the Digital Output and ensure the ADC is working properly. The ADC is connectet to a square wave generator with a frequency up to 100kHz. As mentioned before, if i reduce the Sample Time of the ADC to 1us, the Output remains zero and is not switch on and off.

I also tried to set the sample time to -1, setting it to inherited according to matlab.

I followed the solution mentioned from following Matlab Support Question, but it didn't help.

https://ch.mathworks.com/matlabcentral/answers/378006-tunability-of-sample-time-in-code-embedded-coder

In the datasheet of the 28335 it is mentioned that the sample time of the ADC can be up to some GHz, so i am not quite sure what is causing my error here.

I hope i have not forgotten anything important to set you in the image.

Thanks in advance.

Best regards,

Jonathan

  • The ADC on this device is capable of 12.5MSPS(80ns sample rate).  Would it be possible to post the C code that simulink generates based on the above block diagram?  There are a couple of factors here, both the sample and hold window that is set to the ADC, as well as the trigger source that simulink sets up to sample the signal.  I think it will be easier for me to see the output code to say exactly what is going on.  Perhaps the customer could post the code at 2us(working) and 1us(not working).

    Best,

    Matthew

  • Hello Matthew,

    Here is the customer's response below.

    Thank you in advance for your help. I have attached once the code for sampling time 2us and 1us. I was not sure if the main code is enough so I attached the whole exported code, I hope that’s no problem.

    I don’t know if this additional information maybe helps:
    The two separate GPIO’s are driving the two LED on the board which should blink with 0.5Hz. If I set the sampling time to 20us, I can see them blinking. Reducing the sample time to 2us, booth LED stay on (not switching very fast, I measured it).

    Best regards,

    Jonathan

  • Jonathan,
    Did the customer send code to attach to the post?  I'm not seeing the attachment.

    Best,

    Matthew

  • Hello Matthew

    Thank you very much for your help and sorry for the inconveniences with the communication. I had problems getting proper access to the forum.

    I don't know if the main code is enough for you to tell something but i will start with that. Else I will be around now.

    Best regards,

    Marius

    Working code with 2us sampling time:

    /*
     * 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: Test_Sampling_Time.c
     *
     * Code generated for Simulink model 'Test_Sampling_Time'.
     *
     * Model version                  : 1.2
     * Simulink Coder version         : 9.5 (R2021a) 14-Nov-2020
     * C/C++ source code generated on : Fri Apr 29 11:13:56 2022
     *
     * Target selection: ert.tlc
     * Embedded hardware selection: Texas Instruments->C2000
     * Code generation objectives: Unspecified
     * Validation result: Not run
     */
    
    #include "Test_Sampling_Time.h"
    #include "Test_Sampling_Time_private.h"
    
    /* Block signals (default storage) */
    B_Test_Sampling_Time_T Test_Sampling_Time_B;
    
    /* Block states (default storage) */
    DW_Test_Sampling_Time_T Test_Sampling_Time_DW;
    
    /* Real-time model */
    static RT_MODEL_Test_Sampling_Time_T Test_Sampling_Time_M_;
    RT_MODEL_Test_Sampling_Time_T *const Test_Sampling_Time_M =
      &Test_Sampling_Time_M_;
    static void rate_monotonic_scheduler(void);
    uint16_T MW_adcInitFlag = 0;
    
    /*
     * Set which subrates need to run this base step (base rate always runs).
     * This function must be called prior to calling the model step function
     * in order to "remember" which rates need to run this base step.  The
     * buffering of events allows for overlapping preemption.
     */
    void Test_Sampling_Time_SetEventsForThisBaseStep(boolean_T *eventFlags)
    {
      /* Task runs when its counter is zero, computed via rtmStepTask macro */
      eventFlags[1] = ((boolean_T)rtmStepTask(Test_Sampling_Time_M, 1));
    }
    
    /*
     *   This function updates active task flag for each subrate
     * and rate transition flags for tasks that exchange data.
     * The function assumes rate-monotonic multitasking scheduler.
     * The function must be called at model base rate so that
     * the generated code self-manages all its subrates and rate
     * transition flags.
     */
    static void rate_monotonic_scheduler(void)
    {
      /* Compute which subrates run during the next base time step.  Subrates
       * are an integer multiple of the base rate counter.  Therefore, the subtask
       * counter is reset when it reaches its limit (zero means run).
       */
      (Test_Sampling_Time_M->Timing.TaskCounters.TID[1])++;
      if ((Test_Sampling_Time_M->Timing.TaskCounters.TID[1]) > 499999) {/* Sample time: [1.0s, 0.0s] */
        Test_Sampling_Time_M->Timing.TaskCounters.TID[1] = 0;
      }
    }
    
    /* Model step function for TID0 */
    void Test_Sampling_Time_step0(void)    /* Sample time: [2.0E-6s, 0.0s] */
    {
      {                                    /* Sample time: [2.0E-6s, 0.0s] */
        rate_monotonic_scheduler();
      }
    
      /* S-Function (c280xadc): '<Root>/Current_Meassurement' */
      {
        AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;  /* Reset SEQ1 module*/
        AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;/*clear INT sequencer*/
        AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1;  /* Software Trigger*/
        while (AdcRegs.ADCST.bit.INT_SEQ1 == 0) {
        }                                  /*Wait for Sequencer INT bit to clear */
    
        asm(" RPT #11 || NOP");
        Test_Sampling_Time_B.Current_Meassurement = (AdcRegs.ADCRESULT0) >> 4;
      }
    
      /* Switch: '<Root>/Switch' incorporates:
       *  Constant: '<Root>/Constant2'
       *  Gain: '<Root>/Gain'
       *  Gain: '<Root>/Gain1'
       *  Sum: '<Root>/Sum'
       */
      if (Test_Sampling_Time_P.Gain1_Gain *
          Test_Sampling_Time_B.Current_Meassurement * Test_Sampling_Time_P.Gain_Gain
          - Test_Sampling_Time_P.Constant2_Value >
          Test_Sampling_Time_P.Switch_Threshold) {
        /* Switch: '<Root>/Switch' incorporates:
         *  Constant: '<Root>/Constant'
         */
        Test_Sampling_Time_B.Switch = Test_Sampling_Time_P.Constant_Value;
      } else {
        /* Switch: '<Root>/Switch' incorporates:
         *  Constant: '<Root>/Constant1'
         */
        Test_Sampling_Time_B.Switch = Test_Sampling_Time_P.Constant1_Value;
      }
    
      /* End of Switch: '<Root>/Switch' */
    
      /* S-Function (c280xgpio_do): '<Root>/GPIO 02' */
      {
        if (Test_Sampling_Time_B.Switch)
          GpioDataRegs.GPASET.bit.GPIO2 = 1;
        else
          GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;
      }
    }
    
    /* Model step function for TID1 */
    void Test_Sampling_Time_step1(void)    /* Sample time: [1.0s, 0.0s] */
    {
      /* DiscretePulseGenerator: '<Root>/Pulse Generator1' */
      Test_Sampling_Time_B.PulseGenerator1 = (Test_Sampling_Time_DW.clockTickCounter
        < Test_Sampling_Time_P.PulseGenerator1_Duty) &&
        (Test_Sampling_Time_DW.clockTickCounter >= 0L) ?
        Test_Sampling_Time_P.PulseGenerator1_Amp : 0.0;
    
      /* DiscretePulseGenerator: '<Root>/Pulse Generator1' */
      if (Test_Sampling_Time_DW.clockTickCounter >=
          Test_Sampling_Time_P.PulseGenerator1_Period - 1.0) {
        Test_Sampling_Time_DW.clockTickCounter = 0L;
      } else {
        Test_Sampling_Time_DW.clockTickCounter++;
      }
    
      /* S-Function (c280xgpio_do): '<Root>/LED 1' */
      {
        if (Test_Sampling_Time_B.PulseGenerator1)
          GpioDataRegs.GPASET.bit.GPIO31 = 1;
        else
          GpioDataRegs.GPACLEAR.bit.GPIO31 = 1;
      }
    
      /* Logic: '<Root>/NOT' */
      Test_Sampling_Time_B.NOT = !(Test_Sampling_Time_B.PulseGenerator1 != 0.0);
    
      /* S-Function (c280xgpio_do): '<Root>/LED2' */
      {
        if (Test_Sampling_Time_B.NOT)
          GpioDataRegs.GPBSET.bit.GPIO34 = 1;
        else
          GpioDataRegs.GPBCLEAR.bit.GPIO34 = 1;
      }
    }
    
    /* Model initialize function */
    void Test_Sampling_Time_initialize(void)
    {
      /* Registration code */
    
      /* initialize real-time model */
      (void) memset((void *)Test_Sampling_Time_M, 0,
                    sizeof(RT_MODEL_Test_Sampling_Time_T));
    
      /* block I/O */
      (void) memset(((void *) &Test_Sampling_Time_B), 0,
                    sizeof(B_Test_Sampling_Time_T));
    
      /* states (dwork) */
      (void) memset((void *)&Test_Sampling_Time_DW, 0,
                    sizeof(DW_Test_Sampling_Time_T));
    
      /* Start for S-Function (c280xadc): '<Root>/Current_Meassurement' */
      if (MW_adcInitFlag == 0) {
        InitAdc();
        MW_adcInitFlag = 1;
      }
    
      config_ADC_A (0U, 0U, 0U, 0U, 0U);
    
      /* Start for S-Function (c280xgpio_do): '<Root>/GPIO 02' */
      EALLOW;
      GpioCtrlRegs.GPAMUX1.all &= 0xFFFFFFCF;
      GpioCtrlRegs.GPADIR.all |= 0x4;
      EDIS;
    
      /* Start for DiscretePulseGenerator: '<Root>/Pulse Generator1' */
      Test_Sampling_Time_DW.clockTickCounter = 0L;
    
      /* Start for S-Function (c280xgpio_do): '<Root>/LED 1' */
      EALLOW;
      GpioCtrlRegs.GPAMUX2.all &= 0x3FFFFFFF;
      GpioCtrlRegs.GPADIR.all |= 0x80000000;
      EDIS;
    
      /* Start for S-Function (c280xgpio_do): '<Root>/LED2' */
      EALLOW;
      GpioCtrlRegs.GPBMUX1.all &= 0xFFFFFFCF;
      GpioCtrlRegs.GPBDIR.all |= 0x4;
      EDIS;
    }
    
    /* Model terminate function */
    void Test_Sampling_Time_terminate(void)
    {
      /* (no terminate code required) */
    }
    
    /*
     * File trailer for generated code.
     *
     * [EOF]
     */
    

    Not working code with 1us sampling time:

    /*
     *
     * File: Test_Sampling_Time.c
     *
     * Code generated for Simulink model 'Test_Sampling_Time'.
     *
     * Model version                  : 1.2
     * Simulink Coder version         : 9.5 (R2021a) 14-Nov-2020
     * C/C++ source code generated on : Fri Apr 29 11:12:24 2022
     *
     * Target selection: ert.tlc
     * Embedded hardware selection: Texas Instruments->C2000
     * Code generation objectives: Unspecified
     * Validation result: Not run
     */
    
    #include "Test_Sampling_Time.h"
    #include "Test_Sampling_Time_private.h"
    
    /* Block signals (default storage) */
    B_Test_Sampling_Time_T Test_Sampling_Time_B;
    
    /* Block states (default storage) */
    DW_Test_Sampling_Time_T Test_Sampling_Time_DW;
    
    /* Real-time model */
    static RT_MODEL_Test_Sampling_Time_T Test_Sampling_Time_M_;
    RT_MODEL_Test_Sampling_Time_T *const Test_Sampling_Time_M =
      &Test_Sampling_Time_M_;
    static void rate_monotonic_scheduler(void);
    uint16_T MW_adcInitFlag = 0;
    
    /*
     * Set which subrates need to run this base step (base rate always runs).
     * This function must be called prior to calling the model step function
     * in order to "remember" which rates need to run this base step.  The
     * buffering of events allows for overlapping preemption.
     */
    void Test_Sampling_Time_SetEventsForThisBaseStep(boolean_T *eventFlags)
    {
      /* Task runs when its counter is zero, computed via rtmStepTask macro */
      eventFlags[1] = ((boolean_T)rtmStepTask(Test_Sampling_Time_M, 1));
    }
    
    /*
     *   This function updates active task flag for each subrate
     * and rate transition flags for tasks that exchange data.
     * The function assumes rate-monotonic multitasking scheduler.
     * The function must be called at model base rate so that
     * the generated code self-manages all its subrates and rate
     * transition flags.
     */
    static void rate_monotonic_scheduler(void)
    {
      /* Compute which subrates run during the next base time step.  Subrates
       * are an integer multiple of the base rate counter.  Therefore, the subtask
       * counter is reset when it reaches its limit (zero means run).
       */
      (Test_Sampling_Time_M->Timing.TaskCounters.TID[1])++;
      if ((Test_Sampling_Time_M->Timing.TaskCounters.TID[1]) > 999999) {/* Sample time: [1.0s, 0.0s] */
        Test_Sampling_Time_M->Timing.TaskCounters.TID[1] = 0;
      }
    }
    
    /* Model step function for TID0 */
    void Test_Sampling_Time_step0(void)    /* Sample time: [1.0E-6s, 0.0s] */
    {
      {                                    /* Sample time: [1.0E-6s, 0.0s] */
        rate_monotonic_scheduler();
      }
    
      /* S-Function (c280xadc): '<Root>/Current_Meassurement' */
      {
        AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;  /* Reset SEQ1 module*/
        AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;/*clear INT sequencer*/
        AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1;  /* Software Trigger*/
        while (AdcRegs.ADCST.bit.INT_SEQ1 == 0) {
        }                                  /*Wait for Sequencer INT bit to clear */
    
        asm(" RPT #11 || NOP");
        Test_Sampling_Time_B.Current_Meassurement = (AdcRegs.ADCRESULT0) >> 4;
      }
    
      /* Switch: '<Root>/Switch' incorporates:
       *  Constant: '<Root>/Constant2'
       *  Gain: '<Root>/Gain'
       *  Gain: '<Root>/Gain1'
       *  Sum: '<Root>/Sum'
       */
      if (Test_Sampling_Time_P.Gain1_Gain *
          Test_Sampling_Time_B.Current_Meassurement * Test_Sampling_Time_P.Gain_Gain
          - Test_Sampling_Time_P.Constant2_Value >
          Test_Sampling_Time_P.Switch_Threshold) {
        /* Switch: '<Root>/Switch' incorporates:
         *  Constant: '<Root>/Constant'
         */
        Test_Sampling_Time_B.Switch = Test_Sampling_Time_P.Constant_Value;
      } else {
        /* Switch: '<Root>/Switch' incorporates:
         *  Constant: '<Root>/Constant1'
         */
        Test_Sampling_Time_B.Switch = Test_Sampling_Time_P.Constant1_Value;
      }
    
      /* End of Switch: '<Root>/Switch' */
    
      /* S-Function (c280xgpio_do): '<Root>/GPIO 02' */
      {
        if (Test_Sampling_Time_B.Switch)
          GpioDataRegs.GPASET.bit.GPIO2 = 1;
        else
          GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;
      }
    }
    
    /* Model step function for TID1 */
    void Test_Sampling_Time_step1(void)    /* Sample time: [1.0s, 0.0s] */
    {
      /* DiscretePulseGenerator: '<Root>/Pulse Generator1' */
      Test_Sampling_Time_B.PulseGenerator1 = (Test_Sampling_Time_DW.clockTickCounter
        < Test_Sampling_Time_P.PulseGenerator1_Duty) &&
        (Test_Sampling_Time_DW.clockTickCounter >= 0L) ?
        Test_Sampling_Time_P.PulseGenerator1_Amp : 0.0;
    
      /* DiscretePulseGenerator: '<Root>/Pulse Generator1' */
      if (Test_Sampling_Time_DW.clockTickCounter >=
          Test_Sampling_Time_P.PulseGenerator1_Period - 1.0) {
        Test_Sampling_Time_DW.clockTickCounter = 0L;
      } else {
        Test_Sampling_Time_DW.clockTickCounter++;
      }
    
      /* S-Function (c280xgpio_do): '<Root>/LED 1' */
      {
        if (Test_Sampling_Time_B.PulseGenerator1)
          GpioDataRegs.GPASET.bit.GPIO31 = 1;
        else
          GpioDataRegs.GPACLEAR.bit.GPIO31 = 1;
      }
    
      /* Logic: '<Root>/NOT' */
      Test_Sampling_Time_B.NOT = !(Test_Sampling_Time_B.PulseGenerator1 != 0.0);
    
      /* S-Function (c280xgpio_do): '<Root>/LED2' */
      {
        if (Test_Sampling_Time_B.NOT)
          GpioDataRegs.GPBSET.bit.GPIO34 = 1;
        else
          GpioDataRegs.GPBCLEAR.bit.GPIO34 = 1;
      }
    }
    
    /* Model initialize function */
    void Test_Sampling_Time_initialize(void)
    {
      /* Registration code */
    
      /* initialize real-time model */
      (void) memset((void *)Test_Sampling_Time_M, 0,
                    sizeof(RT_MODEL_Test_Sampling_Time_T));
    
      /* block I/O */
      (void) memset(((void *) &Test_Sampling_Time_B), 0,
                    sizeof(B_Test_Sampling_Time_T));
    
      /* states (dwork) */
      (void) memset((void *)&Test_Sampling_Time_DW, 0,
                    sizeof(DW_Test_Sampling_Time_T));
    
      /* Start for S-Function (c280xadc): '<Root>/Current_Meassurement' */
      if (MW_adcInitFlag == 0) {
        InitAdc();
        MW_adcInitFlag = 1;
      }
    
      config_ADC_A (0U, 0U, 0U, 0U, 0U);
    
      /* Start for S-Function (c280xgpio_do): '<Root>/GPIO 02' */
      EALLOW;
      GpioCtrlRegs.GPAMUX1.all &= 0xFFFFFFCF;
      GpioCtrlRegs.GPADIR.all |= 0x4;
      EDIS;
    
      /* Start for DiscretePulseGenerator: '<Root>/Pulse Generator1' */
      Test_Sampling_Time_DW.clockTickCounter = 0L;
    
      /* Start for S-Function (c280xgpio_do): '<Root>/LED 1' */
      EALLOW;
      GpioCtrlRegs.GPAMUX2.all &= 0x3FFFFFFF;
      GpioCtrlRegs.GPADIR.all |= 0x80000000;
      EDIS;
    
      /* Start for S-Function (c280xgpio_do): '<Root>/LED2' */
      EALLOW;
      GpioCtrlRegs.GPBMUX1.all &= 0xFFFFFFCF;
      GpioCtrlRegs.GPBDIR.all |= 0x4;
      EDIS;
    }
    
    /* Model terminate function */
    void Test_Sampling_Time_terminate(void)
    {
      /* (no terminate code required) */
    }
    
    /*
     * File trailer for generated code.
     *
     * [EOF]
     */

  • Thanks for posting this, something in the function rate_monotonic_scheduler doesn't make sense to me, in the 2us version the counter for the loop is 499999. whereas for 1us it is 999999.  I would think that the 1us should be half the 2us, not double.  Both numbers are >16-bits so I don't think there is a casting issue.

    I will see if the MW team can give some insight as to what exactly is going on with the timer function and how it is eventually calling the ADC SOC.

    Best,

    Matthew

  • Hi Jonathan,

    Could you share the model to help us reproduce the issue?

    Best Regards,

    Ram Alla | MathWorks

  • Test_Sampling_Time.zip

    Dear Ram, thank you for your response.

    Thank you for your response, I am the costumer in whose behalf Jonathan posted this issue. I have attached the model to this message.

    Best Regards,

    Marius