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: DCL PID UPDATE PARAMETERS

Part Number: TMS320F28379D

Tool/software: Code Composer Studio

Good day all,

I have some question about the DCL UPDATE PID PARAMETERS. 

According to DCL user guide, I have::

1. first to declare the following variables: 

DCL_PID pid1 = PID_DEFAULTS;
DCL_PID_SPS spid = PID_SPS_DEFAULTS;
DCL_CSS cpid = DCL_CSS_DEFAULTS;

2. second in void main(void) , write:

pid1.sps = &spid;
pid1.css = &cpid;
pid1.sps->Kp = 0.5f;//0.5f;
pid1.sps->Ki = 0.1f;//0.1f;
pid1.sps->Kd = 0.02f; //0.02f;
pid1.sps->Kr = 1.0f;
pid1.sps->c1 = 150.0f; //periodo de amostragem T = 82us e constante de filtro tau = 2,64 us
pid1.sps->c2 = 0.879f;
pid1.d2 = 0.0f;
pid1.d3 = 0.0f;
pid1.i10 = 0.0f;
pid1.i14 = 0.0f;
pid1.sps->Umax = 1.0f;
pid1.sps->Umin = -1.0f;

DCL_REQUEST_UPDATE(&pid1);
DCL_fupdatePID(&pid1);

My question about the last two line above. Am I right in writing them like just that or do I need to declare more functions ? Because in the watch window,  the PID parameters do not udpate.

BR

  • Christian,

    As far as I can see you are doing everything correctly.  You will need to have the source file "DCL_futils.asm" in your project so the compiler can find the call in the last line.  That should copy over the parameters from the SPS sub-structure 'spid' into the main controller structure 'pid1'.  Are you saying the copy doesn't take place?

    If not, can you try calling "DCL_updatePID()" (i.e. without the 'f') to see if it makes a difference?

    Regards,

    Richard

  • Christian,

    Can you let us know if you are still in difficulty with this please?  The parameter update function seems to be working on every platform I've tried so far.  Thanks.

    Regards,

    Richard

  • Richard, 

    Good day, 

    I still have difficult. The parameters that stabilize my system are 

    kp = 0.5

    ki = 0.1

    kd = 0.02

    However, I changed their values as below in the code, in order to test the DCI_UPDATE, but the parameters do not update in the watch window. Please find below my code: 

    //
    #include "F28x_Project.h"
    #include "F2837xD_GlobalPrototypes.h"
    #include "F2837xD_Device.h"
    #include "F2837xD_Examples.h"
    #include "DCLF32.h"
    #include "DCL.h"
    #include "DCLCLA.h"

    // Defines
    //
    #define RESULTS_BUFFER_SIZE 256

    #define REFERENCE_VDAC 0
    #define REFERENCE_VREF 1
    #define DACA 1
    #define DACB 2
    #define DACC 3
    #define REFERENCE REFERENCE_VREF
    #define DAC_NUM DACA
    #define BLINKY_LED_GPIO1 18
    #define PID_SPS_DEFAULTS { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f }

    // Globals
    volatile struct DAC_REGS* DAC_PTR[4] = {0x0,&DacaRegs,&DacbRegs,&DaccRegs};
    Uint16 AdcaResults[RESULTS_BUFFER_SIZE];
    Uint16 resultsIndex;
    volatile Uint16 bufferFull;
    Uint16 AdcaResult0;
    Uint16 dacval = 2048;

    //Parâmetros interno do PID
    long IdleLoopCount = 0;
    long IsrCount = 0;
    float rk = 0.4f; //0.25f;
    float yk;
    float lk;
    float uk;
    DCL_PID pid1 = PID_DEFAULTS;
    DCL_PID_SPS spid = PID_SPS_DEFAULTS;
    DCL_CSS cpid = DCL_CSS_DEFAULTS;

    float Duty;
    float xk;
    Uint16 tk;
    Uint16 ok;
    //
    // Function Prototypes
    //
    void ConfigureADC(void);
    void ConfigureEPWM(void);
    void SetupADCEpwm(Uint16 channel);
    interrupt void adca1_isr(void);
    void configureDAC(Uint16 dac_num);

    //

    //

    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();

    EALLOW;
    InputXbarRegs.INPUT5SELECT = 1;
    EDIS;


    // 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

    GPIO_SetupPinMux(BLINKY_LED_GPIO1, 4, 0); // Tempo de interrupcao
    GPIO_SetupPinOptions(BLINKY_LED_GPIO1, GPIO_OUTPUT, GPIO_PUSHPULL);
    /////////OUTPUT X-BAR TEST ///////
    EALLOW;
    OutputXbarRegs.OUTPUT1MUX0TO15CFG.bit.MUX1 = 1;
    OutputXbarRegs.OUTPUT1MUXENABLE.bit.MUX1 = 1;
    OutputXbarRegs.OUTPUTLATCHENABLE.bit.OUTPUT1 = 0;
    OutputXbarRegs.OUTPUTINV.bit.OUTPUT1 = 0;
    EDIS;
    ////////OUTPUT X-BAR FIM //////

    //
    // 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();

    // Configure DAC
    //
    configureDAC(DAC_NUM);

    EINT; // Enable Global interrupt INTM
    ERTM; // Enable Global realtime interrupt DBGM
    //
    // 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);

    //
    // 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

    //Updating PID parameters
    pid1.sps = &spid;
    pid1.css = &cpid;
    pid1.sps->Kp = 0.4f;//0.5f;
    pid1.sps->Ki = 0.08f;//0.1f;
    pid1.sps->Kd = 0.004f; //0.02f;
    pid1.sps->Kr = 1.0f;
    pid1.sps->c1 = 150.0f; //periodo de amostragem T = 82us e constante de filtro tau = 2,64 us
    pid1.sps->c2 = 0.879f;
    pid1.d2 = 0.0f;
    pid1.d3 = 0.0f;
    pid1.i10 = 0.0f;
    pid1.i14 = 0.0f;
    pid1.sps->Umax = 1.0f;
    pid1.sps->Umin = -1.0f;

    DCL_REQUEST_UPDATE(&pid1);
    DCL_updatePID(&pid1);


    //
    // Initialize results buffer
    //
    for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++)
    {
    AdcaResults[resultsIndex] = 0;
    }
    resultsIndex = 0;
    bufferFull = 0;

    //
    // enable PIE interrupt
    //
    PieCtrlRegs.PIEIER1.bit.INTx1 = 1;

    //
    // sync ePWM
    //
    EALLOW;
    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;

    //
    //take conversions indefinitely in loop
    //
    do
    {
    //
    //start ePWM
    //
    EPwm1Regs.ETSEL.bit.SOCAEN = 1; //enable SOCA
    EPwm1Regs.TBCTL.bit.CTRMODE = 0; //unfreeze, and enter up count mode

    //
    //wait while ePWM causes ADC conversions, which then cause interrupts,
    //which fill the results buffer, eventually setting the bufferFull
    //flag
    //
    while(!bufferFull); // *****PODE OU NÃO SER ADICIONADO
    bufferFull = 0; //clear the buffer full flag // ******PODE OU NÃO SER ADICIONADO

    //
    //stop ePWM
    //
    EPwm1Regs.ETSEL.bit.SOCAEN = 0; //disable SOCA
    EPwm1Regs.TBCTL.bit.CTRMODE = 3; //freeze counter

    //
    //at this point, AdcaResults[] contains a sequence of conversions
    //from the selected channel
    //

    //
    //software breakpoint, hit run again to get updated conversions
    //
    // asm(" ESTOP0");
    }


    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
    EPwm1Regs.TBCTL.bit.CTRMODE = 3; // freeze counter
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT
    EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    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 = 2; //SOC0 will convert pin A2
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = acqps; //sample window is 100 SYSCLK cycles
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; //trigger on ePWM1 SOCA/C
    AdcaRegs.ADCSOC1CTL.bit.CHSEL = 3; //SOC0 will convert pin A2
    AdcaRegs.ADCSOC1CTL.bit.ACQPS = acqps; //sample window is 100 SYSCLK cycles
    AdcaRegs.ADCSOC1CTL.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)
    {


    GPIO_WritePin(BLINKY_LED_GPIO1, 1);
    tk = AdcaResultRegs.ADCRESULT0;
    yk = ((float) AdcaResultRegs.ADCRESULT0 - 2048.0f) * 0.00048852f;
    xk = (float) AdcaResultRegs.ADCRESULT1;
    // external clamp for anti-windup reset
    lk = DCL_runClamp_C1(&xk, 1.0f, 0.0f);

    uk = DCL_runPID_C1(&pid1, rk, yk, lk);
    ok = 2340 *(uk + 0.75);
    DAC_PTR[DAC_NUM]->DACVALS.all = ok;


    // AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT0;
    // if(RESULTS_BUFFER_SIZE <= resultsIndex)
    // {
    // resultsIndex = 0;
    // bufferFull = 1;
    // }
    //
    GPIO_WritePin(BLINKY_LED_GPIO1, 0);
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear INT1 flag
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    }

    void configureDAC(Uint16 dac_num)
    {
    EALLOW;
    DAC_PTR[dac_num]->DACCTL.bit.DACREFSEL = REFERENCE;
    DAC_PTR[dac_num]->DACOUTEN.bit.DACOUTEN = 1;
    DAC_PTR[dac_num]->DACCTL.bit.SYNCSEL = 1;
    DAC_PTR[dac_num]->DACCTL.bit.LOADMODE = 0;
    DAC_PTR[dac_num]->DACVALS.all = 0;
    DELAY_US(10); // Delay for buffered DAC to power up
    EDIS;
    }
    //
    // End of file
    //

  • I can only say I see the values being copied over cleanly.  I copied your code verbatim into an empty project.  I place a break-point on this line:

    DCL_REQUEST_UPDATE(&pid1);

    ...then single step to observe the sts bit in the CSS structure change to 1, then single step once more and see the new parameters copy across from the SPS to the main structure (see image below).

    I'm not sure what could be going wrong.  Can you send me a screen shot of your watch window under these conditions please?

    Regards,

    Richard

      

  • Richard, 

    I had a breakpoint on default_pid., but the sts bit in css structure remains 0. How can I single step to observe sts ? Second question, while sts changes, kp, ki and kd should not be changing to new values ??

  • Sorry, when you say "I had a breakpoint on default_pid", which line is that?  I don't see it in the code.

    From your screen capture I can see that c1, c2, Umax, and Umin have copied over correctly.  I cannot see the other values (Kp, Ki, Kd, Kr) - you'd need to scroll up in the watch window.

    Regards,

    Richard

  • Hi Richard, 

    Please follow below

  • Hi Christian,

    Thank you for the extra screen-shots.  I see you have a break-point set on the update function and have run from there.  I can see the controller parameters in the  SPS and main PID structure are the same, the sts flag is zero so the copy has taken place, and I see d2 and d3 have changed so the controller has run at least once.

    Can you elaborate a little on what the problem is please?  Everything looks OK here, unless I've missed something.  Thanks.

    Regards,

    Richard

  • Richard, 

    In my understanding, the DCL_update shall update the PID parameters continuously till stabilizing the system. For instance, in my example, the parameters that stabilize the system are kp = 0,5; ki = 0,1 e kd = 0,04.

    So I was thinking that if I choose random parameters like kp = 0,1; ki = 3,5 e kd = 0,04 (these parameters don't control the system), the DCL_UPDATE function will keep finding new values as long as the system is running. 

    However, I think that's not the case, right ?

  • Hi Christian,

    Understand, thanks. 

    No, the controller update function doesn't work that way.  It really just updates the main controller structure with whichever parameters are loaded into the STS.  It's left to the user to find suitable coefficients and load them into the SPS, then request the update and call the update function, as you've done in the code:

    DCL_REQUEST_UPDATE(&pid1);
    DCL_updatePID(&pid1);

    The reason for updating in this way is to ensure the copy takes place when interrupts are disabled, so the controller never runs with a partially updated parameter set.  The DCL doesn't currently have and self-tuning capability. 

    Hopefully this clarifies. Let me know if you need anything further.

    Regards,

    Richard

  • Hi Richard, 

    Thank you very much.

    BR