Post Go back to editing

ADuC7061 problems with measurement results

I have problems with the ADC0 measurement results when switching inputs AIN0_AIN1 and AIN2_AIN3. When switching, the difference in measurements is up to 0.25%. This is 100 times more than it should be.

Parents
  • When the AIN0_AIN1 pins are enabled, the values should be = 200/300 * 0x7FFFFF, and on the AIN2_AIN3 pins = 100/300 * 0x7FFFFF. That is, exactly 2 times less. But this is not happening. Error in 0.25%

  • Can you measure the voltage reference used if your are measuring the expected value? Can you also try using an external reference?

  • Primary Channel:

    External reference inputs (VREF+, VREF−) selected.

    Continuous conversion mode, ADCCLK = 4 MHz.

    ADC0/ADC1 (differential mode) or  ADC2/ADC3 (differential mode).

    Gain=1

    ADC filter: CHOPEN=1, RAVG2=1, NOTCH2=1,SF=9, AF=63

    Excitation current = 600 μA

    Measurements for ADC0/ADC1 and short ADC2/ADC3: Data0 = 2790219,  Data1 = -1781.

    Measurements for ADC2/ADC3 and short ADC0/ADC1: Data0 = -1834,  Data1 = -2792113.

    That is, the difference in the measurements of the same resistor is 1894 units. For other similar channels, this value varies from 4000 to -700. The voltage values in the nodes do not change.

  • Can you configure ADCs to use the internal reference, then check the ADC measurements?

    Just to clarify are using 2's complement or unipolar for the ADC output and is the auxiliary channel ADC configured similarly to the primary channel ADC?

  • This is the same Primary ADC. The same measured resistance. Difference in differential inputs: AIN0/AIN1 or AIN2/AIN3.

  • I tried to replicate the ADC config you sent and the same setup below.

    I checked the ADC reading using different AIN pins and ADC channels.

    Primary ADC - ADC0/ADC1 Primary ADC - ADC2/ADC3 Auxiliary ADC - ADC2/ADC3 Auxiliary ADC - ADC4/ADC5 Auxiliary ADC - ADC6/ADC7 Auxiliary ADC - ADC8/ADC9
    2798965 2799070 2800969 2801402 2801083 2801352
    2799187 2799046 2801151 2801133 2801125 2801178
    2799025 2799185 2800804 2801449 2801196 2801338
    2799143 2799082 2800852 2801345 2800951 2801329
    2799234 2799211 2800930 2801296 2801210 2801219
    2799144 2798936 2800844 2801184 2800879 2801261
    2799195 2798974 2801026 2801096 2800959 2801308
    2799030 2799154 2800902 2800958 2800978 2801302
    2799044 2799059 2801203 2801478 2801025 2801346
    2799151 2799248 2801087 2801092 2801034 2801134
    2799126 2799200 2801166 2801196 2801258 2801306
    2798950 2799219 2801175 2801357 2801023 2800949
    2799181 2798892 2801161 2801207 2801064 2801099
    2798953 2799064 2800804 2801075 2801145 2801356
    2799048 2799138 2800940 2801387 2801117 2801282
    2799212 2799027 2801136 2801278 2801049 2801269
    2798847 2799008 2800950 2801422 2801176 2801067
    2798939 2798958 2801133 2801304 2801004 2801269
    2799159 2798844 2800904 2801421 2801145 2801332
    2799200 2799091 2801032 2801274 2800967 2801286

    The results from the primary ADC for both AIN0_AIN1 and AIN2_AIN3 configuration show no significant difference.  The same when comparing the results of the different pin inputs of the auxiliary ADC. Comparing the results from the primary and auxiliary ADC, the difference between ADC output increases.

    There is some difference in the signal chain between the primary and auxiliary channels. There is also some difference between the primary and auxiliary ADC offset error min-max values. These contribute to the difference in ADC channels.

  • My results on 32 chips are 10..100 times worse. Why?

  • The difference in measurement you have mentioned, up to 0.25%, is it when comparing the expected measurement to the actual measurement or the measurement from the primary ADC to the auxiliary ADC?

  • 2 Shemes jof measurement.

    Soft:

    //*****************************************************************************
    // ADuC7061
    // Keil mVision V5.14
    // ADC convert
    //*****************************************************************************

    #include "ADUC706x.h"
    #include "stdio.h"


    uint16_t countCycle = 0;    
     int32_t Data_ADC0  = 0;    
     int32_t Data_ADC1  = 0;    
     int32_t Data_ADC2  = 0;    
     int32_t Data_ADC3  = 0;    
     int32_t dData0, dData1, dData2, dData3;

    //*****************************************************************************
    // Main
    //*****************************************************************************
    int main(void)
    {
        
    // Internal Crystal Selection
        POWKEY1 = 0x1;
        POWCON0 = CLK_10240_KHZ | CORE_POWER_ON | PERIPH_POWER_ON | PLL_POWER_ON;
        POWKEY2 = 0xF4;
        
    // PIN config
        GP0PAR = 0xFF;      // GPPD[7..0] = 1, pull-up resistor is disabled
        
        GP0KEY1 = 0x07;
        GP0CON1 = 0x01;     // To enable P0.0, P0.1, P0.2 and P0.3 functions as ADC inputs
        GP0KEY2 = 0x13;

    // Config ADC
        // ADC idle mode, ADCCLK = 131 kHz
        ADCMDE  = ADCMDE_IDLE | ADCCLKSEL_131KHZ;   
        // Primary ADC Gain=1, ext.ref (VREF+,VREF-), ADC0/ADC1
        ADC0CON = ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1;  
        // Primary ADC Gain=1, int.ref,  ADC2/ADC3
        // ADC0CON = ADC0CON_REF_INT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1;  

        // Auxiliary ADC Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
        ADC1CON = ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;  
        // Auxiliary ADC Gain=1, int.ref,  ADC2/ADC3
        // ADC1CON = ADC1CON_REF_INT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;  
        
        // ADC Filter Register
        // CHOPEN=1, RAVG2=1, NOTCH2=1, Data_Rate=16.128Hz, Settling_Time=124ms, 50Hz --> -329dB
        ADCFLT  = ADCFLT_CHOP_ENABLE | ADCFLT_RUNNING_AVERAGE | ADCFLT_NOTCH2 | 0x07 | (0x3B << 8);
        
        // Excitation Current Sources Control Register. IEXC1=1000uA, IEXC0=0uA
        IEXCON  = BIT1 | BIT3 | BIT7;          

        // ADC self-offset calibration. Three times.
        ADCMDE  = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ; // ADC self-offset calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.
        ADCMDE  = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ; // ADC self-offset calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.
        ADCMDE  = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ; // ADC self-offset calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.

        // ADC self-gain calibration. Three times.
        ADCMDE  = ADCMDE_GAIN_CAL | ADCCLKSEL_131KHZ;   // ADC self-gain calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.
        ADCMDE  = ADCMDE_GAIN_CAL | ADCCLKSEL_131KHZ;   // ADC self-gain calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.
        ADCMDE  = ADCMDE_GAIN_CAL | ADCCLKSEL_131KHZ;   // ADC self-gain calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.

        // Continuous mode, ADCCLK = 512 kHz    
        ADCMDE  = ADCMDE_CONTINUOUS | ADCCLKSEL_512KHZ;
        while (!(ADCSTA & ADC0RDY)) {}  // Wait new data

        countCycle = 0;    
        while (countCycle < 0x00100)
         {
            while (!(ADCSTA & ADC0RDY)) {}  // Wait new data
            Data_ADC1 += ADC1DAT;           // Auxiliary ADC, ADC2/ADC3 (differential mode)
            Data_ADC0 += ADC0DAT;           // Primary ADC,   ADC0/ADC1 (differential mode)
            countCycle++;    
         }       
         
         
    // Config ADC
        // ADC idle mode, ADCCLK = 131 kHz
        ADCMDE  = ADCMDE_IDLE | ADCCLKSEL_131KHZ;   
        // Primary ADC Gain=1, ext.ref (VREF+,VREF-),  ADC2/ADC3
        ADC0CON = ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_2_3;  
        // Primary ADC Gain=1, int.ref,  ADC2/ADC3
        // ADC0CON = ADC0CON_REF_INT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_2_3;  

        // Auxiliary ADC Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
        ADC1CON = ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;  
        // Auxiliary ADC Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
        // ADC1CON = ADC1CON_REF_INT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;  
        
        // ADC Filter Register
        // CHOPEN=1, RAVG2=1, NOTCH2=1, Data_Rate=16.128Hz, Settling_Time=124ms, 50Hz --> -329dB
        ADCFLT  = ADCFLT_CHOP_ENABLE | ADCFLT_RUNNING_AVERAGE | ADCFLT_NOTCH2 | 0x07 | (0x3B << 8);
        
        // Excitation Current Sources Control Register. IEXC1=1000uA, IEXC0=0uA
        IEXCON  = BIT1 | BIT3 | BIT7;          

        // Continuous mode, ADCCLK = 512 kHz    
        ADCMDE  = ADCMDE_CONTINUOUS | ADCCLKSEL_512KHZ;
        while (!(ADCSTA & ADC0RDY)) {}  // Wait new data

        countCycle = 0;    
        while (countCycle < 0x00100)
         {
            while (!(ADCSTA & ADC0RDY)) {}  // Wait new data
            Data_ADC3 += ADC1DAT;           // Auxiliary ADC, ADC2/ADC3 (differential mode)
            Data_ADC2 += ADC0DAT;           // Primary ADC,   ADC2/ADC3 (differential mode)
            countCycle++;    
         }       

        Data_ADC0 /= 0x00100;       // Primary   ADC0/ADC1       
        Data_ADC1 /= 0x00100;       // Auxiliary ADC2/ADC3  
         
        Data_ADC2 /= 0x00100;       // Primary   ADC2/ADC3         
        Data_ADC3 /= 0x00100;       // Auxiliary ADC2/ADC3  

        dData0 = Data_ADC0 - Data_ADC1; // Primary ADC0/ADC1 - Auxiliary ADC2/ADC3
        dData1 = Data_ADC2 - Data_ADC3; // Primary ADC2/ADC3 - Auxiliary ADC2/ADC3
        dData2 = Data_ADC0 - Data_ADC2; // Primary ADC0/ADC1 - Primary   ADC2/ADC3
        dData3 = dData0 - dData1;       // Calibr Data
         
    }  // Main

    Actual measurement:

    Short AIN0/AIN1/AIN2/AIN3 pins
    Data_ADC0, Primary   ADC0/ADC1 31
    Data_ADC1, Auxiliary ADC2/ADC3 200
    Data_ADC2, Primary   ADC2/ADC3 206
    Data_ADC3, Auxiliary ADC2/ADC3 195
    R = 100, 0.002%
    Data_ADC0, Primary   ADC0/ADC1 2 795 538
    Data_ADC1, Auxiliary ADC2/ADC3 2 797 009
    Data_ADC2, Primary   ADC2/ADC3 2 796 226
    Data_ADC3, Auxiliary ADC2/ADC3 2 797 022
       
    dData0, Primary ADC0/ADC1 - Auxiliary ADC2/ADC3 -1 471
    dData1, Primary ADC2/ADC3 - Auxiliary ADC2/ADC3 -796
    dData2, Primary ADC0/ADC1 - Primary   ADC2/ADC3 -688

    That is, 2 problems.

    1. Zero is not calibrated. According to the specification, this value should not exceed 0.5E-6 V.

    0.5E-6*(2**23)/0.3=14 - MAX. We have 200/14=14 times more.

    2. The primary ADC has significantly different data at different inputs. In this example 0.025%. This is really a lot.

Reply
  • 2 Shemes jof measurement.

    Soft:

    //*****************************************************************************
    // ADuC7061
    // Keil mVision V5.14
    // ADC convert
    //*****************************************************************************

    #include "ADUC706x.h"
    #include "stdio.h"


    uint16_t countCycle = 0;    
     int32_t Data_ADC0  = 0;    
     int32_t Data_ADC1  = 0;    
     int32_t Data_ADC2  = 0;    
     int32_t Data_ADC3  = 0;    
     int32_t dData0, dData1, dData2, dData3;

    //*****************************************************************************
    // Main
    //*****************************************************************************
    int main(void)
    {
        
    // Internal Crystal Selection
        POWKEY1 = 0x1;
        POWCON0 = CLK_10240_KHZ | CORE_POWER_ON | PERIPH_POWER_ON | PLL_POWER_ON;
        POWKEY2 = 0xF4;
        
    // PIN config
        GP0PAR = 0xFF;      // GPPD[7..0] = 1, pull-up resistor is disabled
        
        GP0KEY1 = 0x07;
        GP0CON1 = 0x01;     // To enable P0.0, P0.1, P0.2 and P0.3 functions as ADC inputs
        GP0KEY2 = 0x13;

    // Config ADC
        // ADC idle mode, ADCCLK = 131 kHz
        ADCMDE  = ADCMDE_IDLE | ADCCLKSEL_131KHZ;   
        // Primary ADC Gain=1, ext.ref (VREF+,VREF-), ADC0/ADC1
        ADC0CON = ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1;  
        // Primary ADC Gain=1, int.ref,  ADC2/ADC3
        // ADC0CON = ADC0CON_REF_INT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1;  

        // Auxiliary ADC Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
        ADC1CON = ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;  
        // Auxiliary ADC Gain=1, int.ref,  ADC2/ADC3
        // ADC1CON = ADC1CON_REF_INT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;  
        
        // ADC Filter Register
        // CHOPEN=1, RAVG2=1, NOTCH2=1, Data_Rate=16.128Hz, Settling_Time=124ms, 50Hz --> -329dB
        ADCFLT  = ADCFLT_CHOP_ENABLE | ADCFLT_RUNNING_AVERAGE | ADCFLT_NOTCH2 | 0x07 | (0x3B << 8);
        
        // Excitation Current Sources Control Register. IEXC1=1000uA, IEXC0=0uA
        IEXCON  = BIT1 | BIT3 | BIT7;          

        // ADC self-offset calibration. Three times.
        ADCMDE  = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ; // ADC self-offset calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.
        ADCMDE  = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ; // ADC self-offset calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.
        ADCMDE  = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ; // ADC self-offset calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.

        // ADC self-gain calibration. Three times.
        ADCMDE  = ADCMDE_GAIN_CAL | ADCCLKSEL_131KHZ;   // ADC self-gain calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.
        ADCMDE  = ADCMDE_GAIN_CAL | ADCCLKSEL_131KHZ;   // ADC self-gain calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.
        ADCMDE  = ADCMDE_GAIN_CAL | ADCCLKSEL_131KHZ;   // ADC self-gain calibration, ADCCLK = 131 kHz
        while(!(ADCSTA & ADCCALSTA)) {}                 // Wait ADC calibration status.

        // Continuous mode, ADCCLK = 512 kHz    
        ADCMDE  = ADCMDE_CONTINUOUS | ADCCLKSEL_512KHZ;
        while (!(ADCSTA & ADC0RDY)) {}  // Wait new data

        countCycle = 0;    
        while (countCycle < 0x00100)
         {
            while (!(ADCSTA & ADC0RDY)) {}  // Wait new data
            Data_ADC1 += ADC1DAT;           // Auxiliary ADC, ADC2/ADC3 (differential mode)
            Data_ADC0 += ADC0DAT;           // Primary ADC,   ADC0/ADC1 (differential mode)
            countCycle++;    
         }       
         
         
    // Config ADC
        // ADC idle mode, ADCCLK = 131 kHz
        ADCMDE  = ADCMDE_IDLE | ADCCLKSEL_131KHZ;   
        // Primary ADC Gain=1, ext.ref (VREF+,VREF-),  ADC2/ADC3
        ADC0CON = ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_2_3;  
        // Primary ADC Gain=1, int.ref,  ADC2/ADC3
        // ADC0CON = ADC0CON_REF_INT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_2_3;  

        // Auxiliary ADC Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
        ADC1CON = ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;  
        // Auxiliary ADC Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
        // ADC1CON = ADC1CON_REF_INT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;  
        
        // ADC Filter Register
        // CHOPEN=1, RAVG2=1, NOTCH2=1, Data_Rate=16.128Hz, Settling_Time=124ms, 50Hz --> -329dB
        ADCFLT  = ADCFLT_CHOP_ENABLE | ADCFLT_RUNNING_AVERAGE | ADCFLT_NOTCH2 | 0x07 | (0x3B << 8);
        
        // Excitation Current Sources Control Register. IEXC1=1000uA, IEXC0=0uA
        IEXCON  = BIT1 | BIT3 | BIT7;          

        // Continuous mode, ADCCLK = 512 kHz    
        ADCMDE  = ADCMDE_CONTINUOUS | ADCCLKSEL_512KHZ;
        while (!(ADCSTA & ADC0RDY)) {}  // Wait new data

        countCycle = 0;    
        while (countCycle < 0x00100)
         {
            while (!(ADCSTA & ADC0RDY)) {}  // Wait new data
            Data_ADC3 += ADC1DAT;           // Auxiliary ADC, ADC2/ADC3 (differential mode)
            Data_ADC2 += ADC0DAT;           // Primary ADC,   ADC2/ADC3 (differential mode)
            countCycle++;    
         }       

        Data_ADC0 /= 0x00100;       // Primary   ADC0/ADC1       
        Data_ADC1 /= 0x00100;       // Auxiliary ADC2/ADC3  
         
        Data_ADC2 /= 0x00100;       // Primary   ADC2/ADC3         
        Data_ADC3 /= 0x00100;       // Auxiliary ADC2/ADC3  

        dData0 = Data_ADC0 - Data_ADC1; // Primary ADC0/ADC1 - Auxiliary ADC2/ADC3
        dData1 = Data_ADC2 - Data_ADC3; // Primary ADC2/ADC3 - Auxiliary ADC2/ADC3
        dData2 = Data_ADC0 - Data_ADC2; // Primary ADC0/ADC1 - Primary   ADC2/ADC3
        dData3 = dData0 - dData1;       // Calibr Data
         
    }  // Main

    Actual measurement:

    Short AIN0/AIN1/AIN2/AIN3 pins
    Data_ADC0, Primary   ADC0/ADC1 31
    Data_ADC1, Auxiliary ADC2/ADC3 200
    Data_ADC2, Primary   ADC2/ADC3 206
    Data_ADC3, Auxiliary ADC2/ADC3 195
    R = 100, 0.002%
    Data_ADC0, Primary   ADC0/ADC1 2 795 538
    Data_ADC1, Auxiliary ADC2/ADC3 2 797 009
    Data_ADC2, Primary   ADC2/ADC3 2 796 226
    Data_ADC3, Auxiliary ADC2/ADC3 2 797 022
       
    dData0, Primary ADC0/ADC1 - Auxiliary ADC2/ADC3 -1 471
    dData1, Primary ADC2/ADC3 - Auxiliary ADC2/ADC3 -796
    dData2, Primary ADC0/ADC1 - Primary   ADC2/ADC3 -688

    That is, 2 problems.

    1. Zero is not calibrated. According to the specification, this value should not exceed 0.5E-6 V.

    0.5E-6*(2**23)/0.3=14 - MAX. We have 200/14=14 times more.

    2. The primary ADC has significantly different data at different inputs. In this example 0.025%. This is really a lot.

Children
  • 1. Can you try shorting pins AIN0_AIN1 and AIN2_AIN3, then remove their connection to the current path? 

    2. Can you also try the following code? I made some changes to the calibration sequence.

    // Config ADC
    // ADC idle mode, ADCCLK = 131 kHz
    // ADCMDE = ADCMDE_IDLE | ADCCLKSEL_131KHZ;
    // Primary ADC Gain=1, ext.ref (VREF+,VREF-), ADC0/ADC1
    // ADC0CON = ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1;
    // Primary ADC Gain=1, int.ref, ADC2/ADC3
    // ADC0CON = ADC0CON_REF_INT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1;

    // Auxiliary ADC Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
    // ADC1CON = ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;
    // Auxiliary ADC Gain=1, int.ref, ADC2/ADC3
    // ADC1CON = ADC1CON_REF_INT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;

    // ADC Filter Register
    // CHOPEN=1, RAVG2=1, NOTCH2=1, Data_Rate=16.128Hz, Settling_Time=124ms, 50Hz --> -329dB
    ADCFLT = ADCFLT_CHOP_ENABLE | ADCFLT_RUNNING_AVERAGE | ADCFLT_NOTCH2 | 0x07 | (0x3B << 8);

    // Excitation Current Sources Control Register. IEXC1=1000uA, IEXC0=0uA
    IEXCON = BIT1 | BIT3 | BIT7;

    ADCMDE = ADCMDE_IDLE | ADCCLKSEL_512KHZ;
    ADC0CON = ADC0CON_REF_INT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1;
    ADC1CON = ADC1CON_REF_INT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;

    // ADC self-offset calibration. Three times.
    ADCMDE = ADCMDE_OFFSET_CAL | ADCCLKSEL_512KHZ; // ADC self-offset calibration, ADCCLK = 131 kHz
    while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status.
    // ADCMDE = ADCMDE_OFFSET_CAL | ADCCLKSEL_512KHZ; // ADC self-offset calibration, ADCCLK = 131 kHz
    // while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status.
    // ADCMDE = ADCMDE_OFFSET_CAL | ADCCLKSEL_512KHZ; // ADC self-offset calibration, ADCCLK = 131 kHz
    // while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status.

    // ADC self-gain calibration. Three times.
    ADCMDE = ADCMDE_GAIN_CAL | ADCCLKSEL_512KHZ; // ADC self-gain calibration, ADCCLK = 131 kHz
    while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status.
    // ADCMDE = ADCMDE_GAIN_CAL | ADCCLKSEL_512KHZ; // ADC self-gain calibration, ADCCLK = 131 kHz
    // while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status.
    // ADCMDE = ADCMDE_GAIN_CAL | ADCCLKSEL_512KHZ; // ADC self-gain calibration, ADCCLK = 131 kHz
    // while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status.

    ADC0CON = ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1;
    ADC1CON = ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF;

    // Continuous mode, ADCCLK = 512 kHz
    ADCMDE = ADCMDE_CONTINUOUS | ADCCLKSEL_512KHZ;
    while (!(ADCSTA & ADC0RDY)) {} // Wait new data