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 C200 motorware

Part Number: TMS320F28379D
Other Parts Discussed in Thread: MOTORWARE, DRV8305

Tool/software: Code Composer Studio

Hello everyone, I have a school project where i need to control the speed of a DC motor using a PID and PWM dutycycle. I need to read the speed of this motor using ADC module.


so i used a C2000 motorware example for PID, but unfortunately this example was for F28069M (I'm using F28379D). So i went to change the registers on it, but i have some questions about this example : 

1- why did they configure 2 GPIOs in this program as output, don't we have one output which is PWM output and one input which is ADC ? 

-----------------------------------------------------------------------------------
/* configure GPIO */
InitGpio(); // [F2806x_Gpio.c]
EALLOW;
GpioCtrlRegs.GPBMUX1.bit.GPIO34 = 0; // GPIO34 = I/O pin
GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1; // GPIO34 = output
GpioDataRegs.GPBSET.bit.GPIO34 = 1; // GPIO34 = 1
GpioCtrlRegs.GPBMUX1.bit.GPIO39 = 0; // GPIO39 = I/O pin
GpioCtrlRegs.GPBDIR.bit.GPIO39 = 1; // GPIO39 = output
GpioDataRegs.GPBCLEAR.bit.GPIO39 = 1; // GPIO39 = 0
EDIS;
-------------------------------------------------------------------------------------

2- same in ADC configuration there are using 2 SOC channels (SOC1 and SOC2) even like we just need one channel to read the feedback value. (and the same there used two ADCINT)

---------------------------------------------------------------------------------------------------------
AdcRegs.ADCSOC0CTL.bit.CHSEL = 0; // set SOC0 channel select to ADCINA0
AdcRegs.ADCSOC1CTL.bit.CHSEL = 8; // set SOC1 channel select to ADCINB0
-------------------------------------------------------------------------------------------------------------

3-  In pid parameters why do we need the external saturation variable lk ? 

hope someone can help understand this better.

  • here is the full program :

    /* Example_F28069_PID.c
     *
     * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
     * ALL RIGHTS RESERVED  
     *
    */
    
    // header files
    #include "F2806x_Device.h"
    #include "F2806x_Examples.h"
    #include "F2806x_GlobalPrototypes.h"
    #include "DCLF32.h"
    
    // function prototypes
    extern interrupt void control_Isr(void);
    
    // global  variables
    long IdleLoopCount = 0;
    long IsrCount = 0;
    float rk = 0.25f;
    float yk;
    float lk;
    float uk;
    DCL_PID pid1 = PID_DEFAULTS;
    float Duty;
    
    
    /* main */
    main()
    {
    	/* initialise system */
    	InitSysCtrl();							// [F2806x_SysCtrl.c]
    	DINT;									// disable interrupts
    	IER = 0x0000;
    	IFR = 0x0000;
    	InitPieCtrl();							// initialise PIE control registers [F2806x_PieCtrl.c]
    	InitPieVectTable();						// initialise PIE vector table [F2806x_PieVect.c]
    	EALLOW;
    	PieVectTable.ADCINT1 = &control_Isr;	// [F28069_PID_cisr.c]
    	EDIS;
    
    	/* configure ePWM1 */
    	EALLOW;
    	SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
    	EDIS;
    	InitEPwm();								// [F2806x_EPwm.c]
    	EPwm1Regs.TBCTL.bit.CTRMODE = 3;		// freeze TB counter
    	EPwm1Regs.TBCTL.bit.PRDLD = 1;  		// immediate load
    	EPwm1Regs.TBCTL.bit.PHSEN = 0;	   		// disable phase loading
    	EPwm1Regs.TBCTL.bit.SYNCOSEL = 3;		// disable SYNCOUT signal
    	EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0;		// TBCLK = SYSCLKOUT
    	EPwm1Regs.TBCTL.bit.CLKDIV = 0;			// clock divider = /1
    	EPwm1Regs.TBCTL.bit.FREE_SOFT = 2;		// free run on emulation suspend
    	EPwm1Regs.TBPRD = 0x2328;	          	// set period for ePWM1 (0x2328 = 10kHz)
    	EPwm1Regs.TBPHS.all = 0;			    // time-base Phase Register
    	EPwm1Regs.TBCTR = 0;					// time-base Counter Register
    	EPwm1Regs.ETSEL.bit.SOCAEN = 1;        	// enable SOC on A group
    	EPwm1Regs.ETSEL.bit.SOCASEL = 1;       	// select SOC from zero match
    	EPwm1Regs.ETPS.bit.SOCAPRD = 1;        	// generate pulse on 1st event
    	EPwm1Regs.CMPCTL.bit.SHDWAMODE = 0;		// enable shadow mode
    	EPwm1Regs.CMPCTL.bit.LOADAMODE = 2; 	// reload on CTR=zero
    	EPwm1Regs.CMPA.half.CMPA = 0x0080;	 	// set compare A value
    	EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;		// HIGH on CMPA up match
    	EPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR;	// LOW on zero match
    	EALLOW;
    	SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    	EDIS;
    
    	/* configure ADC */
    	InitAdc();								// [F2806x_Adc.c]
    	EALLOW;
    	AdcRegs.ADCCTL1.bit.INTPULSEPOS	= 0;	// early interrupt generation
    	AdcRegs.INTSEL1N2.bit.INT1E = 1;		// enabled ADCINT1
    	AdcRegs.INTSEL1N2.bit.INT1CONT = 0;		// disable ADCINT1 continuous mode
    	AdcRegs.INTSEL1N2.bit.INT1SEL = 1;		// setup EOC1 to trigger ADCINT1
    	AdcRegs.INTSEL1N2.bit.INT2E = 0;	    // enable ADCINT2
    	AdcRegs.INTSEL1N2.bit.INT2CONT = 0;	    // disable ADCINT1 continuous mode
    	AdcRegs.INTSEL1N2.bit.INT2SEL = 0;	    // setup EOC1 to trigger ADCINT2
    	AdcRegs.ADCSOC0CTL.bit.CHSEL = 0;		// set SOC0 channel select to ADCINA0
    	AdcRegs.ADCSOC1CTL.bit.CHSEL = 8;		// set SOC1 channel select to ADCINB0
    	AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5;		// set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    	AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 5;		// set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    	AdcRegs.ADCSOC0CTL.bit.ACQPS = 6;		// set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    	AdcRegs.ADCSOC1CTL.bit.ACQPS = 6;		// set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    	EDIS;
    
    	/* configure GPIO */
    	InitGpio();  							// [F2806x_Gpio.c]
    	EALLOW;
    	GpioCtrlRegs.GPBMUX1.bit.GPIO34 = 0;	// GPIO34 = I/O pin
    	GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1;		// GPIO34 = output
    	GpioDataRegs.GPBSET.bit.GPIO34 = 1;		// GPIO34 = 1
    	GpioCtrlRegs.GPBMUX1.bit.GPIO39 = 0;	// GPIO39 = I/O pin
    	GpioCtrlRegs.GPBDIR.bit.GPIO39 = 1;		// GPIO39 = output
    	GpioDataRegs.GPBCLEAR.bit.GPIO39 = 1;	// GPIO39 = 0
    	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 interrupts */
    	PieCtrlRegs.PIEIER1.bit.INTx1 = 1; 		// enable PIE INT 1.1 (ADCINT1) - [adcisr]
    	IER |= M_INT1;							// enable core interrupt 1 (ADC) - [control_isr]
    	SetDBGIER(0x0001);						// enable real-time debug interupts
    	EINT;          							// enable global interrupt mask
    
    	EALLOW;
    	EPwm1Regs.TBCTL.bit.CTRMODE = 0;		// PWM1 timer: count up and start
    	EDIS;
    
    	/* idle loop */
    	while(1)
    	{
    		IdleLoopCount++;					// increment loop counter
    		asm(" NOP");
    	} // while
    
    } // main
    
    
    /* control ISR: triggered by ADC EOC */
    interrupt void control_Isr(void)
    {
    	PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    	AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
    
    	// read ADC channel
    	yk = ((float) AdcResult.ADCRESULT0 - 2048.0f) / 2047.0f;
    	lk = (float) AdcResult.ADCRESULT1;
    
    	// external clamp for anti-windup reset
    	DCL_runClamp_C1(&lk, 1.0f, 0.0f);
    
    	// run PID controller
    	uk = DCL_runPID_C4(&pid1, rk, yk, lk);
    
    	// write u(k) to PWM
    	Duty = (uk / 2.0f + 0.5f) * (float) EPwm1Regs.TBPRD;
    	EPwm1Regs.CMPA.half.CMPA = (Uint16) Duty;
    
    	IsrCount++;
    }
    
    
    /* end of file */
    

  • The code you attached is one the examples from the Digital Control Library.

    1) The example source file is intended to illustrate running a PID_C4 controller on the F28069 LaunchPad board. The lines which configure GPIOs 34 and 39 are there simply to control the LEDs on the LaunchPad board, though the program does not make use of them. This should have been made clearer in the user's guide.

    You are correct that the configuration of the PWM output pin used in the ISR has not been done in the program. GPIO0 should have been configured since that is used as the control output. I will mark that for correction in the next revision.

    2) The program reads two ADC channels - one for the feedback (yk), the other for a saturation input (lk). "lk" is used to detect saturation outside the controller so that the integral path of the PID can be disabled to prevent windup.

    3) (see above) If this feature is not needed in your system you can simply not read ADCRESULT1, and call the PID controller with '1.0f' in place of "lk":
    uk = DCL_runPID_C4(&pid1, rk, yk, 1.0f);

    There is more information on this controller, and the use of lk on p.30 of the DCL User's Guide.

    I hope this helps.

    Regards,

    Richard
  • yeah thank you very much, you're a life saver.

    I modified the example program to another one for F28379D, and to configure the PWM as output I replaced the LED GPIO lines in the code with two fuctions :
    InitGpio();
    InitEPwm1Gpio();

    1-so I guess those functions configure my PWM as output on ePWM1A right ?

    2- and i don't know what the 1.0f mean (i know it's double float data type).
    if i want to give my Kp a value 120.08 how am i gonna convert to a double float value.

    here is my program modified :

    // header files
    #include "F28x_Project.h"
    #include "DCLF32.h"
    
    // function prototypes
    extern interrupt void control_Isr(void);
    
    // global  variables
    long IdleLoopCount = 0;
    long IsrCount = 0;
    float rk = 0.25f;
    float yk;
    float lk;
    float uk;
    DCL_PID pid1 = PID_DEFAULTS;
    float Duty;
    
    /* main */
    main()
    {
    	// Initialize System Control
    	InitSysCtrl();
    	EALLOW;
    	ClkCfgRegs.PERCLKDIVSEL.bit.EPWMCLKDIV = 1;
    	EDIS;
    
    	// Initialize GPIO
    	InitGpio(); 		// Configure default GPIO
    	InitEPwm1Gpio();	// Configure EPWM1 GPIO pins
    
        // Clear all interrupts and initialize PIE vector table
        DINT;
        InitPieCtrl();
        IER = 0x0000;
        IFR = 0x0000;
        InitPieVectTable();
    
        /* configure ePWM1 */
        EALLOW;
        CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0;
        EDIS;
        //InitEPwm();								// [F2806x_EPwm.c] ????
        EPwm1Regs.TBCTL.bit.CTRMODE = 3;		// freeze TB counter
        EPwm1Regs.TBCTL.bit.PRDLD = 1;  		// immediate load
        EPwm1Regs.TBCTL.bit.PHSEN = 0;	   		// disable phase loading
        EPwm1Regs.TBCTL.bit.SYNCOSEL = 3;		// disable SYNCOUT signal
        EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0;		// TBCLK = SYSCLKOUT
        EPwm1Regs.TBCTL.bit.CLKDIV = 0;			// clock divider = /1
        EPwm1Regs.TBCTL.bit.FREE_SOFT = 2;		// free run on emulation suspend
        EPwm1Regs.TBPRD = 0x2328;	          	// set period for ePWM1 (0x2328 = 10kHz)
        EPwm1Regs.TBPHS.all = 0;			    // time-base Phase Register
        EPwm1Regs.TBCTR = 0;					// time-base Counter Register
        EPwm1Regs.ETSEL.bit.SOCAEN = 1;        	// enable SOC on A group
        EPwm1Regs.ETSEL.bit.SOCASEL = 1;       	// select SOC from zero match
        EPwm1Regs.ETPS.bit.SOCAPRD = 1;        	// generate pulse on 1st event
    	EPwm1Regs.CMPCTL.bit.SHDWAMODE = 0;		// enable shadow mode
    	EPwm1Regs.CMPCTL.bit.LOADAMODE = 2; 	// reload on CTR=zero
    	EPwm1Regs.CMPA.bit.CMPA = 0x0080;	 	// set compare A value 128 ?
    	EPwm1Regs.AQCTLA.bit.CAU = 0x2;		// HIGH on CMPA up match
    	EPwm1Regs.AQCTLA.bit.ZRO = 0x1;	// LOW on zero match
    	EALLOW;
        CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
        EDIS;
    
    	/* configure ADC */
    	//InitAdc();								// [F2806x_Adc.c] ???
    	EALLOW;
    	AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 0;	// early interrupt generation
    	AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1;		// enabled ADCINT1 (ADCINTSEL1N2)
    	AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 0;	// disable ADCINT1 continuous mode
    	AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 1;	// setup EOC1 to trigger ADCINT1 (j'ai chang� la valeur de 1 � 01h)
    	AdcaRegs.ADCINTSEL1N2.bit.INT2E = 0;	    // enable ADCINT2 (you mean disable ?? not ??)
    	AdcaRegs.ADCINTSEL1N2.bit.INT2CONT = 0;	// disable ADCINT1 continuous mode ????
    	AdcaRegs.ADCINTSEL1N2.bit.INT2SEL = 0;	    // setup EOC1 to trigger ADCINT2 ????
    	AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0;		// set SOC0 channel select to ADCINA0 (j'ai chang� la valeur de 0 � 0h)
    	AdcaRegs.ADCSOC1CTL.bit.CHSEL = 8;		// set SOC1 channel select to ADCINB0 (j'ai chang� la valeur de 8 � 8h)
    	AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5;	// set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    											// (j'ai chang� la valeur de 5 � 05h)
    	AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 5;	// set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    											// (j'ai chang� la valeur de 5 � 05h)
    	AdcaRegs.ADCSOC0CTL.bit.ACQPS = 6;	// set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    	AdcaRegs.ADCSOC1CTL.bit.ACQPS = 6;	// set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    											// (j'ai chang� la valeur de 6 � 06h)
    	EDIS;
    
    	/* configure GPIO */
    	InitGpio();  							// [F2806x_Gpio.c]
        InitEPwm1Gpio();	// Configure EPWM1 GPIO pins
    	//EALLOW;
    	//GpioCtrlRegs.GPBMUX1.bit.GPIO0 = 0;	// GPIO34 = I/O pin
    	//GpioCtrlRegs.GPBDIR.bit.GPIO0 = 1;		// GPIO34 = output
    	//GpioDataRegs.GPBSET.bit.GPIO0 = 1;		// GPIO34 = 1
    	//GpioCtrlRegs.GPBMUX1.bit.GPIO1 = 0;	// GPIO39 = I/O pin
    	//GpioCtrlRegs.GPBDIR.bit.GPI1 = 1;		// GPIO39 = output
    	//GpioDataRegs.GPBCLEAR.bit.GPIO1 = 1;	// GPIO39 = 0
    	//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 interrupts */
    	PieCtrlRegs.PIEIER1.bit.INTx1 = 1; 		// enable PIE INT 1.1 (ADCINT1) - [adcisr]
    	IER |= M_INT1;							// enable core interrupt 1 (ADC) - [control_isr]
    	SetDBGIER(0x0001);						// enable real-time debug interupts
    	EINT;          							// enable global interrupt mask
    
    	EALLOW;
    	EPwm1Regs.TBCTL.bit.CTRMODE = 0;		// PWM1 timer: count up and start
    	EDIS;
    
    	/* idle loop */
    	while(1)
    	{
    		IdleLoopCount++;					// increment loop counter
    		asm(" NOP");
    	} // while
    } // main
    
    
    /* control ISR: triggered by ADC EOC */
    interrupt void control_Isr(void)
    {
    	PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    	AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
    
    	// read ADC channel
    	yk = ((float) AdcaResultRegs.ADCRESULT0 - 2048.0f) / 2047.0f;
    	//lk = (float) AdcaResultRegs.ADCRESULT1;
    	//AdcaResultRegs.ADCRESULT0
    
    	// external clamp for anti-windup reset
    	//DCL_runClamp_C1(&lk, 1.0f, 0.0f);
    
    	// run PID controller
    	uk = DCL_runPID_C4(&pid1, rk, yk, 1.0f);
    
    	// write u(k) to PWM
    	Duty = (uk / 2.0f + 0.5f) * (float) EPwm1Regs.TBPRD;
    	EPwm1Regs.CMPA.bit.CMPA = (Uint16) Duty;
    
    	IsrCount++;
    }
    
    
    /* end of file */
    
    
    
    

  • Yes, that should work.

    The function InitGpio() is in file "F2837xD_Gpio.c". It simply initializes all GPIO pins as inputs.

    The function InitEPwm1Gpio(); is in "F2837xD_EPwm.c" and configures just GPIO0 and GPIO1 pins as outputs from PWM module 1.

    The 'f' after the number tells the compiler to treat it as a single precision floating point, which is 32-bits on C28x. When you set lk as "1.0f" the compiler runs as is there is no extrenal saturation because lk is multiplied by the input to the integrator. It's like turning off the feature.

    To set Kp to this value you just need to modify line 100 in the file you attached to read:
    pid1.Kp = 120.08f;

    I hope this helps.

    Regards,

    Richard
  • A couple of corrections to my last post:

    "The 'f' after the number tells the compiler to treat it as a single precision floating point, which is 32-bits on C28x. When you set lk as "1.0f" the controller runs as is there is no external saturation because lk is multiplied by the input to the integrator. It's like turning off the feature."

    The PID_C4 controller you are using is single precision floating-point, so you don't need to perform any single to double conversion.

    Regards,

    Richard

  • soryy I didn't get it, does that mean I can remove the 'f' from the numbers ?
  • You'll need to keep the 'f' in all the numbers. It tells to compiler to use single precision floating point and that's how the C4 controller is written. Nothing in the program uses double precision.

    Regards,

    Richard
  • Hello again,

    1- In the line where we convert the PID output to a duty cycle, why the did they divide uk per (2.0f + 0.5f) ?
    to what value correspond (2.0f+0.5f) ?
    -------------------------------------------------------------------------
    Duty = (uk / 2.0f + 0.5f) * (float) EPwm1Regs.TBPRD;
    ----------------------------------------------------------------------------
    2- I want to contol the speed of a 220V DC motor with adjusting the PWM dutycyle, and I have the BOOSTXL-DRV8305-EVM .
    All the examples that i saw they were using 3 phase motors with DRV8305 and none for 2 phase motor.

    my question is : can I use the DRV8305 with my 2 phase motor ?
  • In response to the first question, the assumption in the example was that the controller output was normalised to +/-1.0f. The code line scales and then offsets the controller output to bring it in the 0 - 1.0f range, which is multiplied by the PWM period to get the duty cycle. It's just a code example.

    I need to bring in someone else to respond to your second question.

    Regards,

    Richard
  • For Question 2, this depends on what control techniques you will implement on the 2-phase motor, we didn't have a reference design for such a 2-phase motor.
    Btw, the DRV8305 is low voltage gate driver, its maximum operating voltage is 45V, so it's not a good choice for your motor.