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: ADC triggering using cpu_timer0

Part Number: TMS320F28379D
Other Parts Discussed in Thread: C2000WARE

Tool/software: Code Composer Studio

Hello All,

           This is Sainath. I'm relatively new to the TI family of micro controllers. I am working on the ADC conversion by using different analog signals from a signal generator. Can someone help me in triggering the ADC conversion using the cpu_timer0. Is there any sample code available in control suite. If not, can someone help me with a sample code on triggering ADC with cpu timer instead of using epwm.

Thank you.

Sincerely,

Sainath Reddy.

  • Hi Sainath,

    Is there a reason you're wanting to use the CPU timer to trigger the ADC rather than an EPwm? Using an EPwm is more common practice and can have some advantages over using a CPU timer.

    There is no example program within C2000ware for triggering the ADC using a CPU Timer, but there is for an EPwm, which you could alter to use a CPU timer if you really wanted.

    C:\ti\c2000\C2000Ware_1_00_02_00\device_support\f2837xd\examples\cpu1\adc_soc_epwm

    Also, the code piece on page 1397 of the TRM should help you: http://www.ti.com/lit/spruhm8.

    Best,
    Kevin

  • Hello Kevin,
    Thank you so much for your reply. I'm using the timers because I may need the PWM for some other applications. I have tried to modify the adc epwm code to timers. The code shows no errors but the ADC is not able to read the values.

    I have attached my code below. Can you please check if there are any flaws in the code.
    Thank you.

    Sincerely,

    Sainath Reddy.




    //! Monitor the GPIO34 LED blink on (for 500 msec) and off (for 500 msec) on
    //! the F2837xD control card.
    //!
    //
    //###########################################################################
    // $TI Release: F2837xD Support Library v210 $
    // $Release Date: Tue Nov 1 14:46:15 CDT 2016 $
    // $Copyright: Copyright (C) 2013-2016 Texas Instruments Incorporated -
    // http://www.ti.com/ ALL RIGHTS RESERVED $
    //###########################################################################

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

    //
    // Function Prototypes
    //

    void ConfigureADC(void);

    __interrupt void cpu_timer0_isr(void);

    //buffer for storing conversion results
    #define RESULTS_BUFFER_SIZE 256
    Uint16 AdcaResults[RESULTS_BUFFER_SIZE];
    Uint16 resultsIndex;
    volatile Uint16 bufferFull;
    Uint16 input[RESULTS_BUFFER_SIZE];
    Uint16 index=0;


    void main(void)
    {



    //Initialize results buffer

    for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++)
    {
    AdcaResults[resultsIndex] = 0;
    }
    resultsIndex = 0;


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

    //
    // Step 2. Initialize GPIO:
    // This example function is found in the F2837xD_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:
    //
    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 F2837xD_PieCtrl.c file.
    //
    InitPieCtrl();

    //
    // Disable CPU __interrupts and clear all CPU __interrupt flags:
    //
    IER = 0x0000;
    IFR = 0x0000;


    InitPieVectTable();


    EALLOW; // This is needed to write to EALLOW protected registers
    PieVectTable.TIMER0_INT = &cpu_timer0_isr;
    EDIS; // This is needed to disable write to EALLOW protected registers


    InitCpuTimers(); // For this example, only initialize the Cpu Timers

    // Configure CPU-Timer 0 to __interrupt every 500 milliseconds:
    // 60MHz CPU Freq, 50 millisecond Period (in uSeconds)
    //
    ConfigCpuTimer(&CpuTimer0, 60, 500000);

    //
    // To ensure precise timing, use write-only instructions to write to the entire
    // register. Therefore, if any of the configuration bits are changed in
    // ConfigCpuTimer and InitCpuTimers (in F2837xD_cputimervars.h), the below
    // settings must also be updated.
    //
    CpuTimer0Regs.TCR.all = 0x4001;

    //
    // Step 5. User specific code, enable __interrupts:
    // Configure GPIO34 as a GPIO output pin
    //
    EALLOW;
    GpioCtrlRegs.GPBMUX1.bit.GPIO34 = 0;
    GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1;
    EDIS;

    //
    // Enable CPU INT1 which is connected to CPU-Timer 0:
    //
    IER |= M_INT1;

    //
    // Enable TINT0 in the PIE: Group 1 __interrupt 7
    //
    PieCtrlRegs.PIEIER1.bit.INTx7 = 1;

    //
    // Enable global Interrupts and higher priority real-time debug events:
    //
    EINT; // Enable Global __interrupt INTM
    ERTM; // Enable Global realtime __interrupt DBGM

    //
    // Step 6. IDLE loop. Just sit and loop forever (optional):
    //
    for(;;);
    }

    //
    // cpu_timer0_isr - CPU Timer0 ISR that toggles GPIO32 once per 500ms
    //
    __interrupt void cpu_timer0_isr(void)
    {
    CpuTimer0.InterruptCount++;

    AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT0;

    input[index++] = AdcaResults[resultsIndex-1];

    if(RESULTS_BUFFER_SIZE <= resultsIndex)
    {
    resultsIndex = 0;
    index=0;
    bufferFull = 1;

    }

    GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1;

    //
    // Acknowledge this __interrupt to receive more __interrupts from group 1
    //
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    }



    void ConfigureADC(void)
    {
    EALLOW;

    //write configurations
    AdcaRegs.ADCCTL2.bit.PRESCALE = 6; //set ADCCLK divider to /4
    AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_DIFFERENTIAL);

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

    //
    // End of file
    //
  • Sainath,

    In your code it looks like you never called your ConfigureADC() function within main() and you also need to configure it to generate the SOCs (Start of Conversion).

    You need something similar to what's in the TRM and Epwm example program I mentioned:

    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 5; //SOC0 will convert ADCINA5
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = 23; //SOC0 will use sample duration of 24 SYSCLK cycles
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 3; //SOC0 will begin conversion on CPU1 Timer 2

    Alter the above to match whatever channels/timer you're wanting to use and compare to the Epwm example to make sure nothing else is needed.

    Just an FYI. The F28379D has 12 EPwm instances. You can have multiple EPwms running at different frequencies / configurations.

    Best,

    Kevin

  • I modified my code a little bit in order to use cpu_timer0 for triggering the ADC. Please find the code below.

    /###########################################################################
    // FILE:   adc_soc_epwm_cpu01.c
    // TITLE:  ADC triggering via epwm for F2837xD.
    //
    //! \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: F2837xD Support Library v190 $
    // $Release Date: Mon Feb  1 16:51:57 CST 2016 $
    // $Copyright: Copyright (C) 2013-2016 Texas Instruments Incorporated -
    //             http://www.ti.com/ ALL RIGHTS RESERVED $
    //###########################################################################
    
    #include "F28x_Project.h"     // Device Headerfile and Examples Include File
    
    void ConfigureADC(void);
    
    void ConfigureEPWM(void);
    
    void SetupADCEpwm(Uint16 channel);
    
    __interrupt void cpu_timer0_isr(void);
    
    
    //buffer for storing conversion results
    
    #define RESULTS_BUFFER_SIZE 256
    
    Uint16 AdcaResults[RESULTS_BUFFER_SIZE];
    
    Uint16 resultsIndex;
    
    volatile Uint16 bufferFull;
    
    Uint16 input[RESULTS_BUFFER_SIZE];
    
    Uint16 index=0;
    
    Uint16 var = 0;
    
    
    
    
    void main(void)
    {
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2837xD_SysCtrl.c file.
        InitSysCtrl();
    
    // Step 2. Initialize GPIO:
    // This example function is found in the F2837xD_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 F2837xD_PieCtrl.c file.
        InitPieCtrl();
    
        InitCpuTimers();   // For this example, only initialize the Cpu Timers
    
    // 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 F2837xD_DefaultIsr.c.
    // This function is found in F2837xD_PieVect.c.
        InitPieVectTable();
    
    //Map ISR functions
        EALLOW;
    
        EDIS;
    
    //Configure the ADC and power it up
        ConfigureADC();
    
    //Configure the ePWM
        ConfigureEPWM();
    
    //Setup the ADC for ePWM triggered conversions on channel 0
       SetupADCEpwm(0);
    
    
    
       PieVectTable.ADCA1_INT = &cpu_timer0_isr; //function for ADCA interrupt 1
    
       PieVectTable.TIMER2_INT = &cpu_timer0_isr;
    
    
    //
    // To ensure precise timing, use write-only instructions to write to the entire
    // register. Therefore, if any of the configuration bits are changed in
    // ConfigCpuTimer and InitCpuTimers (in F2837xD_cputimervars.h), the below
    // settings must also be updated.
    //
       CpuTimer2Regs.TCR.all = 0x4001;
    
    
    //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
    
    //Initialize results buffer
    
    
        ConfigCpuTimer(&CpuTimer0, 190, 22.67);
    
    //enable PIE interrupt
    
        PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
    
        PieCtrlRegs.PIEIER1.bit.INTx1 = 1;
    
    //sync ePWM
        EALLOW;
    
    
    
    
    
    
        //take conversions indefinitely in loop
        do
        {
            //start ePWM
            EPwm1Regs.ETSEL.bit.SOCAEN = 1;  //enable SOCA
    
            EPwm1Regs.TBCTL.bit.CTRMODE = 0; //unfreeze, and enter up count mode
    
            //wait while ePWM causes ADC conversions, which then cause interrupts,
            //which fill the results buffer, eventually setting the bufferFull
            //flag
            while(!bufferFull);
            bufferFull = 0; //clear the buffer full flag
    
            //stop ePWM
    
            EPwm1Regs.ETSEL.bit.SOCAEN = 0;  //disable SOCA
    
            EPwm1Regs.TBCTL.bit.CTRMODE = 3; //freeze counter
    
            //at this point, AdcaResults[] contains a sequence of conversions
            //from the selected channel
    
            //software breakpoint, hit run again to get updated conversions
            //asm("   ESTOP0");
        }while(1);
    }
    
    
    
    
    
    
    
    //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_16BIT, ADC_SIGNALMODE_DIFFERENTIAL);
    
        //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;
    }
    
    
    
    
    
    
    
    
    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;
    }
    
    
    
    
    
    
    
    
    void SetupADCEpwm(Uint16 channel)
    {
        Uint16 acqps;
    
        //determine minimum acquisition window (in SYSCLKS) based on resolution
    
        if(ADC_RESOLUTION_12BIT == AdcaRegs.ADCCTL2.bit.RESOLUTION)
        {
    
            acqps = 23; //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
    }
    
    
    
    
    
    
    interrupt void cpu_timer0_isr(void)
    
    {
        CpuTimer0.InterruptCount++;
    
        GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1;
    
        AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT0;
    
        input[index++] = AdcaResults[resultsIndex-1];
    
        if(RESULTS_BUFFER_SIZE <= resultsIndex)
        {
            resultsIndex = 0;
    
            index=0;
    
        }
    
        if(var==0)
        {
            var = 1;
        }
    
        else
        {
            var = 0;
        }
    
    
        AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear INT1 flag
    
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    }
    




    The problem I am facing now is that the ADC output values are getting displayed properly but not at the rate which I configured my cpu_timer0. Can you plese check if any thing needs to be changed in the code to get the timer period correct. ( To be more precise, the cpu_timer has been set to 44.1 kHz i.e., 22.67uS).

    Thank you.

    Regards,

    Sainath Reddy.

  • Hi Sainath,

    If you're trying to trigger the ADC with the CPU timer it looks like your TRIGSEL register is set for EPWM1.

    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; //trigger on ePWM1 SOCA/C

    This should be AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 1 for CPU1 Timer 0.

    One other thing I see is that you configured your CPU timer for your device running at 190 MHz.

    // ConfigCpuTimer - This function initializes the selected timer to the period
    //                  specified by the "Freq" and "Period" parameters. The "Freq"
    //                  is entered as "MHz" and the period in "uSeconds". The timer
    //                  is held in the stopped state after configuration.
    
    ConfigCpuTimer(&CpuTimer0, 190, 22.67);

    Are you running your device at 190 MHz instead of the max 200 MHz? Just something to check, probably want to change the middle argument to 200 if so.

    Hope this helps,

    Kevin