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.

ADC calibration in DELFINO DUAL

Other Parts Discussed in Thread: CONTROLSUITE

Hello,

I download latest ControlSuite (3.3.1) and

I read code in "F2837xD_SysCtrl.c" V150

lines 66 ... 78

    //enable pull-ups on unbonded IOs as soon as possible to reduce power consumption.
    GPIO_EnableUnbondedIOPullups();

	CpuSysRegs.PCLKCR13.bit.ADC_A = 1;
	CpuSysRegs.PCLKCR13.bit.ADC_B = 1;
	CpuSysRegs.PCLKCR13.bit.ADC_C = 1;
	CpuSysRegs.PCLKCR13.bit.ADC_D = 1;

    //check if device is trimmed
    if(*((Uint16 *)0x5D1B6) == 0x0000){
        //device is not trimmed, apply static calibration values
        AnalogSubsysRegs.ANAREFTRIMA.all = 31709;
        AnalogSubsysRegs.ANAREFTRIMB.all = 31709;
        AnalogSubsysRegs.ANAREFTRIMC.all = 31709;
        AnalogSubsysRegs.ANAREFTRIMD.all = 31709;
    }

	CpuSysRegs.PCLKCR13.bit.ADC_A = 0;
	CpuSysRegs.PCLKCR13.bit.ADC_B = 0;
	CpuSysRegs.PCLKCR13.bit.ADC_C = 0;
	CpuSysRegs.PCLKCR13.bit.ADC_D = 0;
    EDIS;

    // Initialize the PLL control: PLLCR and CLKINDIV
    // F28_PLLCR and F28_CLKINDIV are defined in F2837xD_Examples.h
    // Note: The internal oscillator CANNOT be used as the PLL source if the
    // PLLSYSCLK is configured to frequencies above 194 MHz.
    InitSysPll(XTAL_OSC,IMULT_20,FMULT_1,PLLCLK_BY_2); 		//PLLSYSCLK = 20MHz(XTAL_OSC) * 20 (IMULT) * 1 (FMULT) /  2 (PLLCLK_BY_2)

    //Turn on all peripherals
	InitPeripheralClocks();

the code "check if device is NOT trimmed"

and fill ANAREFTRIMx regs with 31709 static value,

but the question is:

if the device is trimmed what value I have to fill in ANAREFTRIMx regs ??

  • Hi Mauro, if the device is trimmed, you do not need to load anything into ANAREFTRIMx regs, they will be automatically populated on boot.
  • I don't understand

    in adc samples

    code calls "AdcSetMode"

    for example in "adc_ppb_delay_cpu01" the code is ...

    //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 = 6; //set ADCCLK divider to /4
        AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);
    
    	//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;
    }

    if I open "F2837xD_Adc.c"

    the routine "AdcSetMode"

    calls some OTP routines,

    so it means that in Boot Rom this routines

    are not called automatically

    and the programmer has the charge to call

    this calibration routines in a right way

    /* 
    * Set the resolution and signalmode for a given ADC. This will ensure that
    * the correct trim is loaded. 
    */
    void AdcSetMode(Uint16 adc, Uint16 resolution, Uint16 signalmode)
    {
    	Uint16 adcOffsetTrimOTPIndex; //index into OTP table of ADC offset trims
    	Uint16 adcOffsetTrim; //temporary ADC offset trim
    	
    	//re-populate INL trim
    	CalAdcINL(adc);
    	
    	if(0xFFFF != *((Uint16*)GetAdcOffsetTrimOTP)){
    		//offset trim function is programmed into OTP, so call it
    
    		//calculate the index into OTP table of offset trims and call
    		//function to return the correct offset trim
    		adcOffsetTrimOTPIndex = 4*adc + 2*resolution + 1*signalmode;
    		adcOffsetTrim = (*GetAdcOffsetTrimOTP)(adcOffsetTrimOTPIndex);
    	}
    	else {
    		//offset trim function is not populated, so set offset trim to 0
    		adcOffsetTrim = 0;
    	}
    
    	//Apply the resolution and signalmode to the specified ADC.
    	//Also apply the offset trim and, if needed, linearity trim correction.
    	switch(adc){
    		case ADC_ADCA:
    			AdcaRegs.ADCCTL2.bit.RESOLUTION = resolution;
    			AdcaRegs.ADCCTL2.bit.SIGNALMODE = signalmode;
    			AdcaRegs.ADCOFFTRIM.all = adcOffsetTrim;
    			if(ADC_RESOLUTION_12BIT == resolution){
    
    				//12-bit linearity trim workaround
    				AdcaRegs.ADCINLTRIM1 &= 0xFFFF0000;
    				AdcaRegs.ADCINLTRIM2 &= 0xFFFF0000;
    				AdcaRegs.ADCINLTRIM4 &= 0xFFFF0000;
    				AdcaRegs.ADCINLTRIM5 &= 0xFFFF0000;
    			}
    		break;
    		case ADC_ADCB:
    			AdcbRegs.ADCCTL2.bit.RESOLUTION = resolution;
    			AdcbRegs.ADCCTL2.bit.SIGNALMODE = signalmode;
    			AdcbRegs.ADCOFFTRIM.all = adcOffsetTrim;
    			if(ADC_RESOLUTION_12BIT == resolution){
    
    				//12-bit linearity trim workaround
    				AdcbRegs.ADCINLTRIM1 &= 0xFFFF0000;
    				AdcbRegs.ADCINLTRIM2 &= 0xFFFF0000;
    				AdcbRegs.ADCINLTRIM4 &= 0xFFFF0000;
    				AdcbRegs.ADCINLTRIM5 &= 0xFFFF0000;
    			}
    		break;
    		case ADC_ADCC:
    			AdccRegs.ADCCTL2.bit.RESOLUTION = resolution;
    			AdccRegs.ADCCTL2.bit.SIGNALMODE = signalmode;
    			AdccRegs.ADCOFFTRIM.all = adcOffsetTrim;
    			if(ADC_RESOLUTION_12BIT == resolution){
    
    				//12-bit linearity trim workaround
    				AdccRegs.ADCINLTRIM1 &= 0xFFFF0000;
    				AdccRegs.ADCINLTRIM2 &= 0xFFFF0000;
    				AdccRegs.ADCINLTRIM4 &= 0xFFFF0000;
    				AdccRegs.ADCINLTRIM5 &= 0xFFFF0000;
    			}
    		break;
    		case ADC_ADCD:
    			AdcdRegs.ADCCTL2.bit.RESOLUTION = resolution;
    			AdcdRegs.ADCCTL2.bit.SIGNALMODE = signalmode;
    			AdcdRegs.ADCOFFTRIM.all = adcOffsetTrim;
    			if(ADC_RESOLUTION_12BIT == resolution){
    
    				//12-bit linearity trim workaround
    				AdcdRegs.ADCINLTRIM1 &= 0xFFFF0000;
    				AdcdRegs.ADCINLTRIM2 &= 0xFFFF0000;
    				AdcdRegs.ADCINLTRIM4 &= 0xFFFF0000;
    				AdcdRegs.ADCINLTRIM5 &= 0xFFFF0000;
    			}
    		break;
    	}
    }

    I'm a bit confused

  • Hi Mauro, some trims are dependent on the ADC mode you are using (i.e. 12b or 16b) but some are common regardless how the ADC is configured. ANAREFTRIMx is not dependent on the ADC mode so they can be populated at boot time. Some TMX samples do not have this enabled however, so we provide the code which allows you to statically trim the register in the case the dynamic (unique per device) trim are not present. As for the usage dependent trims such as INL and offset, the customer is responsible to load the proper trim after selecting the ADC mode.

    Does this answer your question or am I still missing the point?
    Regards,
    Joe
  • ok, it answer my question but I notice that CalAdcINL
    is NOT mode dependent, so why not move this in boot ?

    /* 
    * Loads INL trim values from OTP into the trim registers of the specified ADC.
    * Use only as part of AdcSetMode function, since linearity trim correction
    * is needed for some modes.
    */
    void CalAdcINL(Uint16 adc)
    {
    	switch(adc){
    		case ADC_ADCA:
    			if(0xFFFF != *((Uint16*)CalAdcaINL)){
    				//trim function is programmed into OTP, so call it
    				(*CalAdcaINL)();
    			}
    			else {
    				//do nothing, no INL trim function populated
    			}
    			break;
    		case ADC_ADCB:
    			if(0xFFFF != *((Uint16*)CalAdcbINL)){
    				//trim function is programmed into OTP, so call it
    				(*CalAdcbINL)();
    			}
    			else {
    				//do nothing, no INL trim function populated
    			}
    			break;
    		case ADC_ADCC:
    			if(0xFFFF != *((Uint16*)CalAdccINL)){
    				//trim function is programmed into OTP, so call it
    				(*CalAdccINL)();
    			}
    			else {
    				//do nothing, no INL trim function populated
    			}
    			break;
    		case ADC_ADCD:
    			if(0xFFFF != *((Uint16*)CalAdcdINL)){
    				//trim function is programmed into OTP, so call it
    				(*CalAdcdINL)();
    			}
    			else {
    				//do nothing, no INL trim function populated
    			}
    			break;
    	}
    }

  • It is true that the INL datasheet performance can be met with a single INL trim regardless of which mode the ADC is in, however we found that the 12b INL could be further improved by zeroing out some bits in the trim register. That being the case, we decided to treat this as a mode dependent trim and added it to the AdcSetMode procedure so customers could get the best performance available.
  • another question:

    in "F2837xD_Examples.h" V150 lines 300...317

    is defined "Device_cal()" as you see below

    //----------------------------------------------------------------------------
    
    // The following pointer to a function call calibrates the ADC reference, 
    // DAC offset, and internal oscillators
    #define Device_cal (void   (*)(void))0x070282
    
    // The following pointers to functions calibrate the ADC linearity.  Use this
    // in the AdcSetMode(...) function only
    #define CalAdcaINL (void   (*)(void))0x0703B4
    #define CalAdcbINL (void   (*)(void))0x0703B2
    #define CalAdccINL (void   (*)(void))0x0703B0
    #define CalAdcdINL (void   (*)(void))0x0703AE
    
    // The following pointer to a function call looks up the ADC offset trim for a 
    // given condition. Use this in the AdcSetMode(...) function only.   
    #define GetAdcOffsetTrimOTP (Uint16 (*)(Uint16 OTPoffset))0x0703AC
    
    //---------------------------------------------------------------------------

    When I use 28069 processor I had to call "Device_cal()" in order to load calibration values.

    In delfino dual ControlSuite sample I don't see calling of "Device_cal".

    when you said me "calibration routines are called automatically on Boot Loading"

    you mean "Device_cal" ?

    thankyou

  • Sorry for the delay. Yes I was referring to Device_cal. It can be run manually, but will automatically be run by the BROM if a specific key is present. All TMS material will have this key, but most TMX material will not. I do not recommend manually running Device_cal on TMX material.
  • you are telling about key in 0x5D1B6 address ?
  • No, I was referring to a key at 0x70270, but even if the key is present I do not recommend manually running Device_cal on TMX material.
  • so, why controlsuite check 0x5d1b6 address ?

    //enable pull-ups on unbonded IOs as soon as possible to reduce power consumption.
    
    GPIO_EnableUnbondedIOPullups();
    
    
     
    CpuSysRegs.PCLKCR13.bit.ADC_A = 1;
    
    CpuSysRegs.PCLKCR13.bit.ADC_B = 1;
    
    CpuSysRegs.PCLKCR13.bit.ADC_C = 1;
    
    CpuSysRegs.PCLKCR13.bit.ADC_D = 1;
    
    
     
    //check if device is trimmed
    
    if(*((Uint16 *)0x5D1B6) == 0x0000){
    
        //device is not trimmed, apply static calibration values
    
        AnalogSubsysRegs.ANAREFTRIMA.all = 31709;
    
        AnalogSubsysRegs.ANAREFTRIMB.all = 31709;
    
        AnalogSubsysRegs.ANAREFTRIMC.all = 31709;
    
        AnalogSubsysRegs.ANAREFTRIMD.all = 31709;
    
    }
    
    
     
    CpuSysRegs.PCLKCR13.bit.ADC_A = 0;
    
    CpuSysRegs.PCLKCR13.bit.ADC_B = 0;
    
    CpuSysRegs.PCLKCR13.bit.ADC_C = 0;
    
    CpuSysRegs.PCLKCR13.bit.ADC_D = 0;
    
    EDIS;
    
    
     
    // Initialize the PLL control: PLLCR and CLKINDIV
    
    // F28_PLLCR and F28_CLKINDIV are defined in F2837xD_Examples.h
    
    // Note: The internal oscillator CANNOT be used as the PLL source if the
    
    // PLLSYSCLK is configured to frequencies above 194 MHz.
    
    InitSysPll(XTAL_OSC,IMULT_20,FMULT_1,PLLCLK_BY_2);      //PLLSYSCLK = 20MHz(XTAL_OSC) * 20 (IMULT) * 1 (FMULT) /  2 (PLLCLK_BY_2)
    
    
     
    //Turn on all peripherals
    
    InitPeripheralClocks();
    

  • 0x5D1B6 is an analog sub-system trim register. The trim values are store in nonvolatile memory in the factory, but the BROM will copy them to the appropriate trim register if the keys are present. The code above is a simple way to make the code future proof. In other words, it will work now, with devices that do not automatically populate trims by putting in a common trim value for all devices, and it will work in the future when device trims are automatically populated and you can take advantage of the better performance offered with custom trims without modifying your code.
  • ok, thank you,

    I think I have no further questions

  • Hello. I have questions on your Q&A. I am really beginner in this material.

    What does it mean by " Device is trimmed "? what is 0x5D1B6?
    What does it mean by " unbonded IOs " at " enable pull-ups on unbonded IOs as soon as possible to reduce power consumption

    Thanks
  • Hi Chunki,

    Please create a new thread for any new questions.  (especially if they are not exactly related to the original thread).

    This will ensure that you get the best response.

    ===

    'Trimmed' means that the device was calibrated during production.  After this calibration process, the calibration values found are stored in memory so that the device can perform optimally outside of the factory.


    Thank you,
    Brett