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.

Sampling ADC at higher frequency

Hi

 

I've been experimenting with the example Example_2803xAdcSoc.c to read ADC values while using the PWM to generate interrupts for the ADC.

It's working great, except that I would like to sample ADC values at a much higher frequency. Around 200Khz

I suppose I need to change this value:

  EPwm1Regs.TBPRD = 0xFFFF; // Set period for ePWM1

However, when I get around TBPRD = 100, the interrupts are not executed anymore, no conversion are made
Any idea? Thx 
Example below

 

Example_2803xAdcSoc.c

 

 

 

#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File

 

// Prototype statements for functions found within this file.

interrupt void adc_isr(void);

void Adc_Config(void);

 

 

// Global variables used in this example:

Uint16 LoopCount;

Uint16 ConversionCount;

Uint16 Voltage1[10];

Uint16 Voltage2[10];

 

 

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.ADCINT1 = &adc_isr;

   EDIS;    // This is needed to disable write to EALLOW protected registers

 

// Step 4. Initialize all the Device Peripherals:

// This function is found in DSP2803x_InitPeripherals.c

// InitPeripherals(); // Not required for this example

   InitAdc();  // For this example, init the ADC

// Step 5. User specific code, enable interrupts:

// 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 = 1; //setup EOC1 to trigger ADCINT1 to fire

AdcRegs.ADCSOC0CTL.bit.CHSEL = 4; //set SOC0 channel select to ADCINA4

AdcRegs.ADCSOC1CTL.bit.CHSEL = 2; //set SOC1 channel select to ADCINA2

AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5; //set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1

AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 5; //set SOC1 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.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();

   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 = 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;

  Voltage2[ConversionCount] = AdcResult.ADCRESULT1;

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

}

 

 

  • Hi Jerome,

    With TBPRD value around 100, and if you have prescalers set to 1, the frequency is 600kHz on with 60 MHz system clock. This means that interupt period is around 1.6us, and I suppose that the interrupt code can not complete in this time. Check this by seting one of the GPIO poins on entriy in the ISR and clearing it one exit from ISR

     

    Regards, Mitja

     

  • Is there another way to sample at this rate with the ADC if I'm not using the interrupts?

  • You could use the polling mode, which would eliminate the need for context save/restore, and additional gain can be achieved writing the code in assembly language instead in C, but the only proper thing to do if you need to sample and process data at such high frequencies is to switch to faster processor. The 2808 or the 28335 might be suitable alternatives

    Regards, Mitja

  • Thanks for your help, very helpful.

    Which characteristics should I look at, on the datasheets of the other MCUs, to know the maximum sampling rate of the ADC? To be sure the 2808 or the 28335 will be able to sample at the higher frequency I need?

  • I believe there are 2 issues at play; the maximum sampling rate of the ADC and the speed of the processor and its ability to manipulate the ADC results in a certain amount of time.

    The max sampling rate is the DS of each device under the electrical section.  For the 60MHz 2802x/3x parts this is 4.6MSPS.  For 2808 this is 6.25MSPS and for 28335 it is 12.5MSPS.

    The other aspect is the data manipulation in the ISR of the ADC data.  This can slow down what you can really achieve with the ADC if taking longer than when the ADC has the next set of ADC results ready.  This goes back to processor speed which is 60MHz for the 2802x/3x 100MHz for 2808 and 150MHz for 28335.

    There are other aspects of the HW that can help here; for example 28335 has DMA to transfer the ADC data in parallel with processing; 2803x has CLA which can read and process the ADC data in parallel with the processor.

     

    Best,

    Matthew