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.

LAUNCHXL-F28379D: 1 MHz ADC sampling frequency verification

Part Number: LAUNCHXL-F28379D

My application is essentially PWM control for synchronous buck converter, wherein my PWM frequency is 100 kHz, and I want to sample inductor current and output voltage as multiple samples per switching period.

My implementation is as follows:

  • ePWM 4A and 4B for the low and high side FETs PWM
  • ePWM 3A as ADC SOC trigger
  • Using ADC A2 as interrupt

I'm having trouble verifying 1MHz ADC sampling. Just for analysing and verifying ADC interrupt timing, I've used a counter to increment during each interrupt routine (keeping track of how much microseconds has elapsed), and when it reaches a value equal to 1 second, I increment a flag to denote that 1 second of interrupt routine has been serviced. With a stopwatch, I compare the 'flag' updating and the real time to ensure both are in the same speed.

This works accurately for ePWM3 frequencies upto 200 kHz, but beyond that the 'flag' update gets slower than 1 second. I'm not sure if my method of evaluating ADC interrupt timing is reliable/accurate or if there's something that actually affects ADC interrupt servicing beyond a certain rate. But I can see on an external oscilloscope that the ePWM3 pulses' frequency matches whatever the TBPRD and the prescalers refer to (in this case, 1 MHz). I even tried disabling the ePWM4 pulses just to rule out any prioritization issues, but still doesn't work. Please find attached the code.

// ePWM 4A: 100 kHz, 27% duty, up-down counting
// ePWM 4B: 100 kHz, 27% duty, up-down counting, deadband + complementary

#include "F28x_Project.h"
#include "math.h"

void Gpio_select();
void Setup_ePWM4();
void Setup_ePWM3();
void ConfigureADC(void);
void SetupADCSoftware(void);
extern interrupt void adca2_isr(void);

float duty=0.27; //open-loop duty ratio of control FET
float timerprd; //EPWM3 period in micro seconds for ADC SOC trigger
long int counter=0; //counter to check CPU Timer0 timing
int flag=0; //checking 1 sec counter mark
float AdcaResult0;
float ADC_voltage=0.0;
long int adc_f=1000e3; // ADC sampling rate
int adc_x=1, adc_y=1; // ADC ePWM PRD prescalers
Uint16 PWM3_PRD; //TBPRD for ePWM3

void main(void)
{
    InitSysCtrl();
    DINT;
    InitPieCtrl();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();

    PWM3_PRD = (100e6/adc_f/adc_x/adc_y)-1;
    timerprd = 1e6/adc_f;

    EALLOW;
    PieVectTable.ADCA2_INT = &adca2_isr;
    EDIS;

    IER |= M_INT10;
    PieCtrlRegs.PIEIER10.bit.INTx2 = 1;

    Gpio_select();
    //Setup_ePWM4();
    Setup_ePWM3();
    ConfigureADC();
    SetupADCSoftware();
    EINT;
    ERTM;

    while(1);

}

void Gpio_select()
{
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO4=1;
    GpioCtrlRegs.GPAMUX1.bit.GPIO5=1;
    GpioCtrlRegs.GPAMUX1.bit.GPIO6=1;
    GpioCtrlRegs.GPAMUX1.bit.GPIO7=1;
    EDIS;
}

void Setup_ePWM4()
{
    EPwm4Regs.TBCTL.bit.CLKDIV=0;
    EPwm4Regs.TBCTL.bit.HSPCLKDIV=0;
    EPwm4Regs.TBCTL.bit.CTRMODE=2;
    EPwm4Regs.TBPRD=500;
    EPwm4Regs.AQCTLA.all=0x0060;
    //EPwm3Regs.AQCTLB.all=0x0090;
    EPwm4Regs.CMPA.bit.CMPA=500*(1-duty);

    EPwm4Regs.DBCTL.bit.OUT_MODE=3;
    EPwm4Regs.DBCTL.bit.POLSEL=2;
    EPwm4Regs.DBRED.all=50;
    EPwm4Regs.DBFED.all=50;
}

void Setup_ePWM3()
{
    EPwm3Regs.TBCTL.bit.CLKDIV=0;
    EPwm3Regs.TBCTL.bit.HSPCLKDIV=0;
    EPwm3Regs.TBCTL.bit.CTRMODE=0;
    EPwm3Regs.TBPRD=PWM3_PRD;
    EPwm3Regs.AQCTLA.all=0x0012;
    EPwm3Regs.CMPA.bit.CMPA=PWM3_PRD/2;

    EPwm3Regs.ETSEL.bit.SOCAEN=1;
    EPwm3Regs.ETSEL.bit.SOCASEL=1;
    EPwm3Regs.ETPS.bit.SOCAPRD=1;
    EPwm3Regs.ETCLR.bit.SOCA=1;

    EPwm3Regs.ETSEL.bit.INTEN=1;
    EPwm3Regs.ETSEL.bit.INTSEL=1;
    EPwm3Regs.ETPS.bit.INTPRD=1;
    EPwm3Regs.ETCLR.bit.INT=1;
}

void ConfigureADC(void)
{
    EALLOW;
    AdcaRegs.ADCCTL2.bit.PRESCALE = 6; // Set ADCCLK divider to SYSCLK/4
    AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);
    AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1;
    AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // Set value to power up the ADCs
    EDIS;
    DELAY_US(1000); // Set value for delay of 1 ms to allow ADC time to power up
}

void SetupADCSoftware(void)
{
    Uint16 acqps;
    if(ADC_RESOLUTION_12BIT == AdcaRegs.ADCCTL2.bit.RESOLUTION)
    {
       acqps = 14; // Determine minimum acquisition window (in SYSCLKS)
    }
    else
    {
       acqps = 63; // Determine minimum acquisition window (in SYSCLKS)
    }
    EALLOW;
    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 4; // Set value for channel selection
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = acqps;
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 9; // Sets ePWM3 as SOC0 trigger source
    AdcaRegs.ADCINTSEL1N2.bit.INT2SEL = 0; // Event for which INT2 flag is set
    AdcaRegs.ADCINTSEL1N2.bit.INT2E = 1; // Enable INT2 flag
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT2 = 1; // Make sure INT2 flag is cleared
    EDIS;
}

extern interrupt void adca2_isr(void)
{
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT2 = 1;
    if(1 == AdcaRegs.ADCINTOVF.bit.ADCINT2)
    {
        AdcaRegs.ADCINTFLGCLR.bit.ADCINT2 = 1;
        AdcaRegs.ADCINTOVFCLR.bit.ADCINT2 = 1;
    }
    AdcaResult0 = AdcaResultRegs.ADCRESULT0; // Write code to store results to this variable
    ADC_voltage = AdcaResult0/4095*3; // Convert ADC result to voltage
    counter++;
    if(counter>=1000000/timerprd)
    {
        flag++;
        counter=0;
    }
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP10;
}

I'm relatively new to DSP programming, so please bear with my limited knowledge if I'm missing to add some additional information or making a simple mistake over here. Kindly requesting support with this matter. Let me know if I can provide any other supporting information to better assist my query.

Thanks in advance,
SV