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.

F28379D 16 bit differential mode test



Hi Champs,

When my customer used 16 bit ADC differential mode and ADCRESULT maximum difference is around 30 count when they use ref voltage to be input. For example, declare a array which is 100 and get the max/min difference. Their experimental result is around 30 count. However, ENOB is 14.1 bit. This means our result variation should be less 2 bit which is 4 count. If my understanding is wrong, please let me know. They wants to know how to reduce the ADC result variation.

i also did the test on F28379D launchPad and config ADCA to be 16 bit differential mode. I removed JP1.2.3 to enable isolation. I apply 3.3v by using external power supply and use battery(1.5v) to be ADC input. i use adc_ppb_delay_cpu01 to be test code and AdcSetMode to config 16 bit. About my code, please see the attachment. What i get the best ADCRESULT variation is 9 count. but it still didn't meet the SPEC. Could you please tell me what is the test condition and how can we improve 16 bit differential ADC performance? Thanks for your reply in advance.

//###########################################################################
// FILE:   adc_ppb_delay_cpu01.c
// TITLE:  Post-Processing delay capture for F2837xD.
//
//! \addtogroup cpu01_example_list
//! <h1> ADC PPB Delay Capture (adc_ppb_delay)</h1>
//!
//! This example demonstrates delay capture using the post-processing block.
//!
//! Two asynchronous ADC triggers are setup:\n
//!  - ePWM1, with period 2048, triggering SOC0 to convert on pin A0\n
//!  - ePWM1, with period 9999, triggering SOC1 to convert on pin A1\n
//!
//! Each conversion generates an ISR at the end of the conversion.  In the
//! ISR for SOC0, a conversion counter is incremented and the PPB is checked
//! to determine if the sample was delayed.\n
//!
//! After the program runs, the memory will contain:\n
//! - \b conversion \b: the sequence of conversions using SOC0 that were delayed
//! - \b delay \b: the corresponding delay of each of the delayed conversions
//!
//
//###########################################################################
// $TI Release: F2837xD Support Library v180 $
// $Release Date: Fri Nov  6 16:19:46 CST 2015 $
// $Copyright: Copyright (C) 2013-2015 Texas Instruments Incorporated -
//             http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################

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

void ConfigureADC(void);
void ConfigureEPWM(void);
void SetupADCEpwm(Uint16 channel1, Uint16 channel2);
interrupt void adca1_isr(void);
interrupt void adca2_isr(void);

#define DELAY_BUFFER_SIZE 100//30
Uint32 conversion_count;
Uint32 conversion[DELAY_BUFFER_SIZE];
Uint16 delay[DELAY_BUFFER_SIZE] = {0};
Uint16 adcresult[DELAY_BUFFER_SIZE]; //Lisa
Uint16 adcresult1[DELAY_BUFFER_SIZE]; //Lisa
volatile Uint16 delay_index;
Uint16 isra1_cnt = 0; // Lisa
Uint16 isra2_cnt = 0; // Lisa
#define LISA 1

void main(void)
{
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xD_SysCtrl.c file.
    InitSysCtrl();

// Step 2. Initialize GPIO:
// This example function is found in the F2837xD_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 F2837xD_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 F2837xD_DefaultIsr.c.
// This function is found in F2837xD_PieVect.c.
    InitPieVectTable();

//Map ISR functions
    EALLOW;
    PieVectTable.ADCA1_INT = &adca1_isr; //function for ADCA interrupt 1
    PieVectTable.ADCA2_INT = &adca2_isr; //function for ADCA interrupt 2
    EDIS;


//Configure the ADC and power it up
    ConfigureADC();

//Configure ePWM1 and ePWM2 with asynchronous periods
    ConfigureEPWM();

//Setup the ADC for ePWM triggered conversions on channel 0 and 1
    SetupADCEpwm(0,1);

//Setup the post-processing block to be associated with SOC0
#if LISA
    AdcaRegs.ADCPPB1CONFIG.bit.CONFIG = 1;
#else
    AdcaRegs.ADCPPB1CONFIG.bit.CONFIG = 0;
#endif
//Enable global Interrupts and higher priority real-time debug events:
    IER |= M_INT1; //Enable group 1 interrupts
    IER |= M_INT10; //Enable group 10 interrupts
    EINT;  // Enable Global interrupt INTM
    ERTM;  // Enable Global realtime interrupt DBGM

//enable PIE interrupt
    PieCtrlRegs.PIEIER1.bit.INTx1  = 1;
    PieCtrlRegs.PIEIER10.bit.INTx2 = 1;

//initialize program variables
    conversion_count = 0;
    for(delay_index = 0; delay_index < DELAY_BUFFER_SIZE; delay_index++)
    {
    	delay[delay_index] = 0;
    	conversion[delay_index] = 0;
    }

//Start ePWMs
    EALLOW;
    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    EPwm1Regs.ETSEL.bit.SOCAEN = 1; //enable SOCA
    EPwm1Regs.TBCTL.bit.CTRMODE = 0; //unfreeze, and enter up count mode
    EPwm2Regs.ETSEL.bit.SOCAEN = 1; //enable SOCA
    EPwm2Regs.TBCTL.bit.CTRMODE = 0; //unfreeze, and enter up count mode

    do
    {
        delay_index = 0;

    	//wait for list of delayed conversions to fill via interrupts
    	while(DELAY_BUFFER_SIZE > delay_index){}

    	//software breakpoint
    	asm("   ESTOP0");

    	//conversion[] will show which conversions were delayed
    	//delay[] will show how long each conversion was delayed
    	//conversion_count will show total number of conversions
    	//conversion_count - DELAY_BUFFER_SIZE is the number of samples
    	//    that started immediately without any delay
    }while(1);
}

//Write ADC configurations and power up the ADC for both ADC A and ADC B
void ConfigureADC(void)
{
	EALLOW;

	//write configurations
	AdcaRegs.ADCCTL2.bit.PRESCALE = 10;//Lisa // 6; //set ADCCLK divider to /4

#if LISA
	// set ADC to 16 bit/ differential mode
	    AdcSetMode(ADC_ADCA,ADC_RESOLUTION_16BIT,ADC_SIGNALMODE_DIFFERENTIAL);
#else
    AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);
#endif
	//Set pulse positions to late
	AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1;

	//power up the ADC
	AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1;

	//delay for 1ms to allow ADC time to power up
	DELAY_US(1000);

	EDIS;
}

void ConfigureEPWM(void)
{
	//setup PWM1 and PWM2 with asynchronous periods

	EALLOW;
	// Assumes ePWM clock is already enabled
	EPwm1Regs.ETSEL.bit.SOCAEN	= 0;	        // Disable SOC on A group
	EPwm1Regs.ETSEL.bit.SOCASEL	= 4;	        // Select SOC on up-count when TBCTR=CMPA
	EPwm1Regs.ETPS.bit.SOCAPRD = 1;		        // Generate pulse on 1st event
	EPwm1Regs.CMPA.bit.CMPA = 0x0400;           // Set compare A value to 1024 counts
	EPwm1Regs.TBPRD = 0x0800;			        // Set period to 2048 counts
	EPwm1Regs.TBCTL.bit.CTRMODE = 3;            // freeze counter

	// Assumes ePWM clock is already enabled
	EPwm2Regs.ETSEL.bit.SOCAEN	= 0;	        // Disable SOC on A group
	EPwm2Regs.ETSEL.bit.SOCASEL	= 4;	        // Select SOC on up-count
	EPwm2Regs.ETPS.bit.SOCAPRD = 1;		        // Generate pulse on 1st event
	EPwm2Regs.CMPA.bit.CMPA = 0x0400;           // Set compare A value to 1024 counts
	EPwm2Regs.TBPRD = 9999;//4096; //9999;			            // Set period to 9999 counts
	EPwm2Regs.TBCTL.bit.CTRMODE = 3;            // freeze counter
	EDIS;
}

void SetupADCEpwm(Uint16 channel1, Uint16 channel2)
{
	Uint16 acqps;

	//determine minimum acquisition window (in SYSCLKS) based on resolution
	if(ADC_RESOLUTION_12BIT == AdcaRegs.ADCCTL2.bit.RESOLUTION){
		acqps = 14; //75ns
	}
	else { //resolution is 16-bit
		acqps = 63;//126;// //320ns
	}

	//Select the channels to convert and setup the end of conversion flag
	    //ADCA
#if LISA
		EALLOW;
		    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0;//0;  //SOC0 will convert pin A0
		    AdcaRegs.ADCSOC0CTL.bit.ACQPS = acqps; //sample window is 100 SYSCLK cycles
		    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; //trigger on ePWM1 SOCA/C
		    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; //end of SOC0 will set INT1 flag
		    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1;   //enable INT1 flag

#else

	    EALLOW;
	    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0;  //SOC0 will convert pin A0
	    AdcaRegs.ADCSOC1CTL.bit.CHSEL = 1;  //SOC1 will convert pin A1
	    AdcaRegs.ADCSOC1CTL.bit.ACQPS = acqps; //sample window is 100 SYSCLK cycles
	    AdcaRegs.ADCSOC0CTL.bit.ACQPS = acqps; //sample window is 100 SYSCLK cycles
	    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; //trigger on ePWM1 SOCA/C
	    AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 7; //trigger on ePWM2 SOCA/C
	    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; //end of SOC0 will set INT1 flag
	    AdcaRegs.ADCINTSEL1N2.bit.INT2SEL = 1; //end of SOC1 will set INT1 flag
	    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1;   //enable INT1 flag
	    AdcaRegs.ADCINTSEL1N2.bit.INT2E = 1;   //enable INT2 flag
#endif
}

interrupt void adca1_isr(void)
{
	/*Lisa
	isra1_cnt ++;
	Uint16 a ;
	if (isra1_cnt == 4)
		a = AdcaRegs.ADCPPB1STAMP.bit.DLYSTAMP;
	/*Lisa*/
 if(conversion_count == 100)
	 conversion_count = 0;
	//DLYSTAMP will read 2 if the sample was not delayed
	if(2 < AdcaRegs.ADCPPB1STAMP.bit.DLYSTAMP){
		//if DLYSTAMP > 2, then the sample was delayed by (DLYSTAMP - 2) cycles (SYSCLK)
		conversion[delay_index] = conversion_count;
		delay[delay_index] = AdcaRegs.ADCPPB1STAMP.bit.DLYSTAMP - 2; //save sample delay
		delay_index++;

		//corrective action(s) for delayed sample can occur here
		//...
	}

	//read ADC sample here
	//...
	adcresult[conversion_count] = AdcaResultRegs.ADCRESULT0; // read SOC0,Lisa

	conversion_count++;

	AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear INT1 flag
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

interrupt void adca2_isr(void)
{
	isra2_cnt++;
	//read ADC sample
	//...
	adcresult1[delay_index] = AdcaResultRegs.ADCRESULT1; //read SOC1,Lisa

	AdcaRegs.ADCINTFLGCLR.bit.ADCINT2 = 1; //clear INT1 flag
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP10;
}

Test condition

  

  • Hello Lisa,

     

    To get the best possible performance and repeatability on the F2837D ADC in 16-bit differential mode, it is recommended to have a very stable voltage reference that is typically implemented with a fixed reference chip (REFxxx series) buffered with an opamp (OPAxxx series). Both the M and P differential inputs need to be buffered as well for impedance matching. The differential inputs also have to be routed such that they do not cross signal paths that are currently active (e.g. GPIOs that are actively switching during sampling).  Series R, C and ACQPS requirements have to be met as well.  Please refer to a separate discussion on this thread: https://e2e.ti.com/support/microcontrollers/c2000/f/171/p/542665/1999388#1999388 .

     

    Thanks for confirming this on the Launchpad setup as well. I believe the version you have has the buffered reference circuit in place but not the buffers on the differential M and P channels.  Just curious on your setup how you are generating the M and P signals from the 1.5V battery.  Is the +1.5v fed to both the M and P differential inputs?  What is the VREF voltage set to? Please note that there is also a spec for input common mode where M input + N input div by 2 should be within VREF/2 +/- 50mv to satisfy the differential input requirement.  It is also recommended to connect the signal (in this case the wires from the battery) via coax cable through SMA connectors to ensure signal shielding.

     

    Please let me know if there is anything else on this topic I can help you with.

     

    Regards,

    Joseph

  • Joseph Casuga said:

    Hello Lisa,

     

    To get the best possible performance and repeatability on the F2837D ADC in 16-bit differential mode, it is recommended to have a very stable voltage reference that is typically implemented with a fixed reference chip (REFxxx series) buffered with an opamp (OPAxxx series). Both the M and P differential inputs need to be buffered as well for impedance matching. The differential inputs also have to be routed such that they do not cross signal paths that are currently active (e.g. GPIOs that are actively switching during sampling).  Series R, C and ACQPS requirements have to be met as well.  Please refer to a separate discussion on this thread: https://e2e.ti.com/support/microcontrollers/c2000/f/171/p/542665/1999388#1999388 .

     

    Thanks for confirming this on the Launchpad setup as well. I believe the version you have has the buffered reference circuit in place but not the buffers on the differential M and P channels.  Just curious on your setup how you are generating the M and P signals from the 1.5V battery.  Is the +1.5v fed to both the M and P differential inputs? 

    [Lisa]: yes. i connect the battery positive to ADCINxP and negative output to ADCINxN.

    What is the VREF voltage set to?

    [Lisa]: Vref = 3.0v

    Please note that there is also a spec for input common mode where M input + N input div by 2 should be within VREF/2 +/- 50mv to satisfy the differential input requirement.  It is also recommended to connect the signal (in this case the wires from the battery) via coax cable through SMA connectors to ensure signal shielding.

     

     

    Please let me know if there is anything else on this topic I can help you with.

    [Lisa]: an i sent you seperate mail to discuss more circuit detai ? thanks.

     

    Regards,

    Joseph

    Hi Joseph,