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.
ADUC7061
Production
The ADuC7060/ADuC7061 are fully integrated, 8 kSPS, 24-bit data acquisition systems incorporating high performance multi-channel sigma-delta (S-?) analog...
Datasheet
ADUC7061 on Analog.com
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.
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.
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.
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