The Analog-to-Digital Converter (ADC) in [STM32](https://www.ampheo.com/search/STM32) [microcontrollers](https://www.ampheo.com/c/microcontrollers) requires calibration to ensure accurate measurements. Here's a detailed explanation of the calibration process:

**1. Why ADC Calibration is Necessary**
* Compensates for internal capacitor charge/discharge variations
* Corrects offset and linearity errors
* Improves measurement accuracy (typically ±1 LSB after calibration)
* Required after power-up or long idle periods
**2. Calibration Process Steps**
**2.1 Basic Calibration (All STM32 Series)**
```
c
void ADC_Calibrate(ADC_HandleTypeDef* hadc) {
// 1. Ensure ADC is disabled
HAL_ADC_Stop(hadc);
// 2. Start calibration
HAL_ADCEx_Calibration_Start(hadc);
// 3. Wait for completion
while(HAL_ADCEx_Calibration_GetValue(hadc) != HAL_OK);
}
```
**2.2 STM32H7 Specific Calibration**
The H7 series has additional calibration registers:
```
c
void ADC_H7_Calibrate(ADC_HandleTypeDef* hadc) {
// 1. Disable ADC
ADC1->CR &= ~ADC_CR_ADEN;
// 2. Calibrate single-ended mode
ADC1->CR |= ADC_CR_ADCALLIN;
ADC1->CR |= ADC_CR_ADCAL;
while((ADC1->CR & ADC_CR_ADCAL) != 0);
// 3. For differential mode (if used)
ADC1->CR |= ADC_CR_ADCALDIF;
ADC1->CR |= ADC_CR_ADCAL;
while((ADC1->CR & ADC_CR_ADCAL) != 0);
}
```
**3. Important Considerations**
**3.1 Timing Requirements**
* Must be performed when ADC is disabled
* Takes ~10-100 clock cycles depending on [STM32](https://www.onzuu.com/search/STM32) family
* Should be done:
* After power-up
* After temperature changes >10°C
* Periodically in critical applications
**3.2 Multi-ADC Systems**
For STM32 devices with multiple ADCs:
1. Calibrate each ADC separately
2. Maintain consistent timing between calibrations
3. Use same reference voltage for all ADCs
**3.3 Voltage Reference**
* Calibration assumes stable reference voltage
* For VREFINT (internal reference):
```
c
// Enable internal reference buffer (STM32H7)
HAL_SYSCFG_VREFBUF_VoltageScalingConfig(SYSCFG_VREFBUF_VOLTAGE_SCALE0);
HAL_SYSCFG_EnableVREFBUF();
```
**4. Post-Calibration Verification**
```
c
uint32_t Verify_Calibration() {
// Read known voltage (e.g., internal reference)
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc, 10);
uint32_t adcValue = HAL_ADC_GetValue(&hadc);
// Compare with expected value
const uint32_t expected = 1234; // Device-specific
return (abs(adcValue - expected) <= 2); // Within 2 LSB
}
```
**5. Advanced Techniques**
**5.1 Background Calibration ([STM32L4](https://www.ampheo.com/search/STM32L4)/L5)**
```
c
// Enable background calibration
ADC1->CFGR |= ADC_CFGR_CONT;
ADC1->CR |= ADC_CR_ADCAL;
```
**5.2 Temperature Compensation**
```
c
// Read temperature sensor (TS_CAL1/2 values from flash)
float Get_Temperature() {
uint16_t *TS_CAL1 = (uint16_t*)0x1FFF75A8;
uint16_t *TS_CAL2 = (uint16_t*)0x1FFF75CA;
HAL_ADC_Start(&hadc_temp);
uint32_t temp_raw = HAL_ADC_GetValue(&hadc_temp);
return ((temp_raw - TS_CAL1) * (85.0 - 30.0)) /
(TS_CAL2 - TS_CAL1) + 30.0;
}
```
**6. Troubleshooting**

**7. Recommended Practice**
1. Calibrate at startup
2. Store calibration factors in flash/EEPROM
3. Implement periodic recalibration in mission-critical apps
4. Use hardware averaging ([STM32G4](https://www.ampheo.com/search/STM32G4)/H7) for better noise immunity
For specific [STM32](https://www.ampheoelec.de/search/STM32) families (F4, G0, U5, etc.), check the reference manual for family-specific calibration procedures. The process is similar but may have minor register differences.