|
| 1 | +From 43afc527438ea55086c35bb0db9f3938c660e8fc Mon Sep 17 00:00:00 2001 |
| 2 | + |
| 3 | +Date: Thu, 12 Dec 2024 15:25:49 +0800 |
| 4 | +Subject: [PATCH] feat(adc): support esp32s2 adc range above 2500mv |
| 5 | + |
| 6 | +--- |
| 7 | + components/esp_adc/Kconfig | 23 +++++++ |
| 8 | + components/esp_adc/adc_oneshot.c | 61 +++++++++++++++++++ |
| 9 | + .../esp_adc/esp32s2/adc_cali_line_fitting.c | 7 ++- |
| 10 | + components/esp_hw_support/adc_share_hw_ctrl.c | 7 +++ |
| 11 | + 4 files changed, 97 insertions(+), 1 deletion(-) |
| 12 | + |
| 13 | +diff --git a/components/esp_adc/Kconfig b/components/esp_adc/Kconfig |
| 14 | +index 0bdf4dd73e..f9fcb88822 100644 |
| 15 | +--- a/components/esp_adc/Kconfig |
| 16 | ++++ b/components/esp_adc/Kconfig |
| 17 | +@@ -66,6 +66,29 @@ menu "ADC and ADC Calibration" |
| 18 | + If you stick to this, you can enable this option to force use ADC2 under above conditions. |
| 19 | + For more details, you can search for errata on espressif website. |
| 20 | + |
| 21 | ++ menu "ADC User Code Offset" |
| 22 | ++ depends on IDF_TARGET_ESP32S2 |
| 23 | ++ config ENABLE_ADC_USER_CODE_OFFSET |
| 24 | ++ bool "Enable ADC user code offset" |
| 25 | ++ default y |
| 26 | ++ help |
| 27 | ++ On ESP32S2, you can enable the USER_CODE_OFFSET setting to adjust the ADC range to 1000mV - 3300mV. |
| 28 | ++ |
| 29 | ++ choice |
| 30 | ++ prompt "ADC calibration type" |
| 31 | ++ depends on ENABLE_ADC_USER_CODE_OFFSET |
| 32 | ++ default ADC_CAL_TYPE_FLOAT |
| 33 | ++ config ADC_CAL_TYPE_FLOAT |
| 34 | ++ bool "Float" |
| 35 | ++ help |
| 36 | ++ Use float type for ADC calibration calculations. |
| 37 | ++ config ADC_CAL_TYPE_DOUBLE |
| 38 | ++ bool "Double" |
| 39 | ++ help |
| 40 | ++ Use double type for ADC calibration calculations. |
| 41 | ++ endchoice |
| 42 | ++ endmenu |
| 43 | ++ |
| 44 | + config ADC_ONESHOT_FORCE_USE_ADC2_ON_C3 |
| 45 | + depends on IDF_TARGET_ESP32C3 |
| 46 | + bool "Force use ADC2 oneshot mode on ESP32C3" |
| 47 | +diff --git a/components/esp_adc/adc_oneshot.c b/components/esp_adc/adc_oneshot.c |
| 48 | +index 0691e22f1a..dceeea4735 100644 |
| 49 | +--- a/components/esp_adc/adc_oneshot.c |
| 50 | ++++ b/components/esp_adc/adc_oneshot.c |
| 51 | +@@ -166,6 +166,29 @@ esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_chann |
| 52 | + return ESP_OK; |
| 53 | + } |
| 54 | + |
| 55 | ++ |
| 56 | ++#if (CONFIG_ENABLE_ADC_USER_CODE_OFFSET & CONFIG_IDF_TARGET_ESP32S2) |
| 57 | ++static int16_t g_adc_cal_delta = 0; |
| 58 | ++static int16_t g_adc_cal_delta_actual = 0; |
| 59 | ++/** |
| 60 | ++ * @brief Set adc1 calibration delta value |
| 61 | ++ * |
| 62 | ++ * @param delta_mv delta value in mv, This value will be added to the calibration value. |
| 63 | ++ * |
| 64 | ++ */ |
| 65 | ++void adc1_set_cal_delta(int16_t delta_mv) |
| 66 | ++{ |
| 67 | ++ g_adc_cal_delta = delta_mv * 1.54f; |
| 68 | ++} |
| 69 | ++int16_t adc1_get_cal_delta() |
| 70 | ++{ |
| 71 | ++ return g_adc_cal_delta_actual; |
| 72 | ++} |
| 73 | ++ |
| 74 | ++extern uint32_t get_calibration_offset(adc_unit_t adc_n, adc_atten_t atten); |
| 75 | ++#endif |
| 76 | ++ |
| 77 | ++ |
| 78 | + esp_err_t adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw) |
| 79 | + { |
| 80 | + ESP_RETURN_ON_FALSE(handle && out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); |
| 81 | +@@ -180,7 +203,16 @@ esp_err_t adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t chan, |
| 82 | + #if SOC_ADC_CALIBRATION_V1_SUPPORTED |
| 83 | + adc_atten_t atten = adc_ll_get_atten(handle->unit_id, chan); |
| 84 | + adc_hal_calibration_init(handle->unit_id); |
| 85 | ++#if (CONFIG_ENABLE_ADC_USER_CODE_OFFSET & CONFIG_IDF_TARGET_ESP32S2) |
| 86 | ++ adc_calc_hw_calibration_code(handle->unit_id, atten); |
| 87 | ++ uint32_t cal_val = get_calibration_offset(handle->unit_id, atten); |
| 88 | ++ uint32_t cal_val_new = cal_val + g_adc_cal_delta; |
| 89 | ++ cal_val_new = cal_val_new > 4095 ? 4095 : cal_val_new; |
| 90 | ++ g_adc_cal_delta_actual = cal_val_new - cal_val; |
| 91 | ++ adc_hal_set_calibration_param(handle->unit_id, cal_val_new); |
| 92 | ++#else |
| 93 | + adc_set_hw_calibration_code(handle->unit_id, atten); |
| 94 | ++#endif |
| 95 | + #endif // SOC_ADC_CALIBRATION_V1_SUPPORTED |
| 96 | + bool valid = false; |
| 97 | + valid = adc_oneshot_hal_convert(&(handle->hal), out_raw); |
| 98 | +@@ -255,6 +287,35 @@ esp_err_t adc_oneshot_get_calibrated_result(adc_oneshot_unit_handle_t handle, ad |
| 99 | + ESP_LOGD(TAG, "raw: 0d%d", raw); |
| 100 | + ESP_RETURN_ON_ERROR(adc_cali_raw_to_voltage(cali_handle, raw, cali_result), TAG, "adc calibration fail"); |
| 101 | + |
| 102 | ++#if (CONFIG_IDF_TARGET_ESP32S2 & CONFIG_ENABLE_ADC_USER_CODE_OFFSET) |
| 103 | ++ int voltage_b = 0; |
| 104 | ++#if CONFIG_ADC_CAL_TYPE_DOUBLE |
| 105 | ++ typedef const double ADC_CAL_TYPE; |
| 106 | ++#else |
| 107 | ++ typedef const float ADC_CAL_TYPE; |
| 108 | ++#endif |
| 109 | ++ |
| 110 | ++ adc_atten_t atten = adc_ll_get_atten(handle->unit_id, chan); |
| 111 | ++ if(atten == ADC_ATTEN_DB_12) { |
| 112 | ++ if(*cali_result > 2600) { |
| 113 | ++ ESP_LOGD(TAG, "first is %u", *cali_result); |
| 114 | ++ adc1_set_cal_delta(1000); |
| 115 | ++ ESP_RETURN_ON_ERROR(adc_oneshot_read(handle, chan, &raw), TAG, "adc oneshot read fail"); |
| 116 | ++ adc1_set_cal_delta(0); |
| 117 | ++ ESP_RETURN_ON_ERROR(adc_cali_raw_to_voltage(cali_handle, raw, &voltage_b), TAG, "adc calibration fail"); |
| 118 | ++ |
| 119 | ++ ESP_LOGD(TAG, "before is %u", voltage_b); |
| 120 | ++ ADC_CAL_TYPE a = -0.0000050800531; |
| 121 | ++ ADC_CAL_TYPE b = 0.02334678273232382; |
| 122 | ++ ADC_CAL_TYPE c = -26.699083271336267; |
| 123 | ++ ADC_CAL_TYPE e = a * voltage_b * voltage_b + b * voltage_b + c; |
| 124 | ++ voltage_b = voltage_b * (1 + e / 100); |
| 125 | ++ ESP_LOGD(TAG, "after is %u", voltage_b); |
| 126 | ++ *cali_result = voltage_b; |
| 127 | ++ } |
| 128 | ++ } |
| 129 | ++#endif |
| 130 | ++ |
| 131 | + return ESP_OK; |
| 132 | + } |
| 133 | + |
| 134 | +diff --git a/components/esp_adc/esp32s2/adc_cali_line_fitting.c b/components/esp_adc/esp32s2/adc_cali_line_fitting.c |
| 135 | +index 2e826e1f08..a43cdc5173 100644 |
| 136 | +--- a/components/esp_adc/esp32s2/adc_cali_line_fitting.c |
| 137 | ++++ b/components/esp_adc/esp32s2/adc_cali_line_fitting.c |
| 138 | +@@ -143,8 +143,13 @@ static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage) |
| 139 | + //pointers are checked in the upper layer |
| 140 | + |
| 141 | + cali_chars_line_fitting_t *ctx = arg; |
| 142 | +- *voltage = raw * ctx->coeff_a / coeff_a_scaling + ctx->coeff_b / coeff_b_scaling; |
| 143 | + |
| 144 | ++#if (CONFIG_ENABLE_ADC_USER_CODE_OFFSET & CONFIG_IDF_TARGET_ESP32S2) |
| 145 | ++ extern int16_t adc1_get_cal_delta(); |
| 146 | ++ *voltage = (raw + adc1_get_cal_delta() * 2) * ctx->coeff_a / coeff_a_scaling + ctx->coeff_b / coeff_b_scaling; |
| 147 | ++#else |
| 148 | ++ *voltage = raw * ctx->coeff_a / coeff_a_scaling + ctx->coeff_b / coeff_b_scaling; |
| 149 | ++#endif |
| 150 | + return ESP_OK; |
| 151 | + } |
| 152 | + |
| 153 | +diff --git a/components/esp_hw_support/adc_share_hw_ctrl.c b/components/esp_hw_support/adc_share_hw_ctrl.c |
| 154 | +index 32f3c67b79..74019195bc 100644 |
| 155 | +--- a/components/esp_hw_support/adc_share_hw_ctrl.c |
| 156 | ++++ b/components/esp_hw_support/adc_share_hw_ctrl.c |
| 157 | +@@ -96,6 +96,13 @@ void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten) |
| 158 | + ESP_EARLY_LOGV(TAG, "Calib(V%d) ADC%d atten=%d: %04" PRIX32, version, adc_n + 1, atten, init_code); |
| 159 | + } |
| 160 | + |
| 161 | ++#if (CONFIG_ENABLE_ADC_USER_CODE_OFFSET & CONFIG_IDF_TARGET_ESP32S2) |
| 162 | ++uint32_t get_calibration_offset(adc_unit_t adc_n, adc_atten_t atten) |
| 163 | ++{ |
| 164 | ++ return s_adc_cali_param[adc_n][atten]; |
| 165 | ++} |
| 166 | ++#endif |
| 167 | ++ |
| 168 | + void IRAM_ATTR adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten) |
| 169 | + { |
| 170 | + adc_hal_set_calibration_param(adc_n, s_adc_cali_param[adc_n][atten]); |
| 171 | +-- |
| 172 | +2.34.1 |
| 173 | + |
0 commit comments