Skip to content

Commit fae0bd2

Browse files
committed
Merge branch 'feat/add_adc_tp_calibration' into 'master'
feat(adc): support adc two point calibration See merge request ae_group/esp-iot-solution!1274
2 parents 60ae86e + 7a0b4eb commit fae0bd2

31 files changed

+1469
-1
lines changed

.github/workflows/upload_component.yml

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ jobs:
9595
components/usb/usb_device_uac;
9696
components/usb/usb_device_uvc;
9797
components/usb/usb_stream;
98+
components/utilities/adc_tp_calibration;
9899
components/utilities/xz;
99100
components/zero_detection;
100101
tools/cmake_utilities;

.gitlab/ci/build.yml

+20
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,18 @@ build_example_utilities_xz_decompress_file:
976976
variables:
977977
EXAMPLE_DIR: examples/utilities/xz_decompress_file
978978

979+
build_example_utilities_adc_tp_calibration:
980+
extends:
981+
- .build_examples_template
982+
- .rules:build:example_utilities_adc_tp_calibration
983+
parallel:
984+
matrix:
985+
- IMAGE: espressif/idf:release-v5.0
986+
- IMAGE: espressif/idf:release-v5.1
987+
- IMAGE: espressif/idf:release-v5.2
988+
variables:
989+
EXAMPLE_DIR: examples/utilities/adc_tp_calibration
990+
979991
build_example_vision_opencv_color_tracker:
980992
extends:
981993
- .build_examples_template
@@ -1684,6 +1696,14 @@ build_example_elf_loader_build_elf_file_example:
16841696
variables:
16851697
EXAMPLE_DIR: examples/elf_loader/build_elf_file_example
16861698

1699+
build_components_utilities_adc_tp_calibration_test_apps:
1700+
extends:
1701+
- .build_examples_template
1702+
- .rules:build:components_utilities_adc_tp_calibration_test_apps
1703+
- .build_idf_active_release_version
1704+
variables:
1705+
EXAMPLE_DIR: components/utilities/adc_tp_calibration/test_apps
1706+
16871707
build_components_zero_detection_test_apps:
16881708
extends:
16891709
- .build_examples_template

.gitlab/ci/rules.yml

+31
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@
343343
- "components/sensors/power_monitor/ina236/**/*"
344344
- "tools/cmake_utilities/package_manager.cmake"
345345

346+
.patterns-components_utilities_adc_tp_calibration: &patterns-components_utilities_adc_tp_calibration
347+
- "components/utilities/adc_tp_calibration/**/*"
348+
- "tools/cmake_utilities/package_manager.cmake"
349+
346350
# examples folder, in the alphabetic order
347351
.patterns-docs: &patterns-docs
348352
- "docs/**/*"
@@ -397,6 +401,7 @@
397401
- "components/usb/usb_device_uac/include/usb_device_uac.h"
398402
- "components/usb/usb_device_uvc/include/usb_device_uvc.h"
399403
- "components/usb/usb_stream/include/usb_stream.h"
404+
- "components/utilities/adc_tp_calibration/include/adc_tp_calibration.h"
400405
- "components/zero_detection/include/zero_detection.h"
401406
# examples folder, in the alphabetic order
402407
.patterns-example_ai_esp_dl_human_activity_recognition: &patterns-example_ai_esp_dl_human_activity_recognition
@@ -621,6 +626,9 @@
621626
.patterns-example_usb_otg_usb_host_device_mode_manual_switch: &patterns-example_usb_otg_usb_host_device_mode_manual_switch
622627
- "examples/usb/otg/usb_host_device_mode_manual_switch/**/*"
623628

629+
.patterns-example_utilities_adc_tp_calibration: &patterns-example_utilities_adc_tp_calibration
630+
- "examples/utilities/adc_tp_calibration/**/*"
631+
624632
.patterns-example_utilities_xz_decompress_file: &patterns-example_utilities_xz_decompress_file
625633
- "examples/utilities/xz_decompress_file/**/*"
626634

@@ -1590,6 +1598,18 @@
15901598
- <<: *if-dev-push
15911599
changes: *patterns-example_usb_otg_usb_host_device_mode_manual_switch
15921600

1601+
.rules:build:example_utilities_adc_tp_calibration:
1602+
rules:
1603+
- <<: *if-protected
1604+
- <<: *if-label-build
1605+
- <<: *if-trigger-job
1606+
- <<: *if-dev-push
1607+
changes: *patterns-build_system
1608+
- <<: *if-dev-push
1609+
changes: *patterns-components_utilities_adc_tp_calibration
1610+
- <<: *if-dev-push
1611+
changes: *patterns-example_utilities_adc_tp_calibration
1612+
15931613
.rules:build:example_utilities_xz_decompress_file:
15941614
rules:
15951615
- <<: *if-protected
@@ -2470,6 +2490,17 @@
24702490
- <<: *if-dev-push
24712491
changes: *patterns-components_usb_usb_device_uvc
24722492

2493+
.rules:build:components_utilities_adc_tp_calibration_test_apps:
2494+
rules:
2495+
- <<: *if-protected
2496+
- <<: *if-label-build
2497+
- <<: *if-label-target_test
2498+
- <<: *if-trigger-job
2499+
- <<: *if-dev-push
2500+
changes: *patterns-build_system
2501+
- <<: *if-dev-push
2502+
changes: *patterns-components_utilities_adc_tp_calibration
2503+
24732504
.rules:build:components_sensors_humiture_aht20_test_apps:
24742505
rules:
24752506
- <<: *if-protected

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ The registered components in ESP-IoT-Solution are listed below:
5757
| Component | Version |
5858
| --- | --- |
5959
| [adc_mic](https://components.espressif.com/components/espressif/adc_mic) | [![Component Registry](https://components.espressif.com/components/espressif/adc_mic/badge.svg)](https://components.espressif.com/components/espressif/adc_mic) |
60+
| [adc_tp_calibration](https://components.espressif.com/components/espressif/adc_tp_calibration) | [![Component Registry](https://components.espressif.com/components/espressif/adc_tp_calibration/badge.svg)](https://components.espressif.com/components/espressif/adc_tp_calibration) |
6061
| [aht20](https://components.espressif.com/components/espressif/aht20) | [![Component Registry](https://components.espressif.com/components/espressif/aht20/badge.svg)](https://components.espressif.com/components/espressif/aht20) |
6162
| [apds9960](https://components.espressif.com/components/espressif/apds9960) | [![Component Registry](https://components.espressif.com/components/espressif/apds9960/badge.svg)](https://components.espressif.com/components/espressif/apds9960) |
6263
| [at24c02](https://components.espressif.com/components/espressif/at24c02) | [![Component Registry](https://components.espressif.com/components/espressif/at24c02/badge.svg)](https://components.espressif.com/components/espressif/at24c02) |

README_CN.md

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ ESP-IoT-Solution 中注册的组件如下:
5757
| 组件 | 版本 |
5858
| --- | --- |
5959
| [adc_mic](https://components.espressif.com/components/espressif/adc_mic) | [![Component Registry](https://components.espressif.com/components/espressif/adc_mic/badge.svg)](https://components.espressif.com/components/espressif/adc_mic) |
60+
| [adc_tp_calibration](https://components.espressif.com/components/espressif/adc_tp_calibration) | [![Component Registry](https://components.espressif.com/components/espressif/adc_tp_calibration/badge.svg)](https://components.espressif.com/components/espressif/adc_tp_calibration) |
6061
| [aht20](https://components.espressif.com/components/espressif/aht20) | [![Component Registry](https://components.espressif.com/components/espressif/aht20/badge.svg)](https://components.espressif.com/components/espressif/aht20) |
6162
| [apds9960](https://components.espressif.com/components/espressif/apds9960) | [![Component Registry](https://components.espressif.com/components/espressif/apds9960/badge.svg)](https://components.espressif.com/components/espressif/apds9960) |
6263
| [at24c02](https://components.espressif.com/components/espressif/at24c02) | [![Component Registry](https://components.espressif.com/components/espressif/at24c02/badge.svg)](https://components.espressif.com/components/espressif/at24c02) |

components/.build-rules.yml

+4
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ components/usb/usb_device_uvc/test_apps:
194194
enable:
195195
- if: SOC_USB_OTG_SUPPORTED == 1 and IDF_VERSION_MAJOR >= 5
196196

197+
components/utilities/adc_tp_calibration/test_apps:
198+
enable:
199+
- if: IDF_TARGET in ["esp32", "esp32s2"]
200+
197201
components/sensors/power_monitor/ina236/test_apps:
198202
enable:
199203
- if: INCLUDE_DEFAULT == 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# ChangeLog
2+
3+
## v0.1.0 - 2025-4-18
4+
5+
First release version.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
idf_component_register(SRC_DIRS "."
2+
INCLUDE_DIRS "include")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# ADC Tow-Point Calibration Component
2+
3+
``adc_tp_calibration`` is a component that performs two-point ADC calibration for ESP32 and ESP32-S2 chips at the application level. By loading calibration parameters in the application layer, it enables easy implementation of two-point ADC calibration. This component offers the following features:
4+
5+
1. Supports inputting calibration parameters at the application level, allowing users to store the calibration data in storage media such as NVS or SD cards.
6+
2. Supports the two-point calibration scheme for ESP32 and the Method 2 two-point calibration scheme for ESP32-S2, without interfering with the existing calibration scheme provided by ESP-IDF.
7+
8+
## How to Configure Calibration Parameters
9+
10+
You can refer to the calibration principles described in the [documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/others/adc_tp_calibration.html) to obtain the calibration parameters required by the adc_tp_calibration component.
11+
12+
Note that when collecting the raw ADC data needed for calibration, it is recommended to use an external 100 nF filtering capacitor and apply software filtering to ensure stable ADC readings.
13+
14+
## Add component to your project
15+
16+
Please use the component manager command `add-dependency` to add the `adc_tp_calibration` to your project's dependency, during the `CMake` step the component will be downloaded automatically
17+
18+
```
19+
idf.py add-dependency "espressif/adc_tp_calibration=*"
20+
```
21+
22+
Alternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html).
23+
24+
## How to use
25+
26+
Since the calibration scheme is closely related to the ADC attenuation setting, please ensure that the attenuation used by the ``adc_tp_calibration`` component matches the one configured in the ADC driver.
27+
28+
```c
29+
30+
// Step1: Initializing Calibration Parameters
31+
32+
#if CONFIG_IDF_TARGET_ESP32
33+
adc_tp_cali_config_t tp_cali_config = {
34+
.adc_unit = ADC_UNIT_1,
35+
.adc_raw_value_150mv_atten0 = 323,
36+
.adc_raw_value_850mv_atten0 = 3300,
37+
};
38+
#elif CONFIG_IDF_TARGET_ESP32S2
39+
adc_tp_cali_config_t tp_cali_config = {
40+
.adc_unit = ADC_UNIT_1,
41+
.adc_raw_value_600mv_atten0 = 5895,
42+
.adc_raw_value_800mv_atten2_5 = 5786,
43+
.adc_raw_value_1000mv_atten6 = 5820,
44+
.adc_raw_value_2000mv_atten12 = 6287,
45+
};
46+
#endif
47+
48+
// Step2: Initializing Two-Point ADC Calibration
49+
50+
adc_tp_cali_handle_t adc_tp_cali = adc_tp_cali_create(&tp_cali_config, ADC_ATTEN_DB_0);
51+
52+
// Step3: Initialize the ADC driver and acquire raw ADC data.
53+
...
54+
55+
// Step4: Calibrate ADC Data
56+
adc_tp_cali_raw_to_voltage(adc_tp_cali, raw_value, &voltage)
57+
```
58+
59+
Please note that the calibration data used in the above process must be determined by the user based on the [documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/others/adc_tp_calibration.html). This data is not universal and must be obtained through manual calibration.
60+
61+
## Reference
62+
63+
[Documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/others/adc_tp_calibration.html)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <stdio.h>
7+
#include <string.h>
8+
#include "esp_log.h"
9+
#include "esp_check.h"
10+
#include "adc_tp_calibration.h"
11+
12+
static const char* TAG = "adc_tp_cal";
13+
14+
#if CONFIG_IDF_TARGET_ESP32
15+
#define TP_LOW_VOLTAGE 150
16+
#define TP_HIGH_VOLTAGE 850
17+
#define LIN_COEFF_A_SCALE 65536
18+
#define LIN_COEFF_A_ROUND (LIN_COEFF_A_SCALE/2)
19+
static const uint32_t adc1_tp_atten_scale[4] = {65504, 86975, 120389, 224310};
20+
static const uint32_t adc2_tp_atten_scale[4] = {65467, 86861, 120416, 224708};
21+
static const uint32_t adc1_tp_atten_offset[4] = {0, 1, 27, 54};
22+
static const uint32_t adc2_tp_atten_offset[4] = {0, 9, 26, 66};
23+
#elif CONFIG_IDF_TARGET_ESP32S2
24+
static const int coeff_a_scaling = 65536;
25+
static const int coeff_b_scaling = 1024;
26+
static const uint32_t v_high[] = {600, 800, 1000, 2000};
27+
#endif
28+
29+
typedef struct {
30+
adc_atten_t atten;
31+
adc_tp_cali_config_t config;
32+
uint32_t coeff_a;
33+
uint32_t coeff_b;
34+
#if CONFIG_IDF_TARGET_ESP32
35+
const uint32_t *atten_scales;
36+
const uint32_t *atten_offsets;
37+
#elif CONFIG_IDF_TARGET_ESP32S2
38+
uint32_t high[4];
39+
#endif
40+
} adc_tp_cali_t;
41+
42+
adc_tp_cali_handle_t adc_tp_cali_create(adc_tp_cali_config_t *config, adc_atten_t atten)
43+
{
44+
ESP_RETURN_ON_FALSE(config, NULL, TAG, "config is NULL");
45+
ESP_RETURN_ON_FALSE(config->adc_unit == ADC_UNIT_1 || config->adc_unit == ADC_UNIT_2, NULL, TAG, "invalid ADC unit");
46+
47+
adc_tp_cali_t *adc_tp_cal = (adc_tp_cali_t *)calloc(1, sizeof(adc_tp_cali_t));
48+
ESP_RETURN_ON_FALSE(adc_tp_cal, NULL, TAG, "memory allocation for device handler failed");
49+
50+
adc_tp_cal->atten = atten;
51+
adc_tp_cal->config = *config;
52+
53+
#if CONFIG_IDF_TARGET_ESP32
54+
if (adc_tp_cal->config.adc_unit == ADC_UNIT_1) {
55+
adc_tp_cal->atten_scales = adc1_tp_atten_scale;
56+
adc_tp_cal->atten_offsets = adc1_tp_atten_offset;
57+
} else {
58+
adc_tp_cal->atten_scales = adc2_tp_atten_scale;
59+
adc_tp_cal->atten_offsets = adc2_tp_atten_offset;
60+
}
61+
62+
uint32_t delta_x = config->adc_raw_value_850mv_atten0 - config->adc_raw_value_150mv_atten0;
63+
uint32_t delta_v = TP_HIGH_VOLTAGE - TP_LOW_VOLTAGE;
64+
adc_tp_cal->coeff_a = (delta_v * adc_tp_cal->atten_scales[atten] + (delta_x / 2)) / delta_x;
65+
adc_tp_cal->coeff_b = TP_HIGH_VOLTAGE - ((delta_v * config->adc_raw_value_850mv_atten0 + (delta_x / 2)) / delta_x) + adc_tp_cal->atten_offsets[atten];
66+
#elif CONFIG_IDF_TARGET_ESP32S2
67+
const uint32_t high_values[] = {
68+
config->adc_raw_value_600mv_atten0,
69+
config->adc_raw_value_800mv_atten2_5,
70+
config->adc_raw_value_1000mv_atten6,
71+
config->adc_raw_value_2000mv_atten12
72+
};
73+
memcpy(adc_tp_cal->high, high_values, sizeof(high_values));
74+
75+
adc_tp_cal->coeff_a = coeff_a_scaling * v_high[atten] / adc_tp_cal->high[atten];
76+
adc_tp_cal->coeff_b = 0;
77+
#endif
78+
return (adc_tp_cali_handle_t)adc_tp_cal;
79+
}
80+
81+
esp_err_t adc_tp_cali_delete(adc_tp_cali_handle_t *adc_tp_cali_handle)
82+
{
83+
if (*adc_tp_cali_handle == NULL) {
84+
return ESP_OK;
85+
}
86+
87+
adc_tp_cali_t *adc_tp_cal = (adc_tp_cali_t *)(*adc_tp_cali_handle);
88+
free(adc_tp_cal);
89+
*adc_tp_cali_handle = NULL;
90+
return ESP_OK;
91+
}
92+
93+
esp_err_t adc_tp_cali_raw_to_voltage(adc_tp_cali_handle_t adc_tp_cali_handle, int raw_value, int *voltage)
94+
{
95+
ESP_RETURN_ON_FALSE(adc_tp_cali_handle && voltage, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
96+
97+
adc_tp_cali_t *adc_tp_cal = (adc_tp_cali_t *)adc_tp_cali_handle;
98+
#if CONFIG_IDF_TARGET_ESP32
99+
*voltage = (((adc_tp_cal->coeff_a * raw_value) + LIN_COEFF_A_ROUND) / LIN_COEFF_A_SCALE) + adc_tp_cal->coeff_b;
100+
#elif CONFIG_IDF_TARGET_ESP32S2
101+
*voltage = (raw_value * adc_tp_cal->coeff_a / (coeff_a_scaling / coeff_b_scaling) + adc_tp_cal->coeff_b) / coeff_b_scaling;
102+
#endif
103+
return ESP_OK;
104+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: "0.1.0"
2+
targets:
3+
- esp32
4+
- esp32s2
5+
description: ADC two-point calibration scheme for ESP32 and ESP32S2
6+
url: https://github.com/espressif/esp-iot-solution/tree/master/components/utilities/adc_tp_calibration
7+
repository: https://github.com/espressif/esp-iot-solution.git
8+
documentation: https://docs.espressif.com/projects/esp-iot-solution/en/latest/others/adc_tp_calibration.html
9+
issues: https://github.com/espressif/esp-iot-solution/issues
10+
11+
dependencies:
12+
idf: ">=4.4"
13+
cmake_utilities: "*"
14+
sbom:
15+
supplier: 'Organization: Espressif Systems (Shanghai) CO LTD'
16+
originator: 'Organization: Espressif Systems (Shanghai) CO LTD'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#pragma once
7+
8+
#include "hal/adc_types.h"
9+
10+
/**
11+
* @brief ADC calibration configuration structure
12+
*
13+
* This structure contains the raw ADC values measured at specific voltage points
14+
* for calibration. The values are different for ESP32 and ESP32-S2.
15+
*/
16+
typedef struct {
17+
adc_unit_t adc_unit; /*!< ADC unit (ADC1 or ADC2) */
18+
#if CONFIG_IDF_TARGET_ESP32
19+
int adc_raw_value_150mv_atten0; /*!< ADC raw value at 150mV with atten0 */
20+
int adc_raw_value_850mv_atten0; /*!< ADC raw value at 850mV with atten0 */
21+
#elif CONFIG_IDF_TARGET_ESP32S2
22+
int adc_raw_value_600mv_atten0; /*!< ADC raw value at 600mV with atten0 */
23+
int adc_raw_value_800mv_atten2_5; /*!< ADC raw value at 800mV with atten2_5 */
24+
int adc_raw_value_1000mv_atten6; /*!< ADC raw value at 1000mV with atten6 */
25+
int adc_raw_value_2000mv_atten12; /*!< ADC raw value at 2000mV with atten12 */
26+
#endif
27+
} adc_tp_cali_config_t;
28+
29+
typedef void *adc_tp_cali_handle_t; /*!< ADC calibration handle */
30+
31+
/**
32+
* @brief Create ADC calibration handle
33+
*
34+
* @param config Pointer to ADC calibration configuration
35+
* @param atten ADC attenuation level
36+
* @return adc_tp_cali_handle_t Handle of ADC calibration, NULL if failed
37+
*/
38+
adc_tp_cali_handle_t adc_tp_cali_create(adc_tp_cali_config_t *config, adc_atten_t atten);
39+
40+
/**
41+
* @brief Delete ADC calibration handle
42+
*
43+
* @param adc_tp_cali_handle Pointer to ADC calibration handle
44+
* @return esp_err_t
45+
* - ESP_OK: Always returns ESP_OK
46+
*/
47+
esp_err_t adc_tp_cali_delete(adc_tp_cali_handle_t *adc_tp_cali_handle);
48+
49+
/**
50+
* @brief Convert ADC raw value to voltage in millivolts
51+
*
52+
* @param adc_tp_cali_handle ADC calibration handle
53+
* @param raw_value ADC raw value to convert
54+
* @param voltage Pointer to store the converted voltage in millivolts
55+
* @return esp_err_t
56+
* - ESP_OK: Success
57+
* - ESP_ERR_INVALID_ARG: Invalid argument
58+
*/
59+
esp_err_t adc_tp_cali_raw_to_voltage(adc_tp_cali_handle_t adc_tp_cali_handle, int raw_value, int *voltage);

0 commit comments

Comments
 (0)