3.4 Code Example

Gain Error Compensation Code Example for dsPIC33AK Device contains all the necessary steps and information to perform gain error compensation for one ADC instance. In this example, channel 0 of ADC 1 is shown, but any channel can be used.

Gain Error Compensation Code Example for dsPIC33AK Device

#include <xc.h>

int32_t result = 0;  // ADC conversion result output.
int32_t coefficient; // Gain compensation coefficient.

void OscillatorInitialization(); // Oscillator initialization procedure.

int main(){

   OscillatorInitialization();  // Initialize the oscillator. 
   AD1CONbits.ON = 1; // Enable ADC.
   while(AD1CONbits.ADRDY == 0); // Wait when ADC will be ready/calibrated
        
   ////////////////////////////////////////////////////////////////////
   // GET A COEFFICIENT FOR THE GAIN ERROR COMPENSATION
   ////////////////////////////////////////////////////////////////////
   AD1CH0CONbits.MODE = 3; // Select oversampling mode
   AD1CH0CONbits.ACCNUM = 3; // 256 conversions
   AD1CH0CONbits.TRG1SRC = 1; // Software trigger will start a conversion
   AD1CH0CONbits.TRG2SRC = 2; // Back-to-back conversions
   AD1CH0CONbits.PINSEL = 14; // Select the AN14 input which is connected to 15/16 of AVDD
   AD1CH0CONbits.SAMC = 3; // Sampling time (6.5 TADs = 81nS @ 40MHZ ADC clock)
   AD1SWTRGbits.CH0TRG = 1; // Average 256 results of the reference voltage
   while(AD1STATbits.CH0RDY == 0); // Wait when the result is ready

   // 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 = (int32_t)(3840.0*16.0*(1<<18)/AD1CH0DATA); 

   ////////////////////////////////////////////////////////////////////
   // CONVERT AND COMPENSATE THE GAIN ERROR
   ////////////////////////////////////////////////////////////////////
   AD1CH0CON = 0; // Clean channel register for new settings
   AD1CH0CONbits.MODE = 0; // Select single conversion mode
   AD1CH0CONbits.TRG1SRC = 1; // Software trigger will start a conversion
   AD1CH0CONbits.PINSEL = 7; // Select the AN7 input for conversions
   AD1CH0CONbits.SAMC = 3; // Sampling time (6.5 TADs = 81nS @ 40MHZ ADC clock)

   // Trigger channel #1 in software and wait for the result
   while(1){
      AD1SWTRGbits.CH0TRG = 1; // Trigger channel # 1
      while(AD1STATbits.CH1RDY == 0); // Wait for a conversion ready flag
      // Read result. It will clear the conversion ready flag
      // The correction coefficient is in fixed-point format (18 bits before point)
      result = (coefficient*AD1CH0DATA)>>18;
      }
   return 1;
}

void OscillatorInitialization(){
   // Clock generator 6 should provide 320 MHZ to the ADCs
   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 = 640MHz
   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);
}