After calibration Primary / Auxiliary Channel ADC Offset Calibration Register (ADC0OF, ADC1OF) always are read = 0. Both self-offset and zero-scale calibration mode. It is unclear how to correct the values for negative/positive offsets.
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
After calibration Primary / Auxiliary Channel ADC Offset Calibration Register (ADC0OF, ADC1OF) always are read = 0. Both self-offset and zero-scale calibration mode. It is unclear how to correct the values for negative/positive offsets.
Primary (ADC0/ADC1)/ Auxiliary (ADC2/ADC3) channels are in differential mode, enable, external reference inputs (VREF+, VREF−).
All the iput pins are short-circuited. (ADC0=ADC1=ADC2=ADC3).
"Chop Enable = 1" does not correct the offset error Auxiliary (ADC2/ADC3) channel.
Command ADC self-offset calibration: "ADCMDE = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ;" does not correct the offset error Auxiliary (ADC2/ADC3) channel too.
The value of offset error Auxiliary (ADC2/ADC3) channel = 1500 ... 3500.
When using an internal reference, self-offset calibration works well. The value of offset error = 0..3.
Is there no difference in ADC output before and after enabling chop or performing ADC self-offset calibration?
Are you using an ADuC7060 evaluation board or your board in testing the ADC?
Can you show the register values and sequence used in configuring both?
The board is its own. The board does not affect, because the inputs are short-circuited.
Uref = 300 Ohm * 600 uA = 180 mV. Increasing the current to 1000uA (300 mV) has no effect.
// Excitation Current Sources = 600 uA
IEXCON = BIT7 | BIT2 | BIT1; // IEXC1=1, 600uA
DelayMS(2000); // Delay 2000 mS
// ADC0 = (ADC0/ADC1) pins
// ADC1 = (ADC2/ADC3) pins
ADCMDE = ADC_IDLE_MODE; // ADC idle mode
// SF=7, AF=59 (Data_Rate=16.128Hz, Settling_Time=124ms, 50Hz --> -329dB)
ADCFLT = (ADCFLT_CHOP_ENABLE | (0x07 << 0) | (0x3B << 8));
// ADC0 Gain=1, ext.ref (VREF+,VREF-), ADC0/ADC1
ADC0CON = (ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1);
// ADC1 Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
ADC1CON = (ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF);
DelayMS(250); // Delay 250 mS
// Get Data ADC
ADCMDE = ADCMDE_VALUE; // Continuous mode, ADCCLK = 512 kHz
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
ADC1_Dat = ADC1DAT; // Auxiliary ADC = 107
ADC0_Dat = ADC0DAT; // Primary ADC = 2564
// ADC self-gain calibration
ADCMDE = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ;
while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status
// Get Data ADC
ADCMDE = ADCMDE_VALUE; // Continuous mode, ADCCLK = 512 kHz
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
ADC1_Dat = ADC1DAT; // Auxiliary ADC = -27
ADC0_Dat = ADC0DAT; // Primary ADC = 2417
// ADC0 = ADC1 = (ADC2/ADC3) pins
ADCMDE = ADC_IDLE_MODE; // ADC idle mode
// SF=7, AF=59 (Data_Rate=16.128Hz, Settling_Time=124ms, 50Hz --> -329dB)
ADCFLT = (ADCFLT_CHOP_ENABLE | (0x07 << 0) | (0x3B << 8));
// ADC0 Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
ADC0CON = (ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_2_3);
// ADC1 Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
ADC1CON = (ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF);
DelayMS(250); // Delay 250 mS
// Get Data ADC
ADCMDE = ADCMDE_VALUE; // Continuous mode, ADCCLK = 512 kHz
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
ADC1_Dat = ADC1DAT; // Auxiliary ADC = 2480
ADC0_Dat = ADC0DAT; // Primary ADC = 2488
// ADC self-gain calibration
ADCMDE = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ;
while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status
// Get Data ADC
ADCMDE = ADCMDE_VALUE; // Continuous mode, ADCCLK = 512 kHz
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
ADC1_Dat = ADC1DAT; // Auxiliary ADC = 2447
ADC0_Dat = ADC0DAT; // Primary ADC = 2478
The board is its own. The board does not affect, because the inputs are short-circuited.
Uref = 300 Ohm * 600 uA = 180 mV. Increasing the current to 1000uA (300 mV) has no effect.
// Excitation Current Sources = 600 uA
IEXCON = BIT7 | BIT2 | BIT1; // IEXC1=1, 600uA
DelayMS(2000); // Delay 2000 mS
// ADC0 = (ADC0/ADC1) pins
// ADC1 = (ADC2/ADC3) pins
ADCMDE = ADC_IDLE_MODE; // ADC idle mode
// SF=7, AF=59 (Data_Rate=16.128Hz, Settling_Time=124ms, 50Hz --> -329dB)
ADCFLT = (ADCFLT_CHOP_ENABLE | (0x07 << 0) | (0x3B << 8));
// ADC0 Gain=1, ext.ref (VREF+,VREF-), ADC0/ADC1
ADC0CON = (ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_0_1);
// ADC1 Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
ADC1CON = (ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF);
DelayMS(250); // Delay 250 mS
// Get Data ADC
ADCMDE = ADCMDE_VALUE; // Continuous mode, ADCCLK = 512 kHz
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
ADC1_Dat = ADC1DAT; // Auxiliary ADC = 107
ADC0_Dat = ADC0DAT; // Primary ADC = 2564
// ADC self-gain calibration
ADCMDE = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ;
while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status
// Get Data ADC
ADCMDE = ADCMDE_VALUE; // Continuous mode, ADCCLK = 512 kHz
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
ADC1_Dat = ADC1DAT; // Auxiliary ADC = -27
ADC0_Dat = ADC0DAT; // Primary ADC = 2417
// ADC0 = ADC1 = (ADC2/ADC3) pins
ADCMDE = ADC_IDLE_MODE; // ADC idle mode
// SF=7, AF=59 (Data_Rate=16.128Hz, Settling_Time=124ms, 50Hz --> -329dB)
ADCFLT = (ADCFLT_CHOP_ENABLE | (0x07 << 0) | (0x3B << 8));
// ADC0 Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
ADC0CON = (ADC0CON_REF_EXT | ADC0CON_ADC0EN | ADC0CON_CHANNEL_DIFF_2_3);
// ADC1 Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3
ADC1CON = (ADC1CON_REF_EXT | ADC1CON_ADC0EN | ADC1CON_CHANNEL_2_3_DIFF);
DelayMS(250); // Delay 250 mS
// Get Data ADC
ADCMDE = ADCMDE_VALUE; // Continuous mode, ADCCLK = 512 kHz
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
ADC1_Dat = ADC1DAT; // Auxiliary ADC = 2480
ADC0_Dat = ADC0DAT; // Primary ADC = 2488
// ADC self-gain calibration
ADCMDE = ADCMDE_OFFSET_CAL | ADCCLKSEL_131KHZ;
while(!(ADCSTA & ADCCALSTA)) {} // Wait ADC calibration status
// Get Data ADC
ADCMDE = ADCMDE_VALUE; // Continuous mode, ADCCLK = 512 kHz
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
while (!(ADCSTA & (ADC0RDY | ADC1RDY))) {} // Wait new data
ADC1_Dat = ADC1DAT; // Auxiliary ADC = 2447
ADC0_Dat = ADC0DAT; // Primary ADC = 2478
Can you check the ADC reading before and after calibration if the primary and auxiliary ADC configuration uses the internal reference?
Can you also try performing a system zero-scale calibration using your ADC configurations?
Internal reference, before calibration: ADC0 = 2730; ADC1 = 4772
Internal reference, after calibration: ADC0 = 1; ADC1 = -3
As an experiment, I tried to use zero-scale calibration. Works well. But to do this,have to short the channel externally. In work it is impossible.
I checked that you could write manually to the offset calibration register.
Is it possible to perform the calibration, then record the value of the offset calibration register and write it manually later in the user code?
At the manufacturing stage, such calibration can be performed. But in the operating mode, it is impossible to calibrate the offset, because this will require an external zero. And in the temperature range -40..+85 C will have to do this periodically. Therefore, zero-scale calibration with the connection of an internal zero is used. For ADC2/ADC3 pins, it does not work correctly (see above). You can evaluate the error only by connecting an external zero.
I tried to replicate your setup with the code provided.
IEXCON = BIT7 | BIT2 | BIT1; // IEXC1=1, 600uA ADCMDE = BIT1|BIT0; // ADC IDLE MODE ADCFLT = BIT15|(0x07<<0)|(0x3B<<8); // ADC0 Gain=1, ext.ref (VREF+,VREF-), ADC0/ADC1 ADC0CON = BIT15|BIT4; // ADC1 Gain=1, ext.ref (VREF+,VREF-), ADC2/ADC3 ADC1CON = BIT15|BIT4; ADCMDE = BIT7|BIT0; // Enable Continuous conversion mode while (!(ADCSTA & (BIT1|BIT0))) {} while (!(ADCSTA & (BIT1|BIT0))) {} while (!(ADCSTA & (BIT1|BIT0))) {} slADC1Result = ADC1DAT; slADC0Result = ADC0DAT; // ADC self-gain calibration ADCMDE = BIT7|BIT2; while(!(ADCSTA & BIT15)) {} // Wait ADC calibration status ADCMDE = BIT7|BIT0; // Enable Continuous conversion mode while (!(ADCSTA & (BIT1|BIT0))) {} while (!(ADCSTA & (BIT1|BIT0))) {} while (!(ADCSTA & (BIT1|BIT0))) {} slADC1Result = ADC1DAT; slADC0Result = ADC0DAT;
For the external reference, I assumed that REF- = GND and REF+ = 180mV.
For ADC0 = (ADC0/ADC1) and ADC1 = (ADC2/ADC3),
Before Calibration: ADC0 = -3391, ADC1 = -1686
After Calibration: ADC0 = -2, ADC1 = 14
For ADC0 = (ADC2/ADC3) and ADC1 = (ADC2/ADC3),
Before Calibration: ADC0 = -3402, ADC1 = -1640
After Calibration: ADC0 = 11, ADC1 = 14
The ADC input pins are shorted during the testing.
The self-offset calibration is working on my setup. Could you let me know if I missed anything in the ADC configuration or the external reference?
Have you tried using another unit in your testing?
According to the datasheet "External Reference Input Range" should be within = 0.1V .. AVDD. In my case, VREF−(pin 18) = 1.144V and VREF−(pin 17) = 1.324V. Diff VRef=180mV. The results are described above.
Now I want to redo REF- = GND and REF+ = 180mV. This will require reworking of finished products. Let's see what happens.
The "External Reference Input Range" refers to the REF+ and REF- pins voltage difference.
I tried replicating the schematic shown. I measured different voltage readings in the REF+ and REF- pins. REF+ = 0.73V and REF- = 0.55V. The Diff Vref is still 180mV.
Before Calibration: ADC0 = -3451, ADC1 = -1737
After Calibration: ADC0 = -66, ADC1 = -13
I changed 8 channels to REF- = GND and REF+ = 180mV and 300mV. The ADC1 offset remained the same bad. No changes before self-offset calibration and after :(( On average 1500.
On channels assembled on chips from another distributor - about 230! Crooked chips?
There may be an issue with the chip you are using since there seems to be a considerable difference between the readings (1500 and 230).
Have you checked if something may be shorted with the circuitry? When I tried to replicate the schematic shown, I read a different voltage at REF+ and REF- pins compared to 1.144V and 1.324V you mentioned.
The measurements are correct. Voltage relative to the ground for Iref = 0.6mA:
1. VDD = 0.580 (BAV90)
2. I-=I+=U-=U+= 0.580 + 470 Ohm * 0.6 mA = 0.580 + 0.282 = 0.862
3. Ref- = 0.862 + 470 Ohm * 0.6 mA = 0.862 + 0.282 = 1.144
4. Ref+ = 1.144 + 300 Ohm * 0.6 mA = 1.144 + 0.180 = 1.324