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.

2 High Speed PWMs initialization Problem (F28027 Launchpad)

Dear Friends,

I'm trying to initialize two PWM modules for my application in Buck converters. myPwm3 is supposed to start at 1 Mhz rate and trigger the ADC to read the input  voltage, and myPwm2 is supposed to create a 100Khz square wave to maintain the switching frequency. The problem is when I try to run this program one the launchpad, the second PWM (100Khz) does not work. When I try to reduce the myPwm3 PWM's frequency to around 500Khz, the second PWM also starts working. Could you let me know how can I solve this problem with the speed? Theoretically this launchpad is supposed to be able to run these PWMs at the frequencies I need, so I don't know what is the problem. Also could you let me know if the ADC is triggered correctly in this code?

Thank you,

Soroush 

//#############################################################################
//
// File: f2802x_examples/adc_soc/Example_F2802xAdcSoc.c
//
// Title: F2802x ADC Start-Of-Conversion (SOC) Example Program.
//
// Group: C2000
// Target Device: TMS320F2802x
//
//! \addtogroup example_list
//! <h1>ADC Start-Of-Conversion (SOC)</h1>
//!
//! Interrupts are enabled and the ePWM1 is setup to generate a periodic
//! ADC SOC - ADCINT1. Two channels are converted, ADCINA4 and ADCINA2.
//!
//! Watch Variables:
//!
//! - Voltage1[10] - Last 10 ADCRESULT0 values
//! - Voltage2[10] - Last 10 ADCRESULT1 values
//! - ConversionCount - Current result number 0-9
//! - LoopCount - Idle loop counter
//
// (C) Copyright 2012, Texas Instruments, Inc.
//#############################################################################
// $TI Release: PACKAGE NAME $
// $Release Date: PACKAGE RELEASE DATE $
//#############################################################################

#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/pwm.h"
#include "f2802x_common/include/wdog.h"

// Prototype statements for functions found within this file.
__interrupt void adc_isr(void);
void Adc_Config(void);

__interrupt void epwm2_isr(void);
__interrupt void epwm3_isr(void);


#ifdef _FLASH
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif

// Global variables used in this example:
uint16_t LoopCount;
uint16_t ConversionCount;
uint16_t Voltage1;
uint16_t Ramp=2000;


ADC_Handle myAdc;
CLK_Handle myClk;
FLASH_Handle myFlash;
GPIO_Handle myGpio;
PIE_Handle myPie;
PWM_Handle myPwm3 , myPwm2;

void main(void)
{

CPU_Handle myCpu;
PLL_Handle myPll;
WDOG_Handle myWDog;

// Initialize all the handles needed for this application
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));
myPwm3 = PWM_init((void *)PWM_ePWM3_BASE_ADDR, sizeof(PWM_Obj));
myPwm2 = PWM_init((void *)PWM_ePWM2_BASE_ADDR, sizeof(PWM_Obj));

myWDog = WDOG_init((void *)WDOG_BASE_ADDR, sizeof(WDOG_Obj));


// Perform basic system initialization
WDOG_disable(myWDog);
CLK_enableAdcClock(myClk);
CLK_enableTbClockSync(myClk);

(*Device_cal)();

//Select the internal oscillator 1 as the clock source
CLK_setOscSrc(myClk, CLK_OscSrc_Internal);

// Setup the PLL for x10 /2 which will yield 50Mhz = 10Mhz * 10 / 2
PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2);

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

// If running from flash copy RAM only functions to RAM
#ifdef _FLASH
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif


// Initalize GPIO
GPIO_setPullUp(myGpio, GPIO_Number_4, GPIO_PullUp_Disable);
GPIO_setMode(myGpio, GPIO_Number_4, GPIO_4_Mode_EPWM3A);


GPIO_setPullUp(myGpio, GPIO_Number_2, GPIO_PullUp_Disable);
GPIO_setMode(myGpio, GPIO_Number_2, GPIO_2_Mode_EPWM2A);

GPIO_setPullUp(myGpio, GPIO_Number_5, GPIO_PullUp_Disable);
GPIO_setMode(myGpio, GPIO_Number_5, GPIO_5_Mode_GeneralPurpose);
GPIO_setDirection(myGpio, GPIO_Number_5, GPIO_Direction_Output);


// Setup a debug vector table and enable the PIE
PIE_setDebugIntVectorTable(myPie);
PIE_enable(myPie);

// Register interrupt handlers in the PIE vector table
PIE_registerPieIntHandler(myPie, PIE_GroupNumber_10, PIE_SubGroupNumber_1, (intVec_t)&adc_isr);
CLK_setClkOutPreScaler(myClk, CLK_ClkOutPreScaler_SysClkOut_by_1);

// Register interrupt handlers in the PIE vector table
// PIE_registerPieIntHandler(myPie, PIE_GroupNumber_3, PIE_SubGroupNumber_1, (intVec_t)&epwm1_isr);


PIE_registerPieIntHandler(myPie, PIE_GroupNumber_3, PIE_SubGroupNumber_2, (intVec_t)&epwm2_isr);
PIE_registerPieIntHandler(myPie, PIE_GroupNumber_3, PIE_SubGroupNumber_3, (intVec_t)&epwm3_isr);

// Enable CPU INT3 which is connected to EPWM1-3 INT:
CPU_enableInt(myCpu, CPU_IntNumber_3);

// Enable EPWM INTn in the PIE: Group 3 interrupt 1-3
PIE_enablePwmInt(myPie, PWM_Number_3);
PIE_enablePwmInt(myPie, PWM_Number_2);


// Enable global Interrupts and higher priority real-time debug events:
CPU_enableGlobalInts(myCpu);
CPU_enableDebugInt(myCpu);

// Initialize the ADC
ADC_enableBandGap(myAdc);
ADC_enableRefBuffers(myAdc);
ADC_powerUp(myAdc);
ADC_enable(myAdc);
ADC_setVoltRefSrc(myAdc, ADC_VoltageRefSrc_Int);

// Enable ADCINT1 in PIE
PIE_enableAdcInt(myPie, ADC_IntNumber_1);
// Enable CPU Interrupt 1
CPU_enableInt(myCpu, CPU_IntNumber_10);
// Enable Global interrupt INTM
CPU_enableGlobalInts(myCpu);
// Enable Global realtime interrupt DBGM
CPU_enableDebugInt(myCpu);

LoopCount = 0;
ConversionCount = 0;

// Configure ADC
//Note: Channel ADCINA4 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_EOC2); //setup EOC2 to trigger ADCINT1 to fire
ADC_setSocChanNumber (myAdc, ADC_SocNumber_0, ADC_SocChanNumber_A4); //set SOC0 channel select to ADCINA4
ADC_setSocChanNumber (myAdc, ADC_SocNumber_1, ADC_SocChanNumber_A4); //set SOC1 channel select to ADCINA4
//ADC_setSocChanNumber (myAdc, ADC_SocNumber_2, ADC_SocChanNumber_A2); //set SOC2 channel select to ADCINA2
ADC_setSocTrigSrc(myAdc, ADC_SocNumber_0, ADC_SocTrigSrc_EPWM3_ADCSOCA); //set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
ADC_setSocTrigSrc(myAdc, ADC_SocNumber_1, ADC_SocTrigSrc_EPWM3_ADCSOCA); //set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
ADC_setSocTrigSrc(myAdc, ADC_SocNumber_2, ADC_SocTrigSrc_EPWM3_ADCSOCA); //set SOC2 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1, then SOC2
ADC_setSocSampleWindow(myAdc, ADC_SocNumber_0, ADC_SocSampleWindow_7_cycles); //set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
ADC_setSocSampleWindow(myAdc, ADC_SocNumber_1, ADC_SocSampleWindow_7_cycles); //set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
ADC_setSocSampleWindow(myAdc, ADC_SocNumber_2, ADC_SocSampleWindow_7_cycles); //set SOC2 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)

CLK_enableTbClockSync(myClk);


// Enable PWM clock
CLK_enablePwmClock(myClk, PWM_Number_3);
CLK_enablePwmClock(myClk, PWM_Number_2);


// --------PWM 1 (ADC Trigger) -------------------------------------

// Setup TBCLK
PWM_setCounterMode(myPwm3, PWM_CounterMode_Up); // Count up/down
PWM_setPeriod(myPwm3, 60); // Set timer period
PWM_disableCounterLoad(myPwm3); // Disable phase loading
PWM_enableHrPhaseSync (myPwm3);
PWM_setPhase(myPwm3, 0x0000); // Phase is 0
PWM_setCount(myPwm3, 0x0000); // Clear counter
PWM_setHighSpeedClkDiv(myPwm3, PWM_HspClkDiv_by_1); // Clock ratio to SYSCLKOUT
PWM_setClkDiv(myPwm3, PWM_ClkDiv_by_1);


// Setup PWM
PWM_enableSocAPulse(myPwm3); // Enable SOC on A group
PWM_setSocAPulseSrc(myPwm3, PWM_SocPulseSrc_CounterEqualCmpAIncr); // Select SOC from from CPMA on upcount
PWM_setSocAPeriod(myPwm3, PWM_SocPeriod_FirstEvent); // Generate pulse on 1st event

// Set Compare values
PWM_setCmpA(myPwm3, 30); // Set compare A value
PWM_setCmpB(myPwm3, 40); // Set compare B value

PWM_setActionQual_Period_PwmA(myPwm3, PWM_ActionQual_Clear); // Clear PWM3A on period
PWM_setActionQual_CntUp_CmpB_PwmA(myPwm3, PWM_ActionQual_Set); // Set PWM3A on event A, up count


// Interrupt where we will change the Compare Values
PWM_setIntMode(myPwm3, PWM_IntMode_CounterEqualZero); // Select INT on Zero event
PWM_enableInt(myPwm3); // Enable INT
PWM_setIntPeriod(myPwm3, PWM_IntPeriod_SecondEvent); // Generate INT on 3rd event

// --------PWM 2 (100Khz clock) -------------------------------------

// Setup TBCLK
PWM_setCounterMode(myPwm2, PWM_CounterMode_Up); // Count up/down
PWM_setPeriod(myPwm2, 600); // Set timer period
PWM_enableHrPhaseSync (myPwm2);
PWM_disableCounterLoad(myPwm2); // Disable phase loading
PWM_setPhase(myPwm2, 0x0000); // Phase is 0
PWM_setCount(myPwm2, 0x0000); // Clear counter
PWM_setHighSpeedClkDiv(myPwm2, PWM_HspClkDiv_by_1); // Clock ratio to SYSCLKOUT
PWM_setClkDiv(myPwm2, PWM_ClkDiv_by_1);


// Set Compare values
PWM_setCmpA(myPwm2,300); // Set compare A value


// Set Actions
// PWM_setActionQual_Period_PwmA(myPwm1, PWM_ActionQual_Set); // Set PWM2A on period
// PWM_setActionQual_CntDown_CmpB_PwmA(myPwm1, PWM_ActionQual_Clear); // Clear PWM3A on event B, down count

PWM_setActionQual_Period_PwmA(myPwm2, PWM_ActionQual_Set); // Clear PWM2A on period
PWM_setActionQual_CntUp_CmpA_PwmA(myPwm2, PWM_ActionQual_Clear); // Set PWM2A on event A, up count

// Interrupt where we will change the Compare Values
PWM_setIntMode(myPwm2, PWM_IntMode_CounterEqualZero); // Select INT on Zero event
PWM_enableInt(myPwm2); // Enable INT
PWM_setIntPeriod(myPwm2, PWM_IntPeriod_FirstEvent); // Generate INT on 3rd event

// Wait for ADC interrupt
for(;;)
{
LoopCount++;


}

}


__interrupt void epwm2_isr(void)

{


GPIO_setHigh(myGpio, GPIO_Number_5);
Ramp=1960;

PWM_clearIntFlag(myPwm2);

// Acknowledge this interrupt to receive more interrupts from group 3
PIE_clearInt(myPie, PIE_GroupNumber_3);


return;
}


__interrupt void epwm3_isr(void)

{
Ramp=Ramp-50;

PWM_clearIntFlag(myPwm3);

// Acknowledge this interrupt to receive more interrupts from group 3
PIE_clearInt(myPie, PIE_GroupNumber_3);


return;
}

__interrupt void adc_isr(void)
{

//discard ADCRESULT0 as part of the workaround to the 1st sample errata for rev0
Voltage1 = ADC_readResult(myAdc, ADC_ResultNumber_1);

if (Voltage1>=Ramp) GPIO_setLow(myGpio, GPIO_Number_5);

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

PWM_clearIntFlag(myPwm3);

// Acknowledge this interrupt to receive more interrupts from group 3
PIE_clearInt(myPie, PIE_GroupNumber_3);


return;
}

  • Hi Soroush,

    My understanding based on a quick look at your code is that both the ADC ISR and the ePWM ISR are running at 1MHz.  My guess is that because of this, the CPU is running out of bandwidth.

    Since the interrupt frequency is 1MHz and the CPU clock is 60MHz, this allows about 60 cycles for both interrupts to be entered and completed. The ISR latency for C28x is about 14 cycles (http://processors.wiki.ti.com/index.php/Interrupt_FAQ_for_C2000), which doesn't leave much time to process 2 interrupts in 60 cycles.

    You could try spin-waiting on the ADC finished flag to remove the ADC ISR and you could decrement the ramp count each time the ADC is finished to remove the ePWM ISR.

    You may also want to look at F2803x devices, since they have a comparator with ramp-generator (I think this can do in HW what you are doing with ADC + ePWM in SW) and a CLA co-processor (which you may be able to offload something like the ramp compare to, to free up the main CPU). F2806x devices have the ramp generator and CLA, plus a faster CPU speed (90MHz).

  • Hi Devin,

    Thank you for your response. I tried to remove the Pwm ISR and put the ramp generating code inside the ADC ISR., and it helped a bit, I could increase the ADC trigger to 600Khz. I'am facing another problem, and that is the output has not constant duty cycle, it keeps changing so fast withing a cycle, like a noise is on the input read from the ADC. Could you help me on how to solve this problem?

    Thank you,

    Soroush

  • Hi Soroush,

    What are you using to drive the ADC input? Is there any filtering in this signal conditioning circuitry? Is it possible to drive a clean DC voltage through this circuitry and measure the distribution of ADC results? Can you remove the control-loop and use a constant duty cycle with constant load, and again measure the distribution of ADC results?