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-F28377S: Max rate ADC-DAC

Part Number: LAUNCHXL-F28377S

Hi Guys,

I modified "adc_soc_epwm_cpu01.c" example in order to verify the speed of chain ADC-DAC.

The code:

//###########################################################################
//
// FILE:   adc_soc_epwm_cpu01.c
//
// TITLE:  ADC triggering via epwm for F2837xS.
//
//! \addtogroup cpu01_example_list
//! <h1> ADC ePWM Triggering (adc_soc_epwm)</h1>
//!
//! This example sets up the ePWM to periodically trigger the ADC.
//!
//! After the program runs, the memory will contain:\n
//! - \b AdcaResults \b: A sequence of analog-to-digital conversion samples from
//! pin A0. The time between samples is determined based on the period
//! of the ePWM timer.
//
//###########################################################################
// $TI Release: F2837xS Support Library v210 $
// $Release Date: Tue Nov  1 15:35:23 CDT 2016 $
// $Copyright: Copyright (C) 2014-2016 Texas Instruments Incorporated -
//             http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################

//
// Included Files
//
#include "F28x_Project.h"

//
// Function Prototypes
//
void ConfigureADC(void);
void ConfigureEPWM(void);
void SetupADCEpwm(Uint16 channel);
interrupt void adca1_isr(void);
void configureDAC_B(void);
void Set_Sample_Frequency(float FS);



void main(void)
{
//
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xS_SysCtrl.c file.
//
    InitSysCtrl();

//
// Step 2. Initialize GPIO:
// This example function is found in the F2837xS_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
//
    InitGpio(); // Skipped for this example

//
// 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 F2837xS_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 F2837xS_DefaultIsr.c.
// This function is found in F2837xS_PieVect.c.
//
    InitPieVectTable();

//
// Map ISR functions
//
    EALLOW;
    PieVectTable.ADCA1_INT = &adca1_isr; //function for ADCA interrupt 1
    EDIS;

//
// Configure the ADC and power it up
//
    ConfigureADC();
    configureDAC_B();

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


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

//
// sync ePWM
//
    EALLOW;
    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    
            //
        //start ePWM and never stop
        //
        
        
        Set_Sample_Frequency(100000.0); //100KHz rate
        EPwm1Regs.ETSEL.bit.SOCAEN = 1;  //enable SOCA
        EPwm1Regs.TBCTL.bit.CTRMODE = 0; //unfreeze, and enter up count mode
    

//
//take conversions indefinitely in loop
//
    do
    {
       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
    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 = channel;  //SOC0 will convert pin A0
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = acqps; //sample window is 100 SYSCLK cycles
    AdcaRegs.ADCSOC0CTL.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)
{
    DacbRegs.DACVALS.all = AdcaResultRegs.ADCRESULT0; //assign converted value by ADC immediatly to DAC
    
     // I whish insert FIR or IIR filter for real time processing
      // How much complex can be my filter to ensure streaming processing?
       // which is sampling rate limit with 200MHz SYSCLOCK?    
        // Which is the DAC rate limit?



    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear INT1 flag
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

//
// End of file
//




void configureDAC_B(void)

{

    EALLOW;

    

    CpuSysRegs.PCLKCR16.bit.DAC_B = 1; // enable DAC_B clock



    DacbRegs.DACCTL.bit.DACREFSEL = 1; // use ADC VREFHI instead of an external signal

    DacbRegs.DACCTL.bit.LOADMODE = 0; // load on SysClk not PWMSYNC (PWM not yet enabled)

    DacbRegs.DACOUTEN.bit.DACOUTEN = 1; // enable output

    DacbRegs.DACVALS.all = 0; // output = 0

    DELAY_US(10); // Delay for buffered DAC to power up



    EDIS;

}

void Set_Sample_Frequency(float FS)
{
    unsigned int TBPRD = 0;
    unsigned int CMPA = 0;
    TBPRD = (unsigned int)((rnd_SP_RS(200000000.0/(4*FS)-1)));
    CMPA = (unsigned int)((rnd_SP_RS((TBPRD/2.0)-1)));
    EPwm1Regs.CMPA.bit.CMPA = CMPA;
    EPwm1Regs.TBPRD = TBPRD;

}



The code work fine quite, the output waveform is acceptable, but i haven't example to show now.

Some question i have,  please read interrupt void adca1_isr(void) function into posted code.

   
     How much complex can be my filter to ensure streaming processing?
     Which is sampling rate limit with 200MHz SYSCLOCK?   
     Which is the DAC rate limit?

Thank you very much for help

Best regards
Paolo Marsilia.

  • Paolo,

    The maximum PWM clock on this device is 100 MHz. I want to check you are aware of that because the "Set_Sample_Frequency" function seems to be using 200 MHz in the equation for calculating TBPRD. Since SYSCLK is 200 MHz, you must set PERCLKDIVSEL.EPWMCLKDIV to /2 (see internal clock frequencies table in the datasheet).

    Once you have this, for a 100 kHz sample rate you should be loading TBPRD with 1,000 decimal. You therefore have 2,000 CPU clock cycles between interrupts and this is the number of cycles available to support your filter and the ISR overhead. It's quite a lot, just for filtering.

    To get an idea of processing requirements, I suggest looking at the filter function in the FPU DSP library in C2000Ware. If you have this
    installed in the default location on your hard drive, the documentation will be at:
    C:\ti\c2000\C2000Ware_1_00_01_00\libraries\dsp\FPU\c28\docs
    There are tables of benchmarks in each function description.

    ADC sample rate is a more complicated question which involves the input settling time. It's not just related to the CPU clock speed.
    In principle, each ADC will run at up to 3.5 MSPS in 12-bit mode.

    From the datasheet, the DAC settling time is 2 us (typ), so you probably wouldn't want to go much faster than the 100 kHz you're using.

    I hope this helps. Please post back if this doesn't answer all your questions.

    Regards,

    Richard
  • Hy Richard,
    thank you very much for help.

    The question of PWM it's curious situation. I'm already using Set_Sample_Frequency() in other project and this works fine: i computed fundamental frequency of sine and square signals acquired to set rate with this function and FFT fundamental detected is correct.
    However i will check better my code.

    I'was just consulting the library, i hope to use FIR Filter Module as soon as possible so i can give a feedback.

    Best regards

    Paolo