Post Go back to editing

ADuC7061. ADC Offset Calibration Register (ADC0OF, ADC1OF)

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.

Parents
  • 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



Reply

  •    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



Children
  • 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