Skip to content

Commit 7a0b4eb

Browse files
committed
feat(adc): support adc two point calibration
1 parent 3339788 commit 7a0b4eb

31 files changed

+1469
-1
lines changed

.github/workflows/upload_component.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ jobs:
9494
components/usb/usb_device_uac;
9595
components/usb/usb_device_uvc;
9696
components/usb/usb_stream;
97+
components/utilities/adc_tp_calibration;
9798
components/utilities/xz;
9899
components/zero_detection;
99100
tools/cmake_utilities;

.gitlab/ci/build.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,18 @@ build_example_utilities_xz_decompress_file:
946946
variables:
947947
EXAMPLE_DIR: examples/utilities/xz_decompress_file
948948

949+
build_example_utilities_adc_tp_calibration:
950+
extends:
951+
- .build_examples_template
952+
- .rules:build:example_utilities_adc_tp_calibration
953+
parallel:
954+
matrix:
955+
- IMAGE: espressif/idf:release-v5.0
956+
- IMAGE: espressif/idf:release-v5.1
957+
- IMAGE: espressif/idf:release-v5.2
958+
variables:
959+
EXAMPLE_DIR: examples/utilities/adc_tp_calibration
960+
949961
build_example_vision_opencv_color_tracker:
950962
extends:
951963
- .build_examples_template
@@ -1644,6 +1656,14 @@ build_example_elf_loader_build_elf_file_example:
16441656
variables:
16451657
EXAMPLE_DIR: examples/elf_loader/build_elf_file_example
16461658

1659+
build_components_utilities_adc_tp_calibration_test_apps:
1660+
extends:
1661+
- .build_examples_template
1662+
- .rules:build:components_utilities_adc_tp_calibration_test_apps
1663+
- .build_idf_active_release_version
1664+
variables:
1665+
EXAMPLE_DIR: components/utilities/adc_tp_calibration/test_apps
1666+
16471667
build_components_zero_detection_test_apps:
16481668
extends:
16491669
- .build_examples_template

.gitlab/ci/rules.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@
339339
- "components/sensors/power_monitor/ina236/**/*"
340340
- "tools/cmake_utilities/package_manager.cmake"
341341

342+
.patterns-components_utilities_adc_tp_calibration: &patterns-components_utilities_adc_tp_calibration
343+
- "components/utilities/adc_tp_calibration/**/*"
344+
- "tools/cmake_utilities/package_manager.cmake"
345+
342346
# examples folder, in the alphabetic order
343347
.patterns-docs: &patterns-docs
344348
- "docs/**/*"
@@ -393,6 +397,7 @@
393397
- "components/usb/usb_device_uac/include/usb_device_uac.h"
394398
- "components/usb/usb_device_uvc/include/usb_device_uvc.h"
395399
- "components/usb/usb_stream/include/usb_stream.h"
400+
- "components/utilities/adc_tp_calibration/include/adc_tp_calibration.h"
396401
- "components/zero_detection/include/zero_detection.h"
397402
# examples folder, in the alphabetic order
398403
.patterns-example_ai_esp_dl_human_activity_recognition: &patterns-example_ai_esp_dl_human_activity_recognition
@@ -614,6 +619,9 @@
614619
.patterns-example_usb_otg_usb_host_device_mode_manual_switch: &patterns-example_usb_otg_usb_host_device_mode_manual_switch
615620
- "examples/usb/otg/usb_host_device_mode_manual_switch/**/*"
616621

622+
.patterns-example_utilities_adc_tp_calibration: &patterns-example_utilities_adc_tp_calibration
623+
- "examples/utilities/adc_tp_calibration/**/*"
624+
617625
.patterns-example_utilities_xz_decompress_file: &patterns-example_utilities_xz_decompress_file
618626
- "examples/utilities/xz_decompress_file/**/*"
619627

@@ -1562,6 +1570,18 @@
15621570
- <<: *if-dev-push
15631571
changes: *patterns-example_usb_otg_usb_host_device_mode_manual_switch
15641572

1573+
.rules:build:example_utilities_adc_tp_calibration:
1574+
rules:
1575+
- <<: *if-protected
1576+
- <<: *if-label-build
1577+
- <<: *if-trigger-job
1578+
- <<: *if-dev-push
1579+
changes: *patterns-build_system
1580+
- <<: *if-dev-push
1581+
changes: *patterns-components_utilities_adc_tp_calibration
1582+
- <<: *if-dev-push
1583+
changes: *patterns-example_utilities_adc_tp_calibration
1584+
15651585
.rules:build:example_utilities_xz_decompress_file:
15661586
rules:
15671587
- <<: *if-protected
@@ -2431,6 +2451,17 @@
24312451
- <<: *if-dev-push
24322452
changes: *patterns-components_usb_usb_device_uvc
24332453

2454+
.rules:build:components_utilities_adc_tp_calibration_test_apps:
2455+
rules:
2456+
- <<: *if-protected
2457+
- <<: *if-label-build
2458+
- <<: *if-label-target_test
2459+
- <<: *if-trigger-job
2460+
- <<: *if-dev-push
2461+
changes: *patterns-build_system
2462+
- <<: *if-dev-push
2463+
changes: *patterns-components_utilities_adc_tp_calibration
2464+
24342465
.rules:build:components_sensors_humiture_aht20_test_apps:
24352466
rules:
24362467
- <<: *if-protected

README.md

Lines changed: 1 addition & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ components/usb/usb_device_uvc/test_apps:
190190
enable:
191191
- if: SOC_USB_OTG_SUPPORTED == 1 and IDF_VERSION_MAJOR >= 5
192192

193+
components/utilities/adc_tp_calibration/test_apps:
194+
enable:
195+
- if: IDF_TARGET in ["esp32", "esp32s2"]
196+
193197
components/sensors/power_monitor/ina236/test_apps:
194198
enable:
195199
- if: INCLUDE_DEFAULT == 1
Lines changed: 5 additions & 0 deletions
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.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
idf_component_register(SRC_DIRS "."
2+
INCLUDE_DIRS "include")
Lines changed: 63 additions & 0 deletions
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)
Lines changed: 104 additions & 0 deletions
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+
}

0 commit comments

Comments
 (0)