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.

CCS/TMS320F28379D: PID Controller

Part Number: TMS320F28379D
Other Parts Discussed in Thread: C2000WARE, CONTROLSUITE

Tool/software: Code Composer Studio

Hi,

I am directly trying to use F28069_PID example project  in DCL folder in ("C:\ti\c2000\C2000Ware_2_00_00_02\libraries\control\DCL\c28\examples\F28069_PID"). I know the headers are different in submodules but how can I fix it? Here is what I did after importing the project:

1)I used (Link File to Project) to link my target configuration.

The project Builds. After hitting Debug, when I am trying to run it, in the first try nothing happens. The  Debug window shows           0x3FE493 (no symbols are defined). If I hit the Resume button again, I show running. And at the same time shows: Break at address "0x3fe493" with no debug information available, or outside of program code.

Disassembly page : 3fe493:   7625        ESTOP0 

I appreciate if there is any help. I don't feed any input and not connecting any jumper wires. I was just trying to run the project first.     

Also, to check the output results I need to check "ADCRESULT0" in Memory Browser page. Right?

  • Mohammad,

    The basic steps are to a) get the right device support files b) modify the memory linker command file to match the device you are using.   I would approach this as:

    • Modify the projectspec file to use the device_support content in for the F2837xD device (instead of F2806x).   These files will be copied into the workspace when you import the project.  
    • Modify the example DCL source to #include the correct header files. (i.e. 2837x... instead of 2806x).  The compiler will complain if you miss any.
    • The linker command files will need to be modified. 
      • Remove F28069_stdmem.cmd, instead use 2837xD_RAM_lnk_cpu1.cmd
      • Modify F28069_DCL.cmd so the sections match memory definitions in the 2837xD_RAM_lnk_cpu1.cmd file. This example does not use CLA so you can comment out those sections.

    Regards

    Lori

  • Dear Lori,

    I much appreciate your help and support. I am not sure if I understood how to modify F28069_DCL.cmd. 

    Regards,

    Mohammad

  • Dear Lori,

    Please apologize me for my multiple questions. For modification of the CMD file, do you mean to match the sections in the F28069_DCL.cmd with 2837xD_RAM_lnk_cpu1.cmd?

    If so, there are some sections in the F28069_DCL such as ".code" and ".cio"  which there is no match for them in 2837xD_RAM_lnk_cpu1.cmd.

    Regards,

    Mohammad

  • Mohammad Kh said:
    For modification of the CMD file, do you mean to match the sections in the F28069_DCL.cmd with 2837xD_RAM_lnk_cpu1.cmd?

    Yes, the memory region names in the DCL.cmd file should match memory names defined in the RAM_link_cpu1.cmd file.   What this does it tells the linker "all .text goes into this memory" 

    Mohammad Kh said:
    If so, there are some sections in the F28069_DCL such as ".code" and ".cio"  which there is no match for them in 2837xD_RAM_lnk_cpu1.cmd.

    .code can go into the same memory block used for .text or .TI.ramfuncs.    These are all related to code. 

    .cio can go into the same section as .const     These are constants used by the printf instructions.  Having said this, I don't think the examples actually use this section, but it doesn't hurt to have it assigned to a memory region.

    You may find section 2 of the hands-on workshop helpful.  Linker command files are discussed.

    https://training.ti.com/c2000-f2837xd-microcontroller-workshop?cu=1137791

    Linker command files are documented in http://www.ti.com/lit/spru513  and compiler generated sections in http://www.ti.com/lit/spru514

    -Lori

  • Thank you very much for your help. Here is what I did:

    A) Changing CMD file

    B)Importing F2837xD source files

    C) changing some parts of the code since the structure bit fields are slightly different

    I still have errors when I Build. I have been including the  capture of the screen.

    Regards

    Mohammad

  • Mohammad,

    On our newer devices we have a driverlib in addition to the bit-field headers.  driverlib.h is included in the device.h file.  

    For this specific example, which doesn't use driverlib, you can comment out the #include within device.h.  I like to put #warn messages to myself so I know I edited standard content.  :) 

    //
    // Included Files
    //
    #warn Commented out because I'm not using driverlib
    // #include "driverlib.h"
    

    -Lori

  • Dear Lori,

    I tried that but still receiving the same errors plus new ones. I have included the project and also the screenshot of the errors. I also searched the forum for related threads but unfortunately didn't find anything related. I appreciate if you could let me know how can I fix it.

    Regards F28069_PID_Test.zip

  • Before I give more advice that may not pan out - I want to look at this closer and get back to you.  My goal is to respond back before end of day Wednesday.

    I regret my advice up to this point has introduced some issues. 

    Regards,

    Lori

  • Mohammad,

    I wanted to provide an update.  The library owner is out of the office and I have some questions for him in order to complete the example and port.  I will provide an updated status to you by end of business day in the US on Wednesday 10/2.

    Thank you for your patience.

    Regards

    Lori

  • It's a lot easier to modify a basic F28379D example to add DCL than to port an F28069 project over to a different device.

    What I suggest is this:

    - Open the F28379D example for PWM triggered ADC at the default C2000Ware path (this is the newest version):
            C:\ti\c2000\C2000Ware_2_00_00_03\device_support\f2837xd\examples\cpu1\adc_soc_epwm

    - Remove the source file "adc_soc_epwm_cpu01.c" from the project and add the one attached to this post. All I've done is add the PID controller and configure PWM1A to come out on GPIO0, just as in the '069 example.

    - Add the include path for the DCL to the project properties as follows:
            - In the CCS Edit perspective, right-click on the project name and select "Properties". Go to CCS Build -> C2000 Compiler -> Include Options
            - Add the DCL include path to the lower window:
            C:\ti\c2000\C2000Ware_2_00_00_03\libraries\control\DCL\c28\include

     - Build, load and run the program.

    This reads in an analog input on pin A0, subtracts it from a reference, and passes the difference to a PID controller. The controller output modulates the duty cycle of PWM1A. If you're using a LaunchPad, monitor pin J4/10 (PWM 1A) with an oscilloscope. Then connect a wire between J3/30 (ADC A0) and J5/3V3. You should observe changing PWM duty cycle. This is working fine at my desk.  You can also feed a variable analogue reference into J3/30 if you have one.

    This is exactly what the '069 example does. It will then be for you to add whatever additional functionality you need to the code.

    Hope this helps.  Post back if anything's not clear.

    Regards,

    Richard

    //###########################################################################
    //
    // FILE:   adc_soc_epwm_cpu01.c
    //
    // TITLE:  ADC triggering via epwm for F2837xD.
    //
    //! \addtogroup cpu01_example_list
    //! <h1> ADC ePWM Triggering (adc_soc_epwm)</h1>
    //!
    //! This example sets up the ePWM to periodically trigger the ADC.
    //!
    //! After the program runs, the memory will contain:\n
    //! - \b AdcaResults \b: A sequence of analog-to-digital conversion samples from
    //! pin A0. The time between samples is determined based on the period
    //! of the ePWM timer.
    //
    //###########################################################################
    // $TI Release: F2837xD Support Library v3.07.00.00 $
    // $Release Date: Sun Sep 29 07:34:54 CDT 2019 $
    // $Copyright:
    // Copyright (C) 2013-2019 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //###########################################################################
    
    //
    // Included Files
    //
    #include "F28x_Project.h"
    #include "DCLF32.h"
    
    //
    // Function Prototypes
    //
    void ConfigureADC(void);
    void ConfigureEPWM(void);
    void SetupADCEpwm(Uint16 channel);
    interrupt void adca1_isr(void);
    
    //
    // Defines
    //
    #define RESULTS_BUFFER_SIZE 256
    
    //
    // Globals
    //
    Uint16 AdcaResults[RESULTS_BUFFER_SIZE];
    Uint16 resultsIndex;
    volatile Uint16 bufferFull;
    
    float rk = 0.25f;
    float yk;
    float lk;
    float uk;
    DCL_PID pid1 = PID_DEFAULTS;
    float Duty;
    float upperlim = 0.95f;
    float lowerlim = 0.05f;
    unsigned int clampactive;
    
    
    void main(void)
    {
    //
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2837xD_SysCtrl.c file.
    //
        InitSysCtrl();
    
    //
    // Step 2. Initialize GPIO:
    // This example function is found in the F2837xD_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    //
        InitGpio(); // Skipped for this example
    
    //
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    //
        DINT;
    
    //
    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the F2837xD_PieCtrl.c file.
    //
        InitPieCtrl();
    
    //
    // Disable CPU interrupts and clear all CPU interrupt flags:
    //
        IER = 0x0000;
        IFR = 0x0000;
    
    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F2837xD_DefaultIsr.c.
    // This function is found in F2837xD_PieVect.c.
    //
        InitPieVectTable();
    
    //
    // Map ISR functions
    //
        EALLOW;
        PieVectTable.ADCA1_INT = &adca1_isr; //function for ADCA interrupt 1
        EDIS;
    
    //
    // Configure the ADC and power it up
    //
        ConfigureADC();
    
    //
    // Configure the ePWM
    //
        ConfigureEPWM();
    
    //
    // Setup the ADC for ePWM triggered conversions on channel 0
    //
        SetupADCEpwm(0);
        EALLOW;
        GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1;    // Disable pull-up on GPIO0 (EPWM1A)
        GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;   // Configure GPIO0 as EPWM1A
        EDIS;
    
    /* initialise controller variables */
        pid1.Kp = 9.0f;
        pid1.Ki = 0.015f;
        pid1.Kd = 0.35f;
        pid1.Kr = 1.0f;
        pid1.c1 = 188.0296600613396f;
        pid1.c2 = 0.880296600613396f;
        pid1.d2 = 0.0f;
        pid1.d3 = 0.0f;
        pid1.i10 = 0.0f;
        pid1.i14 = 1.0f;
        pid1.Umax = 1.0f;
        pid1.Umin = -1.0f;
    
        rk = 0.25f;                             // initial value for control reference
        lk = 1.0f;                              // control loop not saturated
    
    //
    // Enable global Interrupts and higher priority real-time debug events:
    //
        IER |= M_INT1; //Enable group 1 interrupts
        EINT;  // Enable Global interrupt INTM
        ERTM;  // Enable Global realtime interrupt DBGM
    
    //
    // enable PIE interrupt
    //
        PieCtrlRegs.PIEIER1.bit.INTx1 = 1;
    
    //
    // sync ePWM
    //
        EALLOW;
        CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    
    //
    //start ePWM
    //
        EPwm1Regs.ETSEL.bit.SOCAEN = 1;  //enable SOCA
        EPwm1Regs.TBCTL.bit.CTRMODE = 0; //unfreeze, and enter up count mode
    
    
        do
        {
    
        }while(1);
    }
    
    //
    // ConfigureADC - Write ADC configurations and power up the ADC for both
    //                ADC A and ADC B
    //
    void ConfigureADC(void)
    {
        EALLOW;
    
        //
        //write configurations
        //
        AdcaRegs.ADCCTL2.bit.PRESCALE = 6; //set ADCCLK divider to /4
        AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);
    
        //
        //Set pulse positions to late
        //
        AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1;
    
        //
        //power up the ADC
        //
        AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1;
    
        //
        //delay for 1ms to allow ADC time to power up
        //
        DELAY_US(1000);
    
        EDIS;
    }
    
    //
    // ConfigureEPWM - Configure EPWM SOC and compare values
    //
    void ConfigureEPWM(void)
    {
        EALLOW;
        // Assumes ePWM clock is already enabled
        EPwm1Regs.ETSEL.bit.SOCAEN    = 0;    // Disable SOC on A group
        EPwm1Regs.ETSEL.bit.SOCASEL    = 4;   // Select SOC on up-count
        EPwm1Regs.ETPS.bit.SOCAPRD = 1;       // Generate pulse on 1st event
        EPwm1Regs.CMPA.bit.CMPA = 0x0800;     // Set compare A value to 2048 counts
        EPwm1Regs.TBPRD = 0x1000;             // Set period to 4096 counts
    
        // Setup shadow register load on ZERO
        EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
        EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
        EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
        EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
        // Set actions
        EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET;            // Set PWM1A on Zero
        EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;          // Clear PWM1A on event A up count
    
        EPwm1Regs.TBCTL.bit.CTRMODE = 3;      // freeze counter
        EDIS;
    }
    
    //
    // SetupADCEpwm - Setup ADC EPWM acquisition window
    //
    void SetupADCEpwm(Uint16 channel)
    {
        Uint16 acqps;
    
        //
        // Determine minimum acquisition window (in SYSCLKS) based on resolution
        //
        if(ADC_RESOLUTION_12BIT == AdcaRegs.ADCCTL2.bit.RESOLUTION)
        {
            acqps = 14; //75ns
        }
        else //resolution is 16-bit
        {
            acqps = 63; //320ns
        }
    
        //
        //Select the channels to convert and end of conversion flag
        //
        EALLOW;
        AdcaRegs.ADCSOC0CTL.bit.CHSEL = channel;  //SOC0 will convert pin A0
        AdcaRegs.ADCSOC0CTL.bit.ACQPS = acqps; //sample window is 100 SYSCLK cycles
        AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; //trigger on ePWM1 SOCA/C
        AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; //end of SOC0 will set INT1 flag
        AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1;   //enable INT1 flag
        AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared
        EDIS;
    }
    
    //
    // adca1_isr - Read ADC Buffer in ISR
    //
    interrupt void adca1_isr(void)
    {
        // read ADC channel
        yk = ((float) AdcaResultRegs.ADCRESULT0 - 2048.0f) / 2047.0f;
    
        // run PID controller
        uk = DCL_runPID_C3(&pid1, rk, yk, lk);
    
        // external clamp for anti-windup reset
        clampactive = DCL_runClamp_C2(&uk, upperlim, lowerlim);
        lk = (clampactive == 0U) ? 1.0f : 0.0f;
    
        // write u(k) to PWM
        Duty = (uk / 2.0f + 0.5f) * (float) EPwm1Regs.TBPRD;
        EPwm1Regs.CMPA.bit.CMPA = (Uint16) Duty;
    
        AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear INT1 flag
    
        //
        // Check if overflow has occurred
        //
        if(1 == AdcaRegs.ADCINTOVF.bit.ADCINT1)
        {
            AdcaRegs.ADCINTOVFCLR.bit.ADCINT1 = 1; //clear INT1 overflow flag
            AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear INT1 flag
        }
    
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    }
    
    //
    // End of file
    //
    

  • Dear Richard,

    Thank you very much for your response. It is really helpful, I followed the steps and it is working in the same way as you mentioned. I am just wondering to ask a couple of questions about it.

    1. Based on DCL manual (C2000™ Digital Controller Library): for using functions, the linker command file needs to be modified to include dclfuns. I checked the file in Project Properties>C2000 Linker and I am not sure that I understood how it is has been modified.

    2. Having two cascaded PI(D): I need to set the result of the first PID (uk1) as the reference of the second loop. Correct?

    3. What is the reason behind this calculation :((float) AdcaResultRegs.ADCRESULT0 - 2048.0f) / 2047.0f;

    4. I am working on controlling the power electronic converters. In that context, I need to use Park and Clarke transformation before controlling the signals. As much as I know IQmath library supports that. For example, I have read the motor control project in Control Suite ("C:\ti\controlSUITE\development_kits\TMDSIDDK_v2.0") accurately. So my question is to use PI controllers from the same library or use PI in DCL and call the transformation from IQmath Library?

    I much appreciate your support.

    Regards,

    Mohammad

  • Dear Mohammad,

    Glad it helped.

    1. The ".dclfuncs" section is defined in the assembly modules of DCL. In this case I used PID_C3 and Clamp_C2, both of which are inline C functions in DCLF32.h, so the dclfuncs section was never defined. All the code appears in one of the .text sections. The advantage of having DCL code in a separate named section is you can place it in a specific memory block in the linker command file, for example if your program is in flash and you want to have the controller in faster RAM memory, but in this case it's not necessary.

    2. Correct.

    3. Assuming the ADC is configured in 12-bit mode (as it is in this example) the result lies in the range 0 to 4095. The PID controller expects to see a normalized feedback (yk) in the range -1 to +1, so this line of code first offsets the ADC result to make it bi-polar, then scales it to the required range.

    4. I understand the confusion. ControlSUITE is no longer being updated - for some time, any new content has been going into C2000Ware and the relevant SDK (MCSDK for motor control).
    http://www.ti.com/tool/C2000WARE-MOTORCONTROL-SDK

    As of today, the MCSDK does not use the DCL controllers, though it may well do so in future. You can take your pick about which approach to follow but I think if it were me I would go with whatever is in MCSDK today. Feel free to open a new post if you have further questions on this topic.

    Regards,

    Richard