How to calibrate the error of ADC module inside MCU?

 Understanding ADC Error Sources

Before calibration, it's important to understand the common error sources in microcontroller ADCs:



  1. Offset Error: Non-zero output when input is zero

  2. Gain Error: Deviation from ideal slope in transfer function

  3. Non-linearity: Deviation from straight-line transfer function

  4. Noise: Random variations in readings

  5. Reference Voltage Errors: Inaccuracies in voltage reference


Hardware Preparation for Calibration

  1. Precision voltage source (or at least a stable known voltage)

  2. High-quality multimeter (for reference measurements)

  3. Stable power supply (clean power to MCU)

  4. Temperature-controlled environment (if temperature compensation needed)


Basic Calibration Methods

1. Offset Calibration

c

// Measure with grounded input
#define NUM_OFFSET_SAMPLES 100

float adc_calibrate_offset() {
    uint32_t sum = 0;
    for(int i=0; i<NUM_OFFSET_SAMPLES; i++) {
        sum += adc_read(); // Replace with your ADC read function
        delay(1);
    }
    float offset = (float)sum / NUM_OFFSET_SAMPLES;
    return offset;
}


2. Gain Calibration

c

// Apply known reference voltage (e.g., 2.5V)
float adc_calibrate_gain(float known_voltage, float vref) {
    float offset = adc_calibrate_offset(); // Get offset first
    uint32_t sum = 0;
    
    for(int i=0; i<100; i++) {
        sum += adc_read();
        delay(1);
    }
    
    float raw_avg = (float)sum / 100.0;
    float expected_raw = (known_voltage / vref) * ADC_MAX_VALUE;
    float gain_error = (raw_avg - offset) / expected_raw;
    
    return gain_error;
}


Advanced Calibration Techniques

1. Multi-Point Calibration

c

typedef struct {
    float actual_voltage;
    float raw_adc;
} CalibrationPoint;

typedef struct {
    float slope;
    float intercept;
} CalibrationCoeff;

CalibrationCoeff calculate_calibration(CalibrationPoint points[], uint8_t count) {
    float sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
    
    for(uint8_t i=0; i<count; i++) {
        sum_x += points[i].raw_adc;
        sum_y += points[i].actual_voltage;
        sum_xy += points[i].raw_adc * points[i].actual_voltage;
        sum_xx += points[i].raw_adc * points[i].raw_adc;
    }
    
    CalibrationCoeff coeff;
    coeff.slope = (count * sum_xy - sum_x * sum_y) / (count * sum_xx - sum_x * sum_x);
    coeff.intercept = (sum_y - coeff.slope * sum_x) / count;
    
    return coeff;
}


2. Temperature Compensation

c

typedef struct {
    float temp;
    float offset;
    float gain_error;
} TempCalPoint;

float interpolate_temp_compensation(TempCalPoint cal_table[], uint8_t count, float current_temp) {
    // Find surrounding points
    // Perform linear interpolation
    // Return compensation value
}


Implementation in Firmware

1. Storing Calibration Parameters

c

typedef struct {
    float offset;
    float gain;
    float temp_comp_slope;
    uint32_t crc; // For data integrity check
} AdcCalibrationData;

void save_calibration_to_flash(AdcCalibrationData *data) {
    // Calculate CRC
    data->crc = calculate_crc(data, sizeof(AdcCalibrationData)-4);
    
    // Write to flash
    flash_write(CALIBRATION_ADDRESS, (uint8_t*)data, sizeof(AdcCalibrationData));
}


2. Applying Calibration

c

float read_calibrated_adc(float temperature) {
    static AdcCalibrationData calib;
    static bool calib_loaded = false;
    
    if(!calib_loaded) {
        load_calibration_from_flash(&calib);
        calib_loaded = true;
    }
    
    float raw = (float)adc_read();
    float temp_comp = calib.temp_comp_slope * (temperature - 25.0); // 25°C as reference
    
    // Apply calibration
    float calibrated = (raw - calib.offset - temp_comp) * calib.gain;
    
    return calibrated;
}


Practical Calibration Procedure

  1. Warm-up period: Power on system and wait for stabilization (10-15 minutes)

  2. Offset calibration:

    • Short ADC input to ground

    • Measure multiple samples and calculate average

  3. Gain calibration:

    • Apply precise reference voltage (e.g., 80% of full scale)

    • Measure and compare with expected value

  4. Multi-point verification:

    • Check at 10%, 50%, 90% of full scale

    • Adjust calibration if needed

  5. Temperature testing (if applicable):

    • Characterize at different temperatures

    • Build temperature compensation table


Special Considerations

  1. Reference Voltage Stability:

    • Use external reference if internal is unstable

    • Consider reference voltage measurement via another channel

  2. Averaging for Noise Reduction:

    c
    复制
    #define ADC_OVERSAMPLE 16
    
    uint32_t read_oversampled_adc() {
        uint32_t sum = 0;
        for(int i=0; i<ADC_OVERSAMPLE; i++) {
            sum += adc_read();
        }
        return sum >> 2; // For 16x oversampling, gives 2 extra bits
    }
  3. PCB Layout Effects:

    • Ensure proper grounding

    • Minimize noise coupling

    • Use proper bypass capacitors


Validation and Testing

  1. Static Test:

    • Apply known DC voltages and verify readings

  2. Dynamic Test:

    • Use function generator for ramp signals

    • Check linearity across range

  3. Long-term Drift Test:

    • Monitor over hours/days

    • Check for environmental effects

评论

此博客中的热门博文

How To Connect Stm32 To PC?

What are the common HDL languages used in FPGA design?

How do you set up ADC (Analog-to-Digital Converter) in STM32?