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/LAUNCHXL-F28069M: Delay between specified Interruption and Interruption occurs

Part Number: LAUNCHXL-F28069M

Tool/software: Code Composer Studio

Hello,

 

I am starting with TI DSP and I am having a problem with the ADC interruptions.

I am configuring the ADC to start the conversion SOC when the period of the EPwm1 reaches the period (in count up-down mode). I have a GPIO8 that SETs in the Main.c when the flag of the SOC0 is 0. It CLEARs when the EOC0 finishes.

Nevertheless, when I capture with the oscilloscope the GPIO8, it does not SET when the period is reached (I am checking it with a EPwm1). And it is SET every 5 periods....

Could you please help me with this issue? What are the causes that may be generating that problem?

void main(void) {

    

// Initialization

   InitSysCtrl(); // Initialize the CPU               (FILE: SysCtrl.c)

   InitGpio();     // Initialize the shared GPIO pins (FILE: Gpio.c)

     InitPieCtrl();  // Initialize and enable the PIE     (FILE: PieCtrl.c)

     InitWatchdog(); // Initialize the Watchdog Timer     (FILE: WatchDog.c)

 

   InitEPwm1();   // Initialize the ePWM (FILE: ePWM.c)

 

    

//   Peripheral Initialization

     InitADC(); // Initialize the ADC (FILE: ADC.c)

     InitADC_SOC0(); // Initialize the SOCX     (FILE: ADC.c)

     goADC();         // ADC start working (FILE: ADC.c) <- Must be enable to work

    

     FLAG_int=0;

 

    

    

//   Enable global interrupts

     asm(" CLRC INTM, DBGM");   // Enable global interrupts and real-time debug

 

//   Main Loop

     while (1) // Endless loop - Wait for an interrupt

     {

 

      
        if ( (AdcRegs.ADCSOCFLG1.bit.SOC0 == 0) && (FLAG_int==0) ){
            GpioDataRegs.GPASET.bit.GPIO8 = 1;
            FLAG_int = 1;
        }

        if (AdcRegs.ADCINTFLG.bit.ADCINT1){
            FLAG_int = 0;
        }



        }

 

           asm(" NOP");

     }

 

} //end of main()

void InitEPwm1(void) {

 

   asm(" EALLOW");                     // Enable EALLOW protected register access

   SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;

   asm(" EDIS");                       // Disable EALLOW protected register access

 

   // Basic Register

   EPwm1Regs.TBPRD             =   EPWm1_Period;   // PWM Period

   EPwm1Regs.TBCTR             =   0x0000;         // Counter value. Set 0 = Reset.

   EPwm1Regs.TBPHS.half.TBPHS =   0x0000;        // Set timer phase

 

   //Setup TBCLK Register

   EPwm1Regs.TBCTL.bit.PHSDIR =   1;     // Only in Up-Down-Count Mode.

   EPwm1Regs.TBCTL.bit.CLKDIV     =   0x000; // 000 => TBCLK = HSPCLK/1 (pag. 339 of the manual)

   EPwm1Regs.TBCTL.bit.HSPCLKDIV   =   0x000; // HSPCLKDIV, 000 => HSPCLK = SYSCLKOUT/1

   EPwm1Regs.TBCTL.bit.SWFSYNC     =   0;     // Has not effect

   EPwm1Regs.TBCTL.bit.SYNCOSEL   =   1;     // Enabled

   EPwm1Regs.TBCTL.bit.PRDLD       =   0;     // Reload PRD on counter

   EPwm1Regs.TBCTL.bit.PHSEN       =   0;     // Phase loading disabled

   EPwm1Regs.TBCTL.bit.CTRMODE     =   2;     // 0=Up ; 1=Down ; 2=UpDown ; 3=Freeze

 

   //Setup Counter-Compare Register

   EPwm1Regs.CMPA.half.CMPA       =   EPWm1_Period*EPWm1_DutyA;   // Compare A = 455 for duty=0.5

   EPwm1Regs.CMPB                 =   70; //EPWm1_Period*EPWm1_DutyB-;   //Compare B = 455*0.5 for duty=0.25

   EPwm1Regs.CMPCTL.bit.SHDWAMODE =   0;

   EPwm1Regs.CMPCTL.bit.SHDWBMODE =   0;

   EPwm1Regs.CMPCTL.bit.LOADAMODE =   0;

   EPwm1Regs.CMPCTL.bit.LOADBMODE =   0;

 

   //Action-Qualifier Register (U=Up ; D=Down)

       //OutputA

           //Comparator A

   EPwm1Regs.AQCTLA.bit.CAU   =   0; //

   EPwm1Regs.AQCTLA.bit.CAD   =   0; //

           //Comparator B

   EPwm1Regs.AQCTLA.bit.CBU   =   0; //

   EPwm1Regs.AQCTLA.bit.CBD   =   0; //

           //Period and Zero

   EPwm1Regs.AQCTLA.bit.PRD   =   2; //

   EPwm1Regs.AQCTLA.bit.ZRO   =   1; //

 

   //DeadBand Register (R=Rising ; F=Falling)

   EPwm1Regs.DBCTL.bit.OUT_MODE   =   0; // 0 = Disable ; 1 = Falling B ; 2 = Rising A ; 3 = Enable

   EPwm1Regs.DBCTL.bit.POLSEL     =   0; //

   EPwm1Regs.DBRED                 =   0; //  

   EPwm1Regs.DBFED                 =   0; // Dead-time of 100 TBCLK counts

 

   //Chopper in 353

 

   //Event-Trigger Register

       //ADC Interruption

   EPwm1Regs.ETSEL.bit.SOCAEN =   1;

   EPwm1Regs.ETSEL.bit.SOCASEL =   2; // 2 Enable event time-base counter equal to period

   //Event-Trigger Prescale Register

       //ADC Interruption

   EPwm1Regs.ETPS.bit.SOCACNT =   0x1;

   EPwm1Regs.ETPS.bit.SOCAPRD =   0x1;

 

 

void InitPieCtrl(void)

{

//   Disable interrupts

     asm(" SETC INTM, DBGM");             // Disable global interrupts

 

//   Initialize the PIE_RAM

     PieCtrlRegs.PIECTRL.bit.ENPIE = 0;   // Disable the PIE

     asm(" EALLOW");                            // Enable EALLOW protected register access

 

     // Step around the first three 32-bit locations (six 16-bit locations).

     // These locations are used by the ROM bootloader during debug, and also

     // by the Flash API algorithms.

     memcpy((Uint16 *)&PieVectTable+6, (Uint16 *)&PieVectTableInit+6, 256-6);

 

     asm(" EDIS");

 

//   Enable the desired interrupts

 

     PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // Enable interrupt INT1 (for ADC EOC0)

IER |= 0x0204;

//   Acknowlege all PIE interrupt groups

     PieCtrlRegs.PIEACK.all = 0xFFFF;

 

//   Enable the PIE

     PieCtrlRegs.PIECTRL.bit.ENPIE = 1;

 

} // end of InitPieCtrl()

 

 

void InitADC(void)

{

   asm(" EALLOW");                 // Enable EALLOW protected register access

   AdcRegs.ADCCTL1.bit.RESET = 1; // Reset the ADC

   asm(" NOP");                   // Must wait 2 ADCCLK periods for the reset to take effect

   asm(" NOP");

 

   AdcRegs.ADCCTL1.bit.RESET       =   0; //ADC software reset:       No effect=0     ; Resets the ADC=1

   AdcRegs.ADCCTL1.bit.ADCENABLE   =   0; //ADC enable:               Disable=0       ; Enable=1

   AdcRegs.ADCCTL1.bit.ADCBSY     =   0; //ADC busy:                 Read-only

   AdcRegs.ADCCTL1.bit.ADCBSYCHN   =   0; //ADC busy channel:         Read-only       ; Bits:12-8

   AdcRegs.ADCCTL1.bit.ADCPWDN     =   1; //ADC power down:           Powered down=0 ; Powered up=1

   AdcRegs.ADCCTL1.bit.ADCBGPWD   =   1; //ADC band-gap power down: Powered down=0 ; Powered up=1

   AdcRegs.ADCCTL1.bit.ADCREFPWD   =   1; //ADC reference power down: Powered down=0 ; Powered up=1

 

   AdcRegs.ADCCTL1.bit.ADCREFSEL   =   0; //ADC reference select:     Internal=0             ; External=1

   AdcRegs.ADCCTL1.bit.INTPULSEPOS =   1; //INT pulse generation:     Start of conversion=0   ; End of conversion=1

   AdcRegs.ADCCTL1.bit.VREFLOCONV =   0; //VREFLO convert:           ADCINB5=0               ; VREFLO=1

   AdcRegs.ADCCTL1.bit.TEMPCONV   =   0; //Temperature convert:     ADCINA5=0               ; TEMPsensor=1

 

 

 

 

   AdcRegs.ADCCTL2.bit.ADCNONOVERLAP   =   1; //0=overlap sample and conversion, 1=no overlap

   AdcRegs.ADCCTL2.bit.CLKDIV2EN       =   1; //ADC clock divider. 0=CPUCLK, 1=CPUCLK/2

 

   DelayUs(1000); // Delay 1ms

 

   AdcRegs.SOCPRICTL.bit.SOCPRIORITY   =   0; // All SOCs handled in round-robin mode

 

   //ADC INTERRUPTION SETUP

   AdcRegs.ADCINTFLG.bit.ADCINT1   =   1; //ADC interrupt.   0=No pulse is generated. 1=Pulse Generated.

 

   AdcRegs.ADCINTFLGCLR.bit.ADCINT1   =   1;

 

   //Interruption 1

   AdcRegs.INTSEL1N2.bit.INT1CONT =   0;     // ADCINT1 pulses generated only when ADCINT1 flag is clear by user.

   AdcRegs.INTSEL1N2.bit.INT1E     =   1;     // Enable ADCINT1

   AdcRegs.INTSEL1N2.bit.INT1SEL   =   0;     // EOCx triggers ADCINT1. x=EOCx;

 

   asm(" EDIS");                       // Disable EALLOW protected register access

}

 

void goADC(void)

{

   asm(" EALLOW"); // Enable EALLOW protected register access

   AdcRegs.ADCCTL1.bit.ADCENABLE   = 1;

   asm(" EDIS");                       //

}

 

 

void InitADC_SOC0(void)

{

   asm(" EALLOW"); // Enable EALLOW protected register access

 

   AdcRegs.ADCSAMPLEMODE.bit.SIMULEN0 =   0; // SOCx 0=single sampling mode; 1=Simultaneous sampling mode.

 

   //Remove one of the following register. SEL1 is for SOC0 to SOC7. SEL2 is for SOC8 to SOC15.

   AdcRegs.ADCINTSOCSEL1.bit.SOC0     =   0; // 0=No ADCINT will trigger SOC0. 1=ADCINT1 will trigger SOC0. 2=ADCINT2 will trigger SOC0.

 

 

   //Control register SOC0

   AdcRegs.ADCSOC0CTL.bit.TRIGSEL     =   5; // 05h=ePWM1-ADCSOCA;

  

   AdcRegs.ADCSOC0CTL.bit.CHSEL           =   0;

   AdcRegs.ADCSOC0CTL.bit.ACQPS           =   6; // Acquisition window set to (x+1) cycles.

 

   // Note: The values will be saved on: AdcResult.ADCRESULT0;

   asm(" EDIS");                       // Disable EALLOW protected register access

 

}



interrupt void ADCINT1_ISR(void)   // ADC  (Can also be ISR for INT10.1 when enabled)
{
    // Insert ISR Code here

    // To receive more interrupts from this PIE group, acknowledge this interrupt
     PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;


     GpioDataRegs.GPACLEAR.bit.GPIO8 = 1;

    // To clear the flag.
    AdcRegs.ADCINTFLGCLR.bit.ADCINT1    =    1;
}

Thank you very much in advance for your help.

  • Your post has been assigned to an expert. 

    If you insert a code snippet in your post, always paste it using the “Syntax Highlighter” option. That makes the code easier to read.

  • Nicholas,
    Thanks for reaching out to us on the E2E. I've got a few recommendations, as well as an explanation for what you are seeing.

    1)I would not seperate the ADCENABLE bit setting to its own function; you can set it after you have set the ADC power up bits in your main ADC initializtion.
    2)I would not use ADCSOCFLG as you have done. This only shows when the start of conversion is pending and is immediately cleared when the ADC begins the conversion(not finished).

    Since you only have one ADCSOC in use, the first time the PWM sends the SOC signal to the ADC this ADCSOCFLG bit is going to get set then cleared on the next ADC clock cycle since the ADC is not busy. Likely the wait loop check you have will miss this setting most of the time, even with the 2:1 ratio of CPU clock to ADC clock

    There are 2 possiblities why you are seeing this bit get set after sometime when the C28x tried to read it:
    1)The timings match up exactly so we do see this set before it is automatically cleared.
    2)The period of the PWM is small enough that over time it "catches up" with the ADC conversion rate so that the ADC is still converting a previous SOC and has to pend this new SOC and the bit stays set for a longer time until the ADC can start the conversion.

    The use of the ADCINTFLG is the more reliable way to see that the conversion is complete and then clear it to check again. I see you have this lower down in the code

    Another way to check if the ADC is running that would have a longer set duration would be to use a combination of the ADCBSY bit and the ADCBSYCHN(if you had more than one channel) in ADCCTL1 register.

    Given the ratio of the MCU clock to the ADC clock, I'm pretty confident you would catch this happening, even with the while loop constraints(the branch the compiler is likely generating to implement the while loop in assembly will still eat 4 CPU cycles to fetch the discontinuity).

    Best,
    Matthew