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.

Piccolo ADC Timing?



Hi all,

I am playing with the Piccolo F28035 examples and try to understand the ADC timings.

I want to start sequential AD conversion for channels 0..5 on PWM timer equal to zero and get an interrupt when all channels are sampled.
I have set up the ADC and PWM so that the PWM timer is upcounting and triggering an SOC on A group on time-base counter equal to zero.
The ADC SOC start triggers are set up for start on ePWM1A (for several ADC channels, here 0..5).
I have setup EOC0..5 to trigger ADCINT1 to fire and measured the PWM counter when entering the interrupt for the different EOC trigger 0..5 settings.
I get the following timing values (measured via breakpoint on interrupt entry):
setup EOC0 to trigger ADCINT1 to fire: EPwm1Regs.TBCTR = 22
setup EOC1 to trigger ADCINT1 to fire: EPwm1Regs.TBCTR = 27
setup EOC2 to trigger ADCINT1 to fire: EPwm1Regs.TBCTR = 34
setup EOC3 to trigger ADCINT1 to fire: EPwm1Regs.TBCTR = 40
setup EOC4 to trigger ADCINT1 to fire: EPwm1Regs.TBCTR = 47
setup EOC5 to trigger ADCINT1 to fire: EPwm1Regs.TBCTR = 53

The first timer value is clear, EOC pulse after 22 cycles is like in the datasheet.
The following samples do not take 13 cycles as described in the datasheet, but only 5..7 cycles.
Where is my fault?

Here is my code:

// Enable ADCINT1 in PIE
   PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // Enable INT 1.1 in the PIE
   IER |= M_INT1;       // Enable CPU Interrupt 1
   EINT;                // Enable Global interrupt INTM
   ERTM;                // Enable Global realtime interrupt DBGM

   LoopCount = 0;
   ConversionCount = 0;

// Configure ADC
 EALLOW;
 AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1; //ADCINT1 trips after AdcResults latch
 AdcRegs.INTSEL1N2.bit.INT1E     = 1; //Enabled ADCINT1
 AdcRegs.INTSEL1N2.bit.INT1CONT  = 0; //Disable ADCINT1 Continuous mode
 //AdcRegs.INTSEL1N2.bit.INT1SEL = 0; //setup EOC0 to trigger ADCINT1 to fire
 //AdcRegs.INTSEL1N2.bit.INT1SEL = 1; //setup EOC1 to trigger ADCINT1 to fire
 //AdcRegs.INTSEL1N2.bit.INT1SEL = 2; //setup EOC2 to trigger ADCINT1 to fire
 //AdcRegs.INTSEL1N2.bit.INT1SEL = 3; //setup EOC3 to trigger ADCINT1 to fire
 AdcRegs.INTSEL1N2.bit.INT1SEL = 5; //setup EOC4 to trigger ADCINT1 to fire


 AdcRegs.ADCSOC0CTL.bit.CHSEL   = 4; //set SOC0 channel select to ADCINA4
 AdcRegs.ADCSOC0CTL.bit.TRIGSEL  = 5; //set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
 AdcRegs.ADCSOC0CTL.bit.ACQPS   = 6; //set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)

 AdcRegs.ADCSOC1CTL.bit.CHSEL   = 2; //set SOC1 channel select to ADCINA2
 AdcRegs.ADCSOC1CTL.bit.TRIGSEL  = 5; //set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
 AdcRegs.ADCSOC1CTL.bit.ACQPS   = 6; //set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)

 AdcRegs.ADCSOC2CTL.bit.CHSEL   = 3; //set SOC2 channel select to ADCINA3
 AdcRegs.ADCSOC2CTL.bit.TRIGSEL  = 5; //set SOC2 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
 AdcRegs.ADCSOC2CTL.bit.ACQPS   = 6; //set SOC2 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)

 AdcRegs.ADCSOC3CTL.bit.CHSEL   = 5; //set SOC3 channel select to ADCINA5
 AdcRegs.ADCSOC3CTL.bit.TRIGSEL  = 5; //set SOC3 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
 AdcRegs.ADCSOC3CTL.bit.ACQPS   = 6; //set SOC3 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)

 AdcRegs.ADCSOC4CTL.bit.CHSEL   = 7; //set SOC4 channel select to ADCINA5
 AdcRegs.ADCSOC4CTL.bit.TRIGSEL  = 5; //set SOC4 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
 AdcRegs.ADCSOC4CTL.bit.ACQPS   = 6; //set SOC4 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)

 AdcRegs.ADCSOC5CTL.bit.CHSEL   = 9; //set SOC5 channel select to ADCINA5
 AdcRegs.ADCSOC5CTL.bit.TRIGSEL  = 5; //set SOC5 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
 AdcRegs.ADCSOC5CTL.bit.ACQPS   = 6; //set SOC5 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
 EDIS;

// Assumes ePWM1 clock is already enabled in InitSysCtrl();
   EPwm1Regs.ETSEL.bit.SOCAEN = 1;  // Enable SOC on A group
   //EPwm1Regs.ETSEL.bit.SOCASEL = 4;  // Select SOC from CPMA on upcount
   EPwm1Regs.ETSEL.bit.SOCASEL = 1;  // Enable event time-base counter equal to zero. (TBCTR = 0x0000)
   EPwm1Regs.ETPS.bit.SOCAPRD  = 1;  // Generate pulse on 1st event
   EPwm1Regs.CMPA.half.CMPA  = 0x0080; // Set compare A value
   EPwm1Regs.TBPRD     = 0xFFFF; // Set period for ePWM1
   EPwm1Regs.TBCTL.bit.CTRMODE  = 0;  // count up and start

// Wait for ADC interrupt
   for(;;)
   {
      LoopCount++;
   }

}


interrupt void  adc_isr(void)
{

  Voltage1[ConversionCount] = AdcResult.ADCRESULT0; // <- here is the breakpoint and EPwm1Regs.TBCTR measured
  Voltage2[ConversionCount] = AdcResult.ADCRESULT1;
  Voltage3[ConversionCount] = AdcResult.ADCRESULT2;

  // If 20 conversions have been logged, start over
  if(ConversionCount >= 9)
  {
     ConversionCount = 0;
  }
  else ConversionCount++;

  AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;  //Clear ADCINT1 flag reinitialize for next SOC
  PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;   // Acknowledge interrupt to PIE

  return;
}

  • Stephan,

    By default the ePWM timers are running at SYSCLK/2; you'll need to set the HSPCLK divider in TBCTL register to 0 to get SYSCLK equal to the timebase clock.

    This is what is causing the delta in the timer value for interrupts 1-5 to be ~half of what is specified.

    For the ADCEOC0 case this was a case of 2 factors coming together to give the apparent correct time; 1) the already mentioned half clock rate giving fewer apparent cycles and 2)The C ISR latency adding significant overhead boosting the number of clock cycles.

    Using your code with the correct dividers I get a value of 44 for the 1st TBCTR read, and 57/70/83/ etc for the other ISRs.  These means there is around 22 cycles of overhead from the ISR being generated in the ADC to actually executing ISR code; this is because of context saves and pipeline discontinuities introduced by the ISR.

    The timings listed for the ADC in the DS/UG are correct.

    Best,

    Matthew

  • Ah, thanks, that was it!

    Setting EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0 leads to a PWM timer running at SYSCLK.

    In addition, we have the interrupt latency, but this is clear and only an offset. When comparing 2 channel timings, it won't be in the timing result.

    Now the measured timing is like in the datasheet - 13 cycles minimum.