17.5.1 Gain Error Calibration

Gain Error Calibration Example

#include <xc.h>

// The channel output.
long result = 0;
// Gain compensation coefficient.
long coefficient;
long result1div16;
long result15div16;

// Oscillator initialization procedure.
void OscillatorInitialization();
int main(){

    // Initialize the oscillator.
    // Clock generator 6 should provide 320MHZ to the ADCs.
    OscillatorInitialization();

    // Enable ADC.
    AD1CONbits.ON = 1;
    // Wait when ADC will be ready/calibrated.
    while(AD1CONbits.ADRDY == 0);
    ////////////////////////////////////////////////////////////////////
    // GET A COEFFICIENT FOR THE GAIN ERROR COMPENSATION
    ////////////////////////////////////////////////////////////////////
    // Select oversampling mode.
    AD1CH1CON1bits.MODE = 3;
    // 256 conversions
    AD1CH1CON1bits.ACCNUM = 3;
    // Software trigger will start a conversion.
    AD1CH1CON1bits.TRG1SRC = 1;
    // Back-to-back conversions
    AD1CH1CON1bits.TRG2SRC = 2;
    // Select the AN8 input which is connected to 1/16 of AVDD
    IBIASCONbits.VREFSEL = 0;
    AD1CH1CON1bits.PINSEL = 8;
    // Select signal sampling time 
    AD1CH1CON1bits.SAMC = 7;
    // Flag when all conversions done
    AD1CH1CON1bits.IRQSEL = 1;
    // Average 256 results of the reference voltage
    AD1SWTRGbits.CH1TRG = 1;
    // Wait when the result is ready
    while(AD1STATbits.CH1RDY == 0);
    result1div16 = AD1CH1DATA;
    // Select the AN8 input which is connected to 15/16 of AVDD
    IBIASCONbits.VREFSEL = 1;
    AD1CH1CON1bits.PINSEL = 8;
    // Average 256 results of the reference voltage
    AD1SWTRGbits.CH1TRG = 1;
    // Wait when the result is ready
    while(AD1STATbits.CH1RDY == 0);
    result15div16 = AD1CH1DATA;
    
    // Oversampling result is 16 Bit (has additional 4 bits).
    // Calculate the gain compensation coefficient.
    // The coefficient is in fixed-point format (18 bits before point).
    coefficient = (long)(3584.0*16.0*(1<<18)/(result15div16-result1div16));

    ////////////////////////////////////////////////////////////////////
    // CONVERT AND COMPENSATE THE GAIN ERROR
    ////////////////////////////////////////////////////////////////////
    // Clean channel register for new settings.
    AD1CH1CON1 = 0;
    // Select single conversion mode.
    AD1CH1CON1bits.MODE = 0;
    // Software trigger will start a conversion.
    AD1CH1CON1bits.TRG1SRC = 1;
    // Select the AN7 input for conversions
    AD1CH1CON1bits.PINSEL = 7;
    // Select signal sampling time
    AD1CH1CON1bits.SAMC = 3;
    // Trigger channel #1 in software and wait for the result.
    while(1){
        // Trigger channel # 1.
        AD1SWTRGbits.CH1TRG = 1;
        // Wait for a conversion ready flag.
        while(AD1STATbits.CH1RDY == 0);
        // Read result. It will clear the conversion ready flag.
        // The gain error correction coefficient is in fixed-point format (18 bits before point).
        result = (coefficient*AD1CH1DATA)>>18;
        _LATC3 = 0; 
//            printf("\nCompensated Gain Error:%08x \r\n\n", result);
    }
    return 1;
}
void OscillatorInitialization(){
    PLL1CONbits.ON = 1;
    OSCCTRLbits.PLL1EN = 1;
    while(OSCCTRLbits.PLL1RDY == 0);
    PLL1CONbits.FSCMEN = 0; // disable clock fail monitor
    VCO1DIVbits.INTDIV = 1; // 1:2 = 320MHz
    PLL1DIVbits.PLLFBDIV = 80; // VCO = 640 MHz
    PLL1DIVbits.PLLPRE = 1;
    PLL1DIVbits.POSTDIV1 = 4;
    PLL1DIVbits.POSTDIV2 = 1;
    PLL1CONbits.DIVSWEN = 1;
    while(PLL1CONbits.DIVSWEN == 1);
    PLL1CONbits.NOSC = 1; // FRC
    PLL1CONbits.OSWEN = 1;
    while(PLL1CONbits.OSWEN == 1);
    PLL1CONbits.FOUTSWEN = 1;
    while(PLL1CONbits.FOUTSWEN == 1);
    PLL1CONbits.PLLSWEN = 1;
    while(PLL1CONbits.PLLSWEN == 1);
    while(PLL1CONbits.CLKRDY == 0);
    CLK1CONbits.NOSC = 5; // PLL1
    CLK1CONbits.OSWEN = 1;
    while(CLK1CONbits.OSWEN == 1);
    while(CLK1CONbits.CLKRDY == 0);
    // ADC high speed clock (Generator 6), should be 320 MHz for 80MHz operation
    CLK6CONbits.ON = 1;
    CLK6CONbits.NOSC = 7; // PLL1 VCO divider
    CLK6CONbits.OSWEN = 1;
    while(CLK6CONbits.OSWEN == 1);
    while(CLK6CONbits.CLKRDY == 0);
}