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.

[Resolved] C2000 F2802x Ping Pong/Continuous Sampling

Other Parts Discussed in Thread: CONTROLSUITE

Hello,

I'm currently working with the TMS320F2802x series MCUs (specifically the F28027 and F28020), and have been trying to implement a program that will continuously sample the ADC at its maximum rate, and store a large series of samples in memory. The default ADCSOC example included in TI's controlSUITE only seems to sample at around 100KSPS maximum if I change the TBPRD register such that the PWM runs as fast as it will go. If TBPRD is set any lower than 0x0080 the ISR seems to take too much time, and samples are not read.

I've been reading other forum posts with similar topics, and the solution of ping pong sampling often comes up, wherein one sample taken by the ADC triggers the next one, which triggers the next one, and so on. During this, the CPU is reading the values out of the ADCRESULT registers into a buffer. There was some old example code posted which illustrated this idea, I've attached it below. However, I'm unable to get this example code working. I was wondering if anyone here had working example code of this or any similar concepts.

5025.7217.ping-pong.c
void setup_adc()
{
	//enable bandgap, clocks, powerup etc.
	//set all SOCs to point to same channel

	//ADCINT 1 and 2 enabled
	AdcRegs.INTSEL1N2.bit.INT1E = 1;
	AdcRegs.INTSEL1N2.bit.INT2E = 1;
	//ADCINT 1 and 2 wait for confirmation
	AdcRegs.INTSEL1N2.bit.INT1CONT = 0;
	AdcRegs.INTSEL1N2.bit.INT2CONT = 0;
    //SOC 6 will trigger ADCINT1
	AdcRegs.INTSEL1N2.bit.INT1SEL = 6;
	//SOC 14 will trigger ADCINT2
	AdcRegs.INTSEL1N2.bit.INT2SEL = 14;

	//ADCINT2 will trigger first 8 SOCs
   	AdcRegs.ADCINTSOCSEL1.bit.SOC0 = 2;
   	AdcRegs.ADCINTSOCSEL1.bit.SOC1 = 2;
   	AdcRegs.ADCINTSOCSEL1.bit.SOC2 = 2;
   	AdcRegs.ADCINTSOCSEL1.bit.SOC3 = 2;
   	AdcRegs.ADCINTSOCSEL1.bit.SOC4 = 2;
   	AdcRegs.ADCINTSOCSEL1.bit.SOC5 = 2;
   	AdcRegs.ADCINTSOCSEL1.bit.SOC6 = 2;
   	AdcRegs.ADCINTSOCSEL1.bit.SOC7 = 2;
	
	//ADCINT1 will trigger second 8 SOCs
   	AdcRegs.ADCINTSOCSEL2.bit.SOC8 = 1;
   	AdcRegs.ADCINTSOCSEL2.bit.SOC9 = 1;
   	AdcRegs.ADCINTSOCSEL2.bit.SOC10 = 1;
   	AdcRegs.ADCINTSOCSEL2.bit.SOC11 = 1;
   	AdcRegs.ADCINTSOCSEL2.bit.SOC12 = 1;
   	AdcRegs.ADCINTSOCSEL2.bit.SOC13 = 1;
   	AdcRegs.ADCINTSOCSEL2.bit.SOC14 = 1;
   	AdcRegs.ADCINTSOCSEL2.bit.SOC15 = 1;
}

void take_samples(Uint16 size, Uint16* buffer)
{
	Uint16 index = 0;
	
	//enable adcint1 and adcint2 needed for ping-pong sampling
	AdcRegs.INTSEL1N2.bit.INT1E = 1;
	AdcRegs.INTSEL1N2.bit.INT2E = 1;
	
	AdcRegs.ADCSOCFRC1.all = 0x00FF; //software force SOC pending flag for first 8 SOCs 
	while(index < sample_size) {
		while (AdcRegs.ADCINTFLG.bit.ADCINT1 == 0){/*wait and do nothing*/}
		AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear ADCINT1
		
		//ADCINT1 was triggered by the end of SOC6.
		//Since they are done, read SOC0-SOC7 into buffer 
		//(this assumes SOC7 will be done converting by 
		//the time the code reaches it to put in buffer).
		//Also note that SOC6 triggered ADCINT1 which
		//then triggered SOC8-SOC15 to be pending.
		//These newly pending SOCs will begin converting 
		//immediately after SOC7 finishes.
		
		buffer[index++] = AdcResult.ADCRESULT0;
		buffer[index++] = AdcResult.ADCRESULT1;
		buffer[index++] = AdcResult.ADCRESULT2;
		buffer[index++] = AdcResult.ADCRESULT3;
		buffer[index++] = AdcResult.ADCRESULT4;
		buffer[index++] = AdcResult.ADCRESULT5;
		buffer[index++] = AdcResult.ADCRESULT6;
		buffer[index++] = AdcResult.ADCRESULT7;

		while (AdcRegs.ADCINTFLG.bit.ADCINT2 == 0){/*wait and do nothing*/}
		AdcRegs.ADCINTFLGCLR.bit.ADCINT2 = 1; //clear ADCINT2
		
		//ADCINT2 was triggered by the end of SOC14.
		//Since they are done, read SOC8-SOC15 into buffer 
		//(this assumes SOC15 will be done converting by 
		//the time the code reaches it to put in buffer).
		//Also note that SOC14 triggered ADCINT2 which
		//then triggered SOC0-SOC7 to be pending.
		//These newly pending SOCs will begin converting 
		//immediately after SOC15 finishes.
		
		buffer[index++] = AdcResult.ADCRESULT8;
		buffer[index++] = AdcResult.ADCRESULT9;
		buffer[index++] = AdcResult.ADCRESULT10;
		buffer[index++] = AdcResult.ADCRESULT11;
		buffer[index++] = AdcResult.ADCRESULT12;
		buffer[index++] = AdcResult.ADCRESULT13;
		buffer[index++] = AdcResult.ADCRESULT14;
		buffer[index++] = AdcResult.ADCRESULT15;
	}

	//disable adcint1 and adcint2 to STOP the ping-pong sampling
	AdcRegs.INTSEL1N2.bit.INT1E = 0;
	AdcRegs.INTSEL1N2.bit.INT2E = 0;
}

  • Hi Timothy,

    I don't see anything obviously wrong with the attached code. Can you elaborate a little bit on how the code fails?
  • Well then, it seems I've managed to get it sampling since I last posted. However, in these samples it seems that there are many artifacts spaced rather frequently. I don't know if this is an analog glitch on my side, or part of the first sample silicon errata. I've posted my full code below:

    //###########################################################################
    // $TI Release: F2802x Support Library v230 $
    // $Release Date: Fri May  8 07:43:05 CDT 2015 $
    // $Copyright: Copyright (C) 2008-2015 Texas Instruments Incorporated -
    //             http://www.ti.com/ ALL RIGHTS RESERVED $
    //###########################################################################
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    // Prototype statements for functions found within this file.
    void Adc_Config(void);
    void setup_adc(void);
    void take_samples(Uint16, Uint16*);
    
    // Global variables used in this example:
    uint16_t buffer[100];
    
    main()
    {
    // WARNING: Always ensure you call memcpy before running any functions from RAM
    // InitSysCtrl includes a call to a RAM based function and without a call to
    // memcpy first, the processor will go "into the weeds"
       #ifdef _FLASH
    	memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
       #endif
    
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the f2802x_SysCtrl.c file.
       InitSysCtrl();
    
    // Step 2. Initialize GPIO:
    // This example function is found in the f2802x_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 f2802x_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 f2802x_DefaultIsr.c.
    // This function is found in f2802x_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
    
       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.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
    
    //Function call to setup ADC for ping pong
       setup_adc();
    
    
    
       for(;;) //call sample function repeatedly every 50000us.
       {
    	take_samples(100,buffer);
    	DELAY_US(50000);
       }
    }
    
    
    
    
    void setup_adc()
    {
    	//enable bandgap, clocks, powerup etc.
    
    
    	EALLOW;
    	//set all SOCs to point channel 4
    	AdcRegs.ADCSOC0CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC2CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC3CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC4CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC5CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC6CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC7CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC8CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC9CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC10CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC11CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC12CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC13CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC14CTL.bit.CHSEL =4;
    	AdcRegs.ADCSOC15CTL.bit.CHSEL =4;
    
    	//Set minimum acquisition time of 7 cycles on each SOC
    	AdcRegs.ADCSOC0CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC1CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC2CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC3CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC4CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC5CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC6CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC7CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC8CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC9CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC10CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC11CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC12CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC13CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC14CTL.bit.ACQPS =6;
    	AdcRegs.ADCSOC15CTL.bit.ACQPS =6;
    
    	//ADCINT 1 and 2 enabled
    	AdcRegs.INTSEL1N2.bit.INT1E = 1;
    	AdcRegs.INTSEL1N2.bit.INT2E = 1;
    	//ADCINT 1 and 2 wait for confirmation
    	AdcRegs.INTSEL1N2.bit.INT1CONT = 0;
    	AdcRegs.INTSEL1N2.bit.INT2CONT = 0;
        //SOC 6 will trigger ADCINT1
    	AdcRegs.INTSEL1N2.bit.INT1SEL = 6;
    	//SOC 14 will trigger ADCINT2
    	AdcRegs.INTSEL1N2.bit.INT2SEL = 14;
    
    	//ADCINT2 will trigger first 8 SOCs
       	AdcRegs.ADCINTSOCSEL1.bit.SOC0 = 2;
       	AdcRegs.ADCINTSOCSEL1.bit.SOC1 = 2;
       	AdcRegs.ADCINTSOCSEL1.bit.SOC2 = 2;
       	AdcRegs.ADCINTSOCSEL1.bit.SOC3 = 2;
       	AdcRegs.ADCINTSOCSEL1.bit.SOC4 = 2;
       	AdcRegs.ADCINTSOCSEL1.bit.SOC5 = 2;
       	AdcRegs.ADCINTSOCSEL1.bit.SOC6 = 2;
       	AdcRegs.ADCINTSOCSEL1.bit.SOC7 = 2;
    
    	//ADCINT1 will trigger second 8 SOCs
       	AdcRegs.ADCINTSOCSEL2.bit.SOC8 = 1;
       	AdcRegs.ADCINTSOCSEL2.bit.SOC9 = 1;
       	AdcRegs.ADCINTSOCSEL2.bit.SOC10 = 1;
       	AdcRegs.ADCINTSOCSEL2.bit.SOC11 = 1;
       	AdcRegs.ADCINTSOCSEL2.bit.SOC12 = 1;
       	AdcRegs.ADCINTSOCSEL2.bit.SOC13 = 1;
       	AdcRegs.ADCINTSOCSEL2.bit.SOC14 = 1;
       	AdcRegs.ADCINTSOCSEL2.bit.SOC15 = 1;
       	EDIS;
    }
    
    
    void take_samples(Uint16 sample_size, Uint16* buffer)
    {
    	Uint16 index = 0;
    
    	//enable adcint1 and adcint2 needed for ping-pong sampling
    	AdcRegs.INTSEL1N2.bit.INT1E = 1;
    	AdcRegs.INTSEL1N2.bit.INT2E = 1;
    
    	AdcRegs.ADCSOCFRC1.all = 0x00FF; //software force SOC pending flag for first 8 SOCs
    	while(index < sample_size) {
    		while (AdcRegs.ADCINTFLG.bit.ADCINT1 == 0){/*wait and do nothing*/}
    		AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear ADCINT1
    
    		//ADCINT1 was triggered by the end of SOC6.
    		//Since they are done, read SOC0-SOC7 into buffer
    		//(this assumes SOC7 will be done converting by
    		//the time the code reaches it to put in buffer).
    		//Also note that SOC6 triggered ADCINT1 which
    		//then triggered SOC8-SOC15 to be pending.
    		//These newly pending SOCs will begin converting
    		//immediately after SOC7 finishes.
    
    		buffer[index++] = AdcResult.ADCRESULT0;
    		buffer[index++] = AdcResult.ADCRESULT1;
    		buffer[index++] = AdcResult.ADCRESULT2;
    		buffer[index++] = AdcResult.ADCRESULT3;
    		buffer[index++] = AdcResult.ADCRESULT4;
    		buffer[index++] = AdcResult.ADCRESULT5;
    		buffer[index++] = AdcResult.ADCRESULT6;
    		buffer[index++] = AdcResult.ADCRESULT7;
    
    		while (AdcRegs.ADCINTFLG.bit.ADCINT2 == 0){/*wait and do nothing*/}
    		AdcRegs.ADCINTFLGCLR.bit.ADCINT2 = 1; //clear ADCINT2
    
    		//ADCINT2 was triggered by the end of SOC14.
    		//Since they are done, read SOC8-SOC15 into buffer
    		//(this assumes SOC15 will be done converting by
    		//the time the code reaches it to put in buffer).
    		//Also note that SOC14 triggered ADCINT2 which
    		//then triggered SOC0-SOC7 to be pending.
    		//These newly pending SOCs will begin converting
    		//immediately after SOC15 finishes.
    
    		buffer[index++] = AdcResult.ADCRESULT8;
    		buffer[index++] = AdcResult.ADCRESULT9;
    		buffer[index++] = AdcResult.ADCRESULT10;
    		buffer[index++] = AdcResult.ADCRESULT11;
    		buffer[index++] = AdcResult.ADCRESULT12;
    		buffer[index++] = AdcResult.ADCRESULT13;
    		buffer[index++] = AdcResult.ADCRESULT14;
    		buffer[index++] = AdcResult.ADCRESULT15;
    	}
    
    	//disable adcint1 and adcint2 to STOP the ping-pong sampling
    	AdcRegs.INTSEL1N2.bit.INT1E = 0;
    	AdcRegs.INTSEL1N2.bit.INT2E = 0;
    }
    

    Also, it would seem that if I try and make my buffer much larger than 100, it writes off of the current page of memory. Would you have any advice on creating larger buffer spaces? Perhaps on the order of 1000 or more? I remember reading somewhere that the c2000 series can do flash pipe-lining. 

    Here is a picture of the glitches I'm seeing, there is a 150KHz sine wave present on the input of the ADC:

  • Hi,

    Missing below piece of code in setup_adc() function. Pls check it again at your end

    AdcRegs.ADCSOC1CTL.bit.CHSEL =4;

    regards

    Aditya

  • Doh! I feel very silly now! Thank you very much for that, it's sampling smoothly now. Now I just need a way to write a larger buffer, I'll start looking into that.
  • Good. :)
    Please close the thread if your problem resolved.

    Goodluck
    Aditya
  • Please let me know if there is working example of ping pong sampling.
    Tried to import the above source code to F28069...but it doesn't work,
    there is no data on the ADC input.... Let me know if there is anything to
    be added to the above source code to work on F28069.
  • Kummi said:
    Please let me know if there is working example of ping pong sampling.
    Tried to import the above source code to F28069...but it doesn't work,
    there is no data on the ADC input.... Let me know if there is anything to
    be added to the above source code to work on F28069.

    Hmm, well the code above was designed to work with the f2802x series of microcontrollers, not the f2806x. I can't really say how portable code is between the two, as that's not my area of expertise.

  • Hello Kummi,

    Please consider creating a new post if the discussion on this thread doesn't answer your question. You can provide the necessary information regarding your question in the new post and include a link to this post if you'd like.

    Elizabeth