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.

Confused about CLA interrupt frequency (adc_cla example 28035)

Other Parts Discussed in Thread: C2000WARE

Hello,

I am trying to understand the CLA example adc_cla for 28035. Without making any changes to the code, I try to see the CLA interrupt frequency on my oscilliscope. The CLA is triggered by adc interrupt 2, which is set to 20 kHz interrupt frequency in the example. After the CLA task 2, an interrupt is cla1_isr2 is entered in order to clear the adc interrupt flag. I added a gpio toggle in cla1_isr2 to see the CLA interrupt frequency on the oscilloscope. However, regardless of how I set the ADC interrupt frequency, the gpio toggles at 500 kHz! How come?

BR Niclas

__interrupt void cla1_isr2()
{
GpioDataRegs.GPBTOGGLE.bit.GPIO41 = 1;

AdcRegs.ADCINTFLGCLR.bit.ADCINT2 = 1; // Clear ADCINT2 flag reinitialize for next SOC
PieCtrlRegs.PIEACK.all = 0xFFFF;
}

  • Hi Niclas,

    Niclas Samuelsson said:
    The CLA is triggered by adc interrupt 2, which is set to 20 kHz interrupt frequency in the example.

    Did you check the ePWM1a output? Is it 20kHz? Introduce the init lines required for generating epwm output - Just for verification.

    Niclas Samuelsson said:
    However, regardless of how I set the ADC interrupt frequency, the gpio toggles at 500 kHz! How come?

    That's odd. Do you mean that you tried altering the TBPRD value of ePWM1?

    Regards,

    Gautam

  • Yes, when I change the TBPRD value of ePWM1 the gpio toggle looks the same on the oscilloscope. When I make the ePWM1 source for CLA task instead of ADCINT then the gpio toggle is changed as I change ePWM TBPRD.
  • //###########################################################################
    // Description:
    //!  \addtogroup f2803x_example_list
    //!  <h1>CLA ADC (cla_adc)</h1>
    //!
    //! In this example ePWM1 is setup to generate a periodic ADC SOC.
    //! Channel ADCINA2 is converted. When the ADC begins conversion,
    //! it will assert ADCINT2 which will start CLA task 2.
    //!
    //! Cla Task2 logs 20 ADCRESULT1 values in a circular buffer.
    //! When Task2 completes an interrupt to the CPU clears the ADCINT2 flag.
    //!
    //! \b Watch \b Variables \n
    //! - VoltageCLA       - Last 20 ADCRESULT1 values
    //! - ConversionCount  - Current result number
    //! - LoopCount        - Idle loop counter
    //
    //
    //###########################################################################
    // $TI Release: F2803x C/C++ Header Files and Peripheral Examples V130 $
    // $Release Date: May  8, 2015 $
    // $Copyright: Copyright (C) 2009-2015 Texas Instruments Incorporated -
    //             http://www.ti.com/ ALL RIGHTS RESERVED $
    //###########################################################################
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    #include "CLAShared.h"
    #include <string.h>
    #include <stdint.h>
    
    // Prototype statements for functions found within this file.
    __interrupt void cla1_isr2(void);
    
    // Global variables used in this example:
    #pragma DATA_SECTION(ConversionCount, "Cla1ToCpuMsgRAM");
    #pragma DATA_SECTION(VoltageCLA,      "Cla1ToCpuMsgRAM");
    
    Uint16 ConversionCount;
    Uint16 LoopCount;
    Uint16 VoltageCLA[NUM_DATA_POINTS];
    
    // These are defined by the linker file
    extern Uint16 Cla1funcsLoadStart;
    extern Uint16 Cla1funcsLoadSize;
    extern Uint16 Cla1funcsRunStart;
    
    main()
    {
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2803x_SysCtrl.c file.
       InitSysCtrl();
    
    // Step 2. Initialize GPIO:
    // This example function is found in the DSP2803x_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 DSP2803x_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 DSP2803x_DefaultIsr.c.
    // This function is found in DSP2803x_PieVect.c.
       InitPieVectTable();
    
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
       EALLOW;  // This is needed to write to EALLOW protected register
       PieVectTable.CLA1_INT2 = &cla1_isr2;
       EDIS;    // This is needed to disable write to EALLOW protected registers
    
    // Step 4. Initialize all the Device Peripherals:
       InitAdc();         // For this example, init the ADC
       AdcOffsetSelfCal();
    
    // Step 5. User specific code, enable interrupts:
    
    // Enable ADCINT1 in PIE
       PieCtrlRegs.PIEIER11.bit.INTx2 = 1;      // Enable INT 11.2 in the PIE (CLA Task2)
       IER |= M_INT11;                          // Enable CPU Interrupt 11
       EINT;          						    // Enable Global interrupt INTM
       ERTM;          						    // Enable Global realtime interrupt DBGM
    
    // Copy CLA code from its load address to CLA program RAM
    //
    // Note: during debug the load and run addresses can be
    // the same as Code Composer Studio can load the CLA program
    // RAM directly.
    //
    // The ClafuncsLoadStart, ClafuncsLoadEnd, and ClafuncsRunStart
    // symbols are created by the linker.
        memcpy((uint16_t *)&Cla1funcsRunStart,(uint16_t *)&Cla1funcsLoadStart, (unsigned long)&Cla1funcsLoadSize);
    
    // Initialize the CLA registers
       EALLOW;
       Cla1Regs.MVECT2 = (Uint16) (&Cla1Task2 - &Cla1Prog_Start)*sizeof(Uint32);
       Cla1Regs.MVECT8 = (Uint16) (&Cla1Task8 - &Cla1Prog_Start)*sizeof(Uint32);
       Cla1Regs.MPISRCSEL1.bit.PERINT2SEL = CLA_INT2_ADCINT2; // ADCINT2 starts Task 2
       Cla1Regs.MMEMCFG.bit.PROGE = 1;          // Map CLA program memory to the CLA
       Cla1Regs.MCTL.bit.IACKE = 1;             // Enable IACK to start tasks via software
       Cla1Regs.MIER.all = (M_INT8 | M_INT2);   // Enable Task 8 and Task 2
       Cla1ForceTask8andWait();                 // Force CLA task 8.
                                                // This will initialize ConversionCount to zero
    
       AdcRegs.ADCCTL1.bit.INTPULSEPOS = 0;	    // ADCINT trips when ADC begins conversion
       AdcRegs.INTSEL1N2.bit.INT2E     = 1;	    // Enable ADCINT2
       AdcRegs.INTSEL1N2.bit.INT2CONT  = 0;	    // Disable ADCINT2 Continuous mode
       AdcRegs.INTSEL1N2.bit.INT2SEL   = 1;	    // setup EOC1 to trigger ADCINT2 to fire
       AdcRegs.ADCSOC1CTL.bit.CHSEL    = 2;	    // set SOC1 channel select to ADCINA2
       AdcRegs.ADCSOC1CTL.bit.TRIGSEL  = 5;     // set SOC1 start trigger on EPWM1A
       AdcRegs.ADCSOC1CTL.bit.ACQPS    = 6;	    // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
       EDIS;
    
    // Assumes ePWM1 clock is already enabled in InitSysCtrl();
       EALLOW;
       SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
       EDIS;
       EPwm1Regs.ETSEL.bit.SOCAEN	= 1;		// Enable SOC on A group
       EPwm1Regs.ETSEL.bit.SOCASEL	= 4;		// Select SOC from from CPMA on upcount
       EPwm1Regs.ETPS.bit.SOCAPRD 	= 1;		// Generate pulse on 1st event
       EPwm1Regs.CMPA.half.CMPA 	= 0x2EE;	// Set compare A value
       EPwm1Regs.TBPRD 				= 0x5DC;	// Set period for ePWM1 - this will determine the sampling frequency(20KHz)
    
       EPwm1Regs.TBCTL.bit.CTRMODE 	= 0;		// count up and start
       EALLOW;
       SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    
    
       GpioCtrlRegs.GPBMUX1.bit.GPIO41 = 0;
       GpioCtrlRegs.GPBDIR.bit.GPIO41 = 1;
       GpioDataRegs.GPBSET.bit.GPIO41 = 0;
       EDIS;
    
    // Wait for ADC interrupt
       for(;;)
       {
    
          LoopCount++;
       }
    }
    
    // This interrupt occurs when CLA Task 2 completes
    __interrupt void cla1_isr2()
    {
        GpioDataRegs.GPBTOGGLE.bit.GPIO41 = 1;
    
        AdcRegs.ADCINTFLGCLR.bit.ADCINT2 = 1;    // Clear ADCINT2 flag reinitialize for next SOC
        PieCtrlRegs.PIEACK.all = 0xFFFF;
    }
    
    
    

  • Hi Niclas,

    You can also have the ADC interrupt trigger a C28x interrupt. If you do this an toggle the GPIO in the C28x ISR, do you see the frequency vary.

    The CLA task frequency should be varying with the ADC interrupt trigger frequency, along with the PWM frequency trigger to the ADC. I think you have the correct understanding. But to debug, you may want to create a ADC ISR on the C28x to confirm. Alternatively, you can toggle the GPIO in the CLA task.

    Right now, I am not sure why you are seeing this behavior.

    Regards,
    sal
  • I edited the code such that a C28x interrupt is triggered by the ADC EOC as you said. This interrupt also has unexpected frequency, the same as the CLA interrupt frequency. Somehow the ADC interrupt is triggered at a rate much faster than it should. Even if I change the PWM SOC signal period from 1 to 3, and change the TBPRD register, the ADC interrupt rate remains the same. My ADC interrupt configuration must be wrong somehow..
  • For help with the ADC, please see the ADC examples in C2000Ware and the chapter in the TRM.

    If you have specific questions regarding ADC, please create a new thread so that it can be answered appropriately.

    Regards,
    sal