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.

Controlling PWM with ADC

Other Parts Discussed in Thread: TMS320F28027F

Hi Guys!

I am working with a TMS320F28027F C2000 Launchpad XL

I am trying to set the duty ratio of the F28027 Launchpad's PWM via a Slide Pot. My end goal here is to vary two PWM signals from Gpio6 and 7 using the slide pot. Luckily I was able to accomplish this using the code below for GPIO 0 however now that I am trying to change the PWM from GPIO0 to GPIO6 and 7 I am unable to get a pwm output. It seems as if the PWM is  not even getting set. I have looked at the sample code in Control suite (Example_2802xEPwmUpAQ.c) however I still haven't been able to figure out why it is behaving as expected with GPIO0 but not GPIO6 and 7. Thank you in advance guys. 


#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
#include "f2802x_common/include/adc.h"
#include "f2802x_common/include/clk.h"
#include "f2802x_common/include/flash.h"
#include "f2802x_common/include/gpio.h"
#include "f2802x_common/include/pie.h"
#include "f2802x_common/include/pll.h"
#include "f2802x_common/include/timer.h"
#include "f2802x_common/include/wdog.h"
#include "f2802x_common/include/pwr.h"
#include "f2802x_common/include/pwm.h"


void pwm_Init_();

unsigned int TBPRD = 4096;
unsigned int CMPA=0; //32500;

ADC_Handle   myAdc;
CLK_Handle   myClk;
FLASH_Handle myFlash;
GPIO_Handle  myGpio;
PIE_Handle   myPie;
TIMER_Handle myTimer;
CPU_Handle   myCpu;
PLL_Handle   myPll;
WDOG_Handle  myWDog;
PWM_Handle 	 myPwm4;
PWR_Handle   myPwr;

uint16_t Digital_Result =0;

void disable();
void enable();
void ADC_INIT_Fn();
void ADC_SETUP_Fn();
void set_duty(int a);

int adcresult=2048;

interrupt void adc_isr(void)
{
    //discard ADCRESULT0 as part of the workaround to the 1st sample errata for rev0
    Digital_Result = ADC_readResult(myAdc, ADC_ResultNumber_0);

    adcresult =Digital_Result;

     set_duty(adcresult);

    ADC_clearIntFlag(myAdc, ADC_IntNumber_1);   // Clear ADCINT1 flag reinitialize for next SOC
    PIE_clearInt(myPie, PIE_GroupNumber_10);// Acknowledge interrupt to PIE
    return;
}




void main(void)
{
   myAdc = ADC_init((void *)ADC_BASE_ADDR, sizeof(ADC_Obj));
   myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
   myCpu = CPU_init((void *)NULL, sizeof(CPU_Obj));
   myFlash = FLASH_init((void *)FLASH_BASE_ADDR, sizeof(FLASH_Obj));
   myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));
   myPie = PIE_init((void *)PIE_BASE_ADDR, sizeof(PIE_Obj));
   myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));
   myTimer = TIMER_init((void *)TIMER0_BASE_ADDR, sizeof(TIMER_Obj));
   myWDog = WDOG_init((void *)WDOG_BASE_ADDR, sizeof(WDOG_Obj));
   myPwm4 = PWM_init((void *)PWM_ePWM4_BASE_ADDR, sizeof(PWM_Obj));
   myPwr = PWR_init((void *)PWR_BASE_ADDR, sizeof(PWR_Obj));

   disable();
    // Perform basic system initialization
    WDOG_disable(myWDog);
    CLK_enableAdcClock(myClk);
    CLK_setOscSrc(myClk, CLK_OscSrc_Internal);  //Select the internal oscillator 1 as the clock source
    PLL_setup(myPll, PLL_Multiplier_10, PLL_DivideSelect_ClkIn_by_2);  // Setup the PLL for x10 /2 which will yield 50Mhz = 10Mhz * 10 / 2


    enable();
    ADC_INIT_Fn();
    ADC_SETUP_Fn();

    //Want to make it work with 6 & 7
    GPIO_setMode(myGpio, GPIO_Number_6, GPIO_6_Mode_EPWM4A);
    GPIO_setMode(myGpio, GPIO_Number_7, GPIO_7_Mode_EPWM4B);


      CLK_disableTbClockSync(myClk);
      pwm_Init_();


      CLK_enableTbClockSync(myClk);
    while(1)
    {
     ADC_forceConversion(myAdc, ADC_SocNumber_0);// Wait for ADC interrupt
    }

}
void disable()
{
  // Disable the PIE and all interrupts
  PIE_disable(myPie);
  PIE_disableAllInts(myPie);
  CPU_disableGlobalInts(myCpu);
  CPU_clearIntFlags(myCpu);
}

void enable()
{
  PIE_enable(myPie);
  // Register interrupt handlers in the PIE vector table
  CPU_enableInt(myCpu, CPU_IntNumber_10);  // Enable CPU Interrupt 1
  CPU_enableGlobalInts(myCpu);        // Enable Global interrupt INTM
  CPU_enableDebugInt(myCpu);     // Enable Global realtime interrupt DBGM


      // Enable XINT1 in the PIE: Group 1 interrupt 4 & 5
      // Enable INT1 which is connected to WAKEINT
      PIE_enableInt(myPie, PIE_GroupNumber_3, PIE_InterruptSource_XINT_1);
  CPU_enableInt(myCpu, CPU_IntNumber_1);

     // GPIO0 is XINT1, GPIO1 is XINT2
     GPIO_setExtInt(myGpio, GPIO_Number_12, CPU_ExtIntNumber_1);

     // Configure XINT1
     PIE_setExtIntPolarity(myPie, CPU_ExtIntNumber_1, PIE_ExtIntPolarity_RisingEdge);

     // Enable XINT1 and XINT2
     PIE_enableExtInt(myPie, CPU_ExtIntNumber_1);
}

void ADC_INIT_Fn()
{
  ADC_enableBandGap(myAdc);
  ADC_enableRefBuffers(myAdc);
  ADC_powerUp(myAdc);
  ADC_enable(myAdc);
  ADC_setVoltRefSrc(myAdc, ADC_VoltageRefSrc_Int);
}

void ADC_SETUP_Fn()
{
 PIE_registerPieIntHandler(myPie, PIE_GroupNumber_10, PIE_SubGroupNumber_1, (intVec_t)&adc_isr);
  PIE_enableAdcInt(myPie, ADC_IntNumber_1);  // Enable ADCINT1 in PIE
  //Note: Channel ADCINA1  will be double sampled to workaround the ADC 1st sample issue for rev0 silicon errata
  ADC_setIntPulseGenMode(myAdc, ADC_IntPulseGenMode_Prior);               //ADCINT1 trips after AdcResults latch
  ADC_enableInt(myAdc, ADC_IntNumber_1);                                  //Enabled ADCINT1
  ADC_setIntMode(myAdc, ADC_IntNumber_1, ADC_IntMode_ClearFlag);          //Disable ADCINT1 Continuous mode
  ADC_setIntSrc(myAdc, ADC_IntNumber_1, ADC_IntSrc_EOC0);                 //setup EOC0 to trigger ADCINT1 to fire
  ADC_setSocChanNumber (myAdc, ADC_SocNumber_0, ADC_SocChanNumber_A4);    //set SOC0 channel select to ADCINA4
  ADC_setSocTrigSrc(myAdc, ADC_SocNumber_0, ADC_SocTrigSrc_Sw);      //set SOC0 start trigger on EPWM4A, due to round-robin SOC0 converts first then SOC1
  ADC_setSocSampleWindow(myAdc, ADC_SocNumber_0, ADC_SocSampleWindow_7_cycles);   //set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
}

void pwm_Init_()
{
    CLK_enablePwmClock(myClk, PWM_Number_1);
    // Setup TBCLK
    PWM_setPeriod(myPwm4, TBPRD);   // Set timer period 801 TBCLKs
    PWM_setPhase(myPwm4, 0x0000);   // Phase is 0
    PWM_setCount(myPwm4, 0x0000);   // Clear counter

    // Setup counter mode
    PWM_setCounterMode(myPwm4, PWM_CounterMode_UpDown); // Count up and down
    PWM_disableCounterLoad(myPwm4);                     // Disable phase loading
    PWM_setHighSpeedClkDiv(myPwm4, PWM_HspClkDiv_by_10); // Clock ratio to SYSCLKOUT
    PWM_setClkDiv(myPwm4, PWM_ClkDiv_by_1);

    ///setup for GPIO6 PWM
    // Setup shadowing
    PWM_setShadowMode_CmpA(myPwm4, PWM_ShadowMode_Shadow);
    PWM_setLoadMode_CmpA(myPwm4, PWM_LoadMode_Zero);
    // Set actions
    PWM_setActionQual_CntUp_CmpA_PwmA(myPwm4, PWM_ActionQual_Clear);      // Set PWM1A on event A, up count
    PWM_setActionQual_CntDown_CmpA_PwmA(myPwm4, PWM_ActionQual_Set);  // Clear PWM1A on event A, down count

    //SETUP for GPIO 7 PWM
    // Setup shadowing
    PWM_setShadowMode_CmpB(myPwm4, PWM_ShadowMode_Shadow);
    PWM_setLoadMode_CmpB(myPwm4, PWM_LoadMode_Zero);
    // Set actions
    PWM_setActionQual_CntUp_CmpB_PwmB(myPwm4, PWM_ActionQual_Clear);      // Set PWM1A on event A, up count
    PWM_setActionQual_CntDown_CmpB_PwmB(myPwm4, PWM_ActionQual_Set);  // Clear PWM1A on event A, down count
}
void set_duty( int a)
{
 CMPA = a;
 PWM_setCmpA(myPwm4, CMPA);
 PWM_setCmpB(myPwm4, CMPA);// Set compare A value
}

//===========================================================================
// No more.



  • Carlo,

    On F28027, GPIO1 is for PWM1B.  In your code:

    GPIO_setMode(myGpio, GPIO_Number_1, GPIO_1_Mode_EPWM1B);

    However when you initialize the PWM module, your comments imply you are configuring PWM1A:

    PWM_setActionQual_CntUp_CmpA_PwmA(myPwm1, PWM_ActionQual_Clear);      // Set PWM1A on event A, up count
    PWM_setActionQual_CntDown_CmpA_PwmA(myPwm1, PWM_ActionQual_Set);  // Clear PWM1A on event A, down count

    Possibly you are initializing the wrong GPIO pin.  Could you check again which output you are configuring for PWM - 1A or 1B?

    Regards,

    Richard

  • Richard,
    Thank you for your response I have updated the question above to reflect the actual code the errors should have not been included in the original text .
    I hope this will now convey what I trying to accomplish better than before.

    Thank you in advance,
    Carlo
  • Hi Carlo

    As Richard said: You are working with PWM1 with your code. If you want to output a PWM on GPIO6 you will need you work with PWM4. So the line:

    myPwm1 = PWM_init((void *)PWM_ePWM1_BASE_ADDR, sizeof(PWM_Obj));

    must be corrected to

    myPwm1 = PWM_init((void *)PWM_ePWM4_BASE_ADDR, sizeof(PWM_Obj));

    Or did you modify this already

    Roger

  • Hi Roger ,
    Thank you for the reply! I went ahead and made the change that you recommend , that definitely would have come to bite me later! I went ahead and tried running my code after making this change. (I went ahead and edited the original post to reflect my updated code) I updated the rest of the code based on the change, however I'm still reading nothing on both Gpio 6 (J2_#8) and Gpio 7 (J2_#9).
    I am using a TMS320F28027F C2000 Launchpad XL I made even triple checked the schematic to ensure I was using the right pins!

    -Carlo
  • Hi Carlo

    Note that I do not know the xF target you have, but I think it must be close to 28027...

    ok, for a PWM (or other peripheral) pin to get to work you must:

    • define gpio mux (if any)
    • enable the peripheral modules clock (in this case PWM4)
    • initialize the peripheral module (some have additional enable bits to be set)
    • use the peripheral

    I think you have done all of this, except point 2: enable the modules clock.

    In your pwm_init function you do enable the PWM1 clock, not PWM4, so modify it to:

        CLK_enablePwmClock(myClk, PWM_Number_4);
    Regards,
    Roger

  • THAT WAS IT!!!!

    THANK you so much Roger I appreciate your help! I also appreciate you breaking that down for me EXTREMELY helpful. MY WORKING CODE  may be found below.

    Thank you to those of you that helped me with this issue!

    Description : This code drives GPIO6 and Gpio 7 which are set to EPWM_4A/4B  respectively from high to low using an adc input currently a slide Pot is used to control the adc value and thus the duty cycle of both PWMs

    -Carlo

    CODE:

    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    #include "f2802x_common/include/adc.h"
    #include "f2802x_common/include/clk.h"
    #include "f2802x_common/include/flash.h"
    #include "f2802x_common/include/gpio.h"
    #include "f2802x_common/include/pie.h"
    #include "f2802x_common/include/pll.h"
    #include "f2802x_common/include/timer.h"
    #include "f2802x_common/include/wdog.h"
    #include "f2802x_common/include/pwr.h"
    #include "f2802x_common/include/pwm.h"
    
    
    void pwm_Init_();
    
    unsigned int TBPRD = 4096;
    unsigned int CMPA=0; //32500;
    
    ADC_Handle   myAdc;
    CLK_Handle   myClk;
    FLASH_Handle myFlash;
    GPIO_Handle  myGpio;
    PIE_Handle   myPie;
    TIMER_Handle myTimer;
    CPU_Handle   myCpu;
    PLL_Handle   myPll;
    WDOG_Handle  myWDog;
    PWM_Handle 	 myPwm4;
    PWR_Handle   myPwr;
    
    uint16_t Digital_Result =0;
    
    void disable();
    void enable();
    void ADC_INIT_Fn();
    void ADC_SETUP_Fn();
    void set_duty(int a);
    
    int adcresult=2048;
    
    interrupt void adc_isr(void)
    {
        //discard ADCRESULT0 as part of the workaround to the 1st sample errata for rev0
        Digital_Result = ADC_readResult(myAdc, ADC_ResultNumber_0);
    
        adcresult =Digital_Result;
    
         set_duty(adcresult);
    
        ADC_clearIntFlag(myAdc, ADC_IntNumber_1);   // Clear ADCINT1 flag reinitialize for next SOC
        PIE_clearInt(myPie, PIE_GroupNumber_10);// Acknowledge interrupt to PIE
        return;
    }
    
    
    
    
    void main(void)
    {
       myAdc = ADC_init((void *)ADC_BASE_ADDR, sizeof(ADC_Obj));
       myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
       myCpu = CPU_init((void *)NULL, sizeof(CPU_Obj));
       myFlash = FLASH_init((void *)FLASH_BASE_ADDR, sizeof(FLASH_Obj));
       myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));
       myPie = PIE_init((void *)PIE_BASE_ADDR, sizeof(PIE_Obj));
       myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));
       myTimer = TIMER_init((void *)TIMER0_BASE_ADDR, sizeof(TIMER_Obj));
       myWDog = WDOG_init((void *)WDOG_BASE_ADDR, sizeof(WDOG_Obj));
       myPwm4 = PWM_init((void *)PWM_ePWM4_BASE_ADDR, sizeof(PWM_Obj));
       myPwr = PWR_init((void *)PWR_BASE_ADDR, sizeof(PWR_Obj));
    
       disable();
        // Perform basic system initialization
        WDOG_disable(myWDog);
        CLK_enableAdcClock(myClk);
        CLK_setOscSrc(myClk, CLK_OscSrc_Internal);  //Select the internal oscillator 1 as the clock source
        PLL_setup(myPll, PLL_Multiplier_10, PLL_DivideSelect_ClkIn_by_2);  // Setup the PLL for x10 /2 which will yield 50Mhz = 10Mhz * 10 / 2
    
    
        enable();
        ADC_INIT_Fn();
        ADC_SETUP_Fn();
    
        //Want to make it work with 6 & 7
        GPIO_setMode(myGpio, GPIO_Number_6, GPIO_6_Mode_EPWM4A);
        GPIO_setMode(myGpio, GPIO_Number_7, GPIO_7_Mode_EPWM4B);
    
    
          CLK_disableTbClockSync(myClk);
          pwm_Init_();
    
    
          CLK_enableTbClockSync(myClk);
        while(1)
        {
         ADC_forceConversion(myAdc, ADC_SocNumber_0);// Wait for ADC interrupt
        }
    
    }
    void disable()
    {
      // Disable the PIE and all interrupts
      PIE_disable(myPie);
      PIE_disableAllInts(myPie);
      CPU_disableGlobalInts(myCpu);
      CPU_clearIntFlags(myCpu);
    }
    
    void enable()
    {
      PIE_enable(myPie);
      // Register interrupt handlers in the PIE vector table
      CPU_enableInt(myCpu, CPU_IntNumber_10);  // Enable CPU Interrupt 1
      CPU_enableGlobalInts(myCpu);        // Enable Global interrupt INTM
      CPU_enableDebugInt(myCpu);     // Enable Global realtime interrupt DBGM
    
    
          // Enable XINT1 in the PIE: Group 1 interrupt 4 & 5
          // Enable INT1 which is connected to WAKEINT
          PIE_enableInt(myPie, PIE_GroupNumber_3, PIE_InterruptSource_XINT_1);
      CPU_enableInt(myCpu, CPU_IntNumber_1);
    
         // GPIO0 is XINT1, GPIO1 is XINT2
         GPIO_setExtInt(myGpio, GPIO_Number_12, CPU_ExtIntNumber_1);
    
         // Configure XINT1
         PIE_setExtIntPolarity(myPie, CPU_ExtIntNumber_1, PIE_ExtIntPolarity_RisingEdge);
    
         // Enable XINT1 and XINT2
         PIE_enableExtInt(myPie, CPU_ExtIntNumber_1);
    }
    
    void ADC_INIT_Fn()
    {
      ADC_enableBandGap(myAdc);
      ADC_enableRefBuffers(myAdc);
      ADC_powerUp(myAdc);
      ADC_enable(myAdc);
      ADC_setVoltRefSrc(myAdc, ADC_VoltageRefSrc_Int);
    }
    
    void ADC_SETUP_Fn()
    {
     PIE_registerPieIntHandler(myPie, PIE_GroupNumber_10, PIE_SubGroupNumber_1, (intVec_t)&adc_isr);
      PIE_enableAdcInt(myPie, ADC_IntNumber_1);  // Enable ADCINT1 in PIE
      //Note: Channel ADCINA1  will be double sampled to workaround the ADC 1st sample issue for rev0 silicon errata
      ADC_setIntPulseGenMode(myAdc, ADC_IntPulseGenMode_Prior);               //ADCINT1 trips after AdcResults latch
      ADC_enableInt(myAdc, ADC_IntNumber_1);                                  //Enabled ADCINT1
      ADC_setIntMode(myAdc, ADC_IntNumber_1, ADC_IntMode_ClearFlag);          //Disable ADCINT1 Continuous mode
      ADC_setIntSrc(myAdc, ADC_IntNumber_1, ADC_IntSrc_EOC0);                 //setup EOC0 to trigger ADCINT1 to fire
      ADC_setSocChanNumber (myAdc, ADC_SocNumber_0, ADC_SocChanNumber_A4);    //set SOC0 channel select to ADCINA4
      ADC_setSocTrigSrc(myAdc, ADC_SocNumber_0, ADC_SocTrigSrc_Sw);      //set SOC0 start trigger on EPWM4A, due to round-robin SOC0 converts first then SOC1
      ADC_setSocSampleWindow(myAdc, ADC_SocNumber_0, ADC_SocSampleWindow_7_cycles);   //set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    }
    
    void pwm_Init_()
    {
        CLK_enablePwmClock(myClk, PWM_Number_4);
        // Setup TBCLK
        PWM_setPeriod(myPwm4, TBPRD);   // Set timer period 801 TBCLKs
        PWM_setPhase(myPwm4, 0x0000);   // Phase is 0
        PWM_setCount(myPwm4, 0x0000);   // Clear counter
    
        // Setup counter mode
        PWM_setCounterMode(myPwm4, PWM_CounterMode_UpDown); // Count up and down
        PWM_disableCounterLoad(myPwm4);                     // Disable phase loading
        PWM_setHighSpeedClkDiv(myPwm4, PWM_HspClkDiv_by_10); // Clock ratio to SYSCLKOUT
        PWM_setClkDiv(myPwm4, PWM_ClkDiv_by_1);
    
        ///setup for GPIO6 PWM
        // Setup shadowing
        PWM_setShadowMode_CmpA(myPwm4, PWM_ShadowMode_Shadow);
        PWM_setLoadMode_CmpA(myPwm4, PWM_LoadMode_Zero);
        // Set actions
        PWM_setActionQual_CntUp_CmpA_PwmA(myPwm4, PWM_ActionQual_Clear);      // Set PWM1A on event A, up count
        PWM_setActionQual_CntDown_CmpA_PwmA(myPwm4, PWM_ActionQual_Set);  // Clear PWM1A on event A, down count
    
        //SETUP for GPIO 7 PWM
        // Setup shadowing
        PWM_setShadowMode_CmpB(myPwm4, PWM_ShadowMode_Shadow);
        PWM_setLoadMode_CmpB(myPwm4, PWM_LoadMode_Zero);
        // Set actions
        PWM_setActionQual_CntUp_CmpB_PwmB(myPwm4, PWM_ActionQual_Clear);      // Set PWM1A on event A, up count
        PWM_setActionQual_CntDown_CmpB_PwmB(myPwm4, PWM_ActionQual_Set);  // Clear PWM1A on event A, down count
    }
    void set_duty( int a)
    {
     CMPA = a;
     PWM_setCmpA(myPwm4, CMPA);
     PWM_setCmpB(myPwm4, CMPA);// Set compare A value
    }
    
    //===========================================================================
    // No more.