mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/esp32s2_adc_calib' into 'master'
adc: add driver for esp32s2 adc calibration scheme Closes IDFGH-3500, IDF-1458, and IDF-2013 See merge request espressif/esp-idf!9557
This commit is contained in:
commit
a92d90435f
@ -546,7 +546,9 @@ esp_err_t adc2_vref_to_gpio(gpio_num_t gpio)
|
||||
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
|
||||
{
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
if (adc_unit & ADC_UNIT_1) return ESP_ERR_INVALID_ARG;
|
||||
if (adc_unit & ADC_UNIT_1) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
#endif
|
||||
adc2_channel_t ch = ADC2_CHANNEL_MAX;
|
||||
/* Check if the GPIO supported. */
|
||||
@ -556,7 +558,9 @@ esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ch == ADC2_CHANNEL_MAX) return ESP_ERR_INVALID_ARG;
|
||||
if (ch == ADC2_CHANNEL_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_set_power_manage(ADC_POWER_SW_ON);
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "soc/sens_struct.h"
|
||||
#include "driver/temp_sensor.h"
|
||||
#include "regi2c_ctrl.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp32s2/esp_efuse_rtc_table.h"
|
||||
|
||||
static const char *TAG = "tsens";
|
||||
|
||||
@ -59,6 +61,8 @@ static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = {
|
||||
|
||||
static SemaphoreHandle_t rtc_tsens_mux = NULL;
|
||||
|
||||
static float deltaT = 1000; // greater than range
|
||||
|
||||
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_FORCE_PD_M);
|
||||
@ -133,6 +137,28 @@ esp_err_t temp_sensor_read_raw(uint32_t *tsens_out)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void read_delta_t_from_efuse(void)
|
||||
{
|
||||
uint32_t version = esp_efuse_rtc_table_read_calib_version();
|
||||
if (version == 1 || version == 2) {
|
||||
// fetch calibration value for temp sensor from eFuse
|
||||
deltaT = esp_efuse_rtc_table_get_parsed_efuse_value(RTCCALIB_IDX_TMPSENSOR, false) / 10.0;
|
||||
} else {
|
||||
// no value to fetch, use 0.
|
||||
deltaT = 0;
|
||||
}
|
||||
ESP_LOGD(TAG, "deltaT = %f\n", deltaT);
|
||||
}
|
||||
|
||||
static float parse_temp_sensor_raw_value(uint32_t tsens_raw, const tsens_dac_offset_t *dac)
|
||||
{
|
||||
if (deltaT > 512) { //suggests that the value is not initialized
|
||||
read_delta_t_from_efuse();
|
||||
}
|
||||
float result = (TSENS_ADC_FACTOR * (float)tsens_raw - TSENS_DAC_FACTOR * dac->offset - TSENS_SYS_OFFSET) - deltaT;
|
||||
return result;
|
||||
}
|
||||
|
||||
esp_err_t temp_sensor_read_celsius(float *celsius)
|
||||
{
|
||||
TSENS_CHECK(celsius != NULL, ESP_ERR_INVALID_ARG);
|
||||
@ -143,7 +169,7 @@ esp_err_t temp_sensor_read_celsius(float *celsius)
|
||||
ret = temp_sensor_read_raw(&tsens_out);
|
||||
TSENS_CHECK(ret == ESP_OK, ret);
|
||||
const tsens_dac_offset_t *dac = &dac_offset[tsens.dac_offset];
|
||||
*celsius = (TSENS_ADC_FACTOR * (float)tsens_out - TSENS_DAC_FACTOR * dac->offset - TSENS_SYS_OFFSET);
|
||||
*celsius = parse_temp_sensor_raw_value(tsens_out, dac);
|
||||
if (*celsius < dac->range_min || *celsius > dac->range_max) {
|
||||
ESP_LOGW(TAG, "Exceeding the temperature range!");
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
|
@ -8,6 +8,9 @@ if(EXISTS "${COMPONENT_DIR}/${target}")
|
||||
list(APPEND srcs "src/${target}/esp_efuse_api.c"
|
||||
"src/${target}/esp_efuse_fields.c"
|
||||
"src/${target}/esp_efuse_utility.c")
|
||||
if("esp32s2" STREQUAL "${target}")
|
||||
list(APPEND srcs "src/${target}/esp_efuse_rtc_table.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND srcs "src/esp_efuse_api.c"
|
||||
|
108
components/efuse/include/esp32s2/esp_efuse_rtc_table.h
Normal file
108
components/efuse/include/esp32s2/esp_efuse_rtc_table.h
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define RTCCALIB_ESP32S2_ADCCOUNT 2
|
||||
#define RTCCALIB_ESP32S2_ATTENCOUNT 4
|
||||
|
||||
#define RTCCALIB_V1_PARAM_VLOW 0
|
||||
#define RTCCALIB_V1_PARAM_VHIGH 1
|
||||
#define RTCCALIB_V2_PARAM_VHIGH 0
|
||||
#define RTCCALIB_V2_PARAM_VINIT 1
|
||||
|
||||
// these are the tags. Either use them directly or use esp_efuse_rtc_table_get_tag to calculate
|
||||
// the corresponding tag.
|
||||
#define RTCCALIB_V1IDX_A10L 1
|
||||
#define RTCCALIB_V1IDX_A11L 2
|
||||
#define RTCCALIB_V1IDX_A12L 3
|
||||
#define RTCCALIB_V1IDX_A13L 4
|
||||
#define RTCCALIB_V1IDX_A20L 5
|
||||
#define RTCCALIB_V1IDX_A21L 6
|
||||
#define RTCCALIB_V1IDX_A22L 7
|
||||
#define RTCCALIB_V1IDX_A23L 8
|
||||
#define RTCCALIB_V1IDX_A10H 9
|
||||
#define RTCCALIB_V1IDX_A11H 10
|
||||
#define RTCCALIB_V1IDX_A12H 11
|
||||
#define RTCCALIB_V1IDX_A13H 12
|
||||
#define RTCCALIB_V1IDX_A20H 13
|
||||
#define RTCCALIB_V1IDX_A21H 14
|
||||
#define RTCCALIB_V1IDX_A22H 15
|
||||
#define RTCCALIB_V1IDX_A23H 16
|
||||
#define RTCCALIB_V2IDX_A10H 17
|
||||
#define RTCCALIB_V2IDX_A11H 18
|
||||
#define RTCCALIB_V2IDX_A12H 19
|
||||
#define RTCCALIB_V2IDX_A13H 20
|
||||
#define RTCCALIB_V2IDX_A20H 21
|
||||
#define RTCCALIB_V2IDX_A21H 22
|
||||
#define RTCCALIB_V2IDX_A22H 23
|
||||
#define RTCCALIB_V2IDX_A23H 24
|
||||
#define RTCCALIB_V2IDX_A10I 25
|
||||
#define RTCCALIB_V2IDX_A11I 26
|
||||
#define RTCCALIB_V2IDX_A12I 27
|
||||
#define RTCCALIB_V2IDX_A13I 28
|
||||
#define RTCCALIB_V2IDX_A20I 29
|
||||
#define RTCCALIB_V2IDX_A21I 30
|
||||
#define RTCCALIB_V2IDX_A22I 31
|
||||
#define RTCCALIB_V2IDX_A23I 32
|
||||
#define RTCCALIB_IDX_TMPSENSOR 33
|
||||
|
||||
/**
|
||||
* @brief Get rtc calibration version.
|
||||
*/
|
||||
int esp_efuse_rtc_table_read_calib_version(void);
|
||||
|
||||
/**
|
||||
* @brief Helper function to calculate a tag from human-readable parameters.
|
||||
* Tag is used to index the desired data from the efuse.
|
||||
* For example, (1, 1, 3, 1) yields the tag RTCCALIB_V1IDX_A13H
|
||||
* extra params are used for identification when a adc_num-atten combination has
|
||||
* multiple efuse values.
|
||||
* @param adc_channel_num verbatim numbering of the ADC channel. For channel 1, use 1 and not 0.
|
||||
* @param atten attenuation. use the enum value.
|
||||
* @param version the version of the scheme to index for.
|
||||
* @param extra_params defined differently for each version.
|
||||
* */
|
||||
int esp_efuse_rtc_table_get_tag(int version, int adc_channel_num, int atten, int extra_params);
|
||||
|
||||
/**
|
||||
* @brief Fetches a raw value from efuse and does signed bit parsing
|
||||
* @param tag tag obtained with esp_efuse_rtc_table_get_tag
|
||||
*
|
||||
* */
|
||||
int esp_efuse_rtc_table_get_raw_efuse_value(int tag);
|
||||
|
||||
/**
|
||||
* @brief Fetches a raw value from efuse and resolve it to get
|
||||
* the original number that it meant to represent.
|
||||
*
|
||||
* @param tag tag obtained with esp_efuse_rtc_table_get_tag
|
||||
* @param use_zero_inputs Does not perform the raw value fetching before resolving the number,
|
||||
* but proceed as if all zeros were read from efuse.
|
||||
*
|
||||
* */
|
||||
int esp_efuse_rtc_table_get_parsed_efuse_value(int tag, bool skip_efuse_reading);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
167
components/efuse/src/esp32s2/esp_efuse_rtc_table.c
Normal file
167
components/efuse/src/esp32s2/esp_efuse_rtc_table.c
Normal file
@ -0,0 +1,167 @@
|
||||
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp32s2/esp_efuse_rtc_table.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#define RTC_TBL_LOG_TAG "efuse_rtc_table"
|
||||
|
||||
|
||||
|
||||
/* Note on definition of tags
|
||||
*
|
||||
* For adc calibration, value = raw * multiplier + offset, but these values are kind of arbitrary so
|
||||
* we use a lookup table to do the bookkeeping.
|
||||
*
|
||||
* The offset of an item can be calculated as follows:
|
||||
* PARAM_OFFSET + ADC_NUM(which is the UNIT_COUNT minus 1) * ATTEN_NUM + ATTEN_NUM
|
||||
* where PARAM_OFFSET is the index of the first item.
|
||||
*
|
||||
* ADC, ATTEN form a 2-dim array. For each (version number, extra parameters) tuple we keep a such array,
|
||||
* and use if-else statements to choose which array we use.
|
||||
* */
|
||||
|
||||
#define RTCCALIB_V1_ADCREADINGLOW_OFFSET RTCCALIB_V1IDX_A10L
|
||||
#define RTCCALIB_V1_ADCREADINGHIGH_OFFSET RTCCALIB_V1IDX_A10H
|
||||
#define RTCCALIB_V2_ADCREADINGHIGH_OFFSET RTCCALIB_V2IDX_A10H
|
||||
#define RTCCALIB_V2_ADCREADINGINIT_OFFSET RTCCALIB_V2IDX_A10I
|
||||
|
||||
typedef struct {
|
||||
const int tag; // should be the same as the index in adc_efuse_raw_map
|
||||
const int block;
|
||||
const int begin_bit;
|
||||
const int length;
|
||||
const int multiplier;
|
||||
const int base;
|
||||
const int depends;
|
||||
} efuse_map_info_t;
|
||||
|
||||
static const efuse_map_info_t adc_efuse_raw_map[] = {
|
||||
{0},
|
||||
// INDEXING TAG, BLOCK, BEGIN_BIT, LENGTH, MULTIPLIER, OFFSET BASE, OFFSET DEP
|
||||
{RTCCALIB_V1IDX_A10L, 2, 208, 6, 4, 2231, 0},
|
||||
{RTCCALIB_V1IDX_A11L, 2, 214, 6, 4, 1643, 0},
|
||||
{RTCCALIB_V1IDX_A12L, 2, 220, 6, 4, 1290, 0},
|
||||
{RTCCALIB_V1IDX_A13L, 2, 226, 6, 4, 701, 0},
|
||||
{RTCCALIB_V1IDX_A20L, 2, 232, 6, 4, 2305, 0},
|
||||
{RTCCALIB_V1IDX_A21L, 2, 238, 6, 4, 1693, 0},
|
||||
{RTCCALIB_V1IDX_A22L, 2, 244, 6, 4, 1343, 0},
|
||||
{RTCCALIB_V1IDX_A23L, 2, 250, 6, 4, 723, 0},
|
||||
|
||||
{RTCCALIB_V1IDX_A10H, 2, 144, 8, 4, 5775, 0},
|
||||
{RTCCALIB_V1IDX_A11H, 2, 152, 8, 4, 5693, 0},
|
||||
{RTCCALIB_V1IDX_A12H, 2, 160, 8, 4, 5723, 0},
|
||||
{RTCCALIB_V1IDX_A13H, 2, 168, 8, 4, 6209, 0},
|
||||
{RTCCALIB_V1IDX_A20H, 2, 176, 8, 4, 5817, 0},
|
||||
{RTCCALIB_V1IDX_A21H, 2, 184, 8, 4, 5703, 0},
|
||||
{RTCCALIB_V1IDX_A22H, 2, 192, 8, 4, 5731, 0},
|
||||
{RTCCALIB_V1IDX_A23H, 2, 200, 8, 4, 6157, 0},
|
||||
|
||||
{RTCCALIB_V2IDX_A10H, 2, 197, 6, 2, 169, RTCCALIB_V2IDX_A12H},
|
||||
{RTCCALIB_V2IDX_A11H, 2, 203, 6, 2, -26, RTCCALIB_V2IDX_A12H},
|
||||
{RTCCALIB_V2IDX_A12H, 2, 209, 9, 2, 126, RTCCALIB_V2IDX_A21H},
|
||||
{RTCCALIB_V2IDX_A13H, 2, 218, 7, 2, 387, RTCCALIB_V2IDX_A12H},
|
||||
{RTCCALIB_V2IDX_A20H, 2, 225, 7, 2, 177, RTCCALIB_V2IDX_A21H},
|
||||
{RTCCALIB_V2IDX_A21H, 2, 232, 10, 2, 5815, 0},
|
||||
{RTCCALIB_V2IDX_A22H, 2, 242, 7, 2, 27, RTCCALIB_V2IDX_A21H},
|
||||
{RTCCALIB_V2IDX_A23H, 2, 249, 7, 2, 410, RTCCALIB_V2IDX_A21H},
|
||||
|
||||
{RTCCALIB_V2IDX_A10I, 2, 147, 8, 2, 1519, 0},
|
||||
{RTCCALIB_V2IDX_A11I, 2, 155, 6, 2, 88, RTCCALIB_V2IDX_A10I},
|
||||
{RTCCALIB_V2IDX_A12I, 2, 161, 5, 2, 8, RTCCALIB_V2IDX_A11I},
|
||||
{RTCCALIB_V2IDX_A13I, 2, 166, 6, 2, 70, RTCCALIB_V2IDX_A12I},
|
||||
{RTCCALIB_V2IDX_A20I, 2, 172, 8, 2, 1677, 0},
|
||||
{RTCCALIB_V2IDX_A21I, 2, 180, 6, 2, 23, RTCCALIB_V2IDX_A20I},
|
||||
{RTCCALIB_V2IDX_A22I, 2, 186, 5, 2, 6, RTCCALIB_V2IDX_A21I},
|
||||
{RTCCALIB_V2IDX_A23I, 2, 191, 6, 2, 13, RTCCALIB_V2IDX_A22I},
|
||||
|
||||
{RTCCALIB_IDX_TMPSENSOR, 2, 135, 9, 1, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
|
||||
int esp_efuse_rtc_table_read_calib_version(void)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_BLOCK2_VERSION, &result, 32);
|
||||
return result;
|
||||
}
|
||||
|
||||
int esp_efuse_rtc_table_get_tag(int version, int adc_num, int atten, int extra_params)
|
||||
{
|
||||
int param_offset; // used to index which (adc_num, atten) array to use.
|
||||
if (version == 1 && extra_params == RTCCALIB_V1_PARAM_VLOW) { // Volage LOW, Version 1
|
||||
param_offset = RTCCALIB_V1_ADCREADINGLOW_OFFSET;
|
||||
} else if (version == 1 && extra_params == RTCCALIB_V1_PARAM_VHIGH) {
|
||||
param_offset = RTCCALIB_V1_ADCREADINGHIGH_OFFSET;
|
||||
} else if (version == 2 && extra_params == RTCCALIB_V2_PARAM_VHIGH) {
|
||||
param_offset = RTCCALIB_V2_ADCREADINGHIGH_OFFSET;
|
||||
} else if (version == 2 && extra_params == RTCCALIB_V2_PARAM_VINIT) {
|
||||
param_offset = RTCCALIB_V2_ADCREADINGINIT_OFFSET;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int result = param_offset + (adc_num - 1) * RTCCALIB_ESP32S2_ATTENCOUNT + atten;
|
||||
ESP_EARLY_LOGV(RTC_TBL_LOG_TAG, "V%d ADC%d ATTEN%d PARAM%d -> %d", version, adc_num, atten, extra_params, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a signed-bit int to a normal (2-complement) int.
|
||||
* */
|
||||
static int signed_bit_to_int(uint32_t number, int len)
|
||||
{
|
||||
if (number >> (len - 1)) {
|
||||
// first bit is set, unset that bit and negate the number.
|
||||
number = -(number ^ (1 << (len - 1)));
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
int esp_efuse_rtc_table_get_raw_efuse_value(int tag)
|
||||
{
|
||||
assert(tag > 0);
|
||||
if (tag == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t val = 0;
|
||||
esp_efuse_read_block(adc_efuse_raw_map[tag].block, &val, adc_efuse_raw_map[tag].begin_bit, adc_efuse_raw_map[tag].length);
|
||||
int result = signed_bit_to_int(val, adc_efuse_raw_map[tag].length);
|
||||
ESP_EARLY_LOGV(RTC_TBL_LOG_TAG, "Fetching raw for tag %d @blk%d bit%d len%d: %d", tag, adc_efuse_raw_map[tag].block, adc_efuse_raw_map[tag].begin_bit, adc_efuse_raw_map[tag].length,
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int esp_efuse_rtc_table_get_parsed_efuse_value(int tag, bool skip_efuse_reading)
|
||||
{
|
||||
assert(tag >= 0);
|
||||
if (tag == 0) {
|
||||
return 0; // tag 0 is the dummy tag and has no value. (used by depends)
|
||||
}
|
||||
|
||||
int efuse_val = 0;
|
||||
if (!skip_efuse_reading) {
|
||||
efuse_val = esp_efuse_rtc_table_get_raw_efuse_value(tag) * adc_efuse_raw_map[tag].multiplier;
|
||||
}
|
||||
int result = efuse_val + adc_efuse_raw_map[tag].base +
|
||||
esp_efuse_rtc_table_get_parsed_efuse_value(adc_efuse_raw_map[tag].depends, skip_efuse_reading);
|
||||
|
||||
ESP_EARLY_LOGV(RTC_TBL_LOG_TAG, "Parsed efuse val for tag %d: %d", tag, result);
|
||||
return result;
|
||||
}
|
@ -68,7 +68,7 @@ esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr,
|
||||
if ((bits_counter + num_bits) > req_size) { // Limits the length of the field.
|
||||
num_bits = req_size - bits_counter;
|
||||
}
|
||||
ESP_LOGD(TAG, "In EFUSE_BLK%d__DATA%d_REG is used %d bits starting with %d bit",
|
||||
ESP_EARLY_LOGD(TAG, "In EFUSE_BLK%d__DATA%d_REG is used %d bits starting with %d bit",
|
||||
(int)field[i]->efuse_block, num_reg, num_bits, start_bit);
|
||||
err = func_proc(num_reg, field[i]->efuse_block, start_bit, num_bits, ptr, &bits_counter);
|
||||
++i_reg;
|
||||
|
@ -20,166 +20,94 @@
|
||||
#include "assert.h"
|
||||
#include "esp_adc_cal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp32s2/esp_efuse_rtc_table.h"
|
||||
#include "hal/adc_hal.h"
|
||||
|
||||
#define ADC_CAL_CHECK(cond, ret) ({ \
|
||||
if(!(cond)){ \
|
||||
return ret; \
|
||||
} \
|
||||
})
|
||||
const static char LOG_TAG[] = "adc_calib";
|
||||
|
||||
/* ------------------------ Characterization Constants ---------------------- */
|
||||
#define ADC_CHAR_VERSION1_EFUSEVAL 1
|
||||
|
||||
static const uint32_t adc1_D_mean_low[] = {2231, 1643, 1290, 701};
|
||||
static const uint32_t adc2_D_mean_low[] = {2305, 1693, 1343, 723};
|
||||
static const uint32_t adc1_D_mean_high[] = {5775, 5692, 5725, 6209};
|
||||
static const uint32_t adc2_D_mean_high[] = {5817, 5703, 5731, 6157};
|
||||
|
||||
static const int Dlow_data_length = 6;
|
||||
static const int Dhigh_data_length = 8;
|
||||
|
||||
static const int adc_efuse_block = 2;
|
||||
static const int adc_calib_ver_block = 2;
|
||||
static const int adc_calib_ver_word_loc = 4;
|
||||
static const int adc_calib_ver_offset = 4;
|
||||
static const int adc_calib_ver_len = 3;
|
||||
|
||||
static const int adc1_atten0_Dlow_word_loc = 6;
|
||||
static const int adc2_atten0_Dlow_word_loc = 7;
|
||||
static const int adc1_atten0_Dhigh_word_loc = 4;
|
||||
static const int adc2_atten0_Dhigh_word_loc = 5;
|
||||
|
||||
static const int adc1_atten0_Dlow_offset = 16;
|
||||
static const int adc2_atten0_Dlow_offset = 8;
|
||||
static const int adc1_atten0_Dhigh_offset = 16;
|
||||
static const int adc2_atten0_Dhigh_offset = 16;
|
||||
/* ----------------------- EFuse Access Functions --------------------------- */
|
||||
/**
|
||||
* Convenience function that reads a few bits from efuse and assembles them.
|
||||
* For example, if the contents of the EFuse are:
|
||||
* Word2: 0x1234 Word3:0x5678
|
||||
* Then, setting base=2, offset=24, len=24 will yield 0x456.
|
||||
* @note does not check for boundaries, make sure parameters are correct
|
||||
* @param blk EFuse Block
|
||||
* @param base the starting word
|
||||
* @param offset the bit offset in the starting word
|
||||
* @param bit how many consecutive bits to fetch
|
||||
* @return the assembled number
|
||||
*/
|
||||
static uint32_t get_consecutive_bits_from_blk(int blk, uint32_t base, int offset, int len)
|
||||
{
|
||||
|
||||
base += offset / 32;
|
||||
offset %= 32;
|
||||
if (offset + len <= 32 || base == 7) {
|
||||
uint32_t result = esp_efuse_read_reg(blk, base);
|
||||
result <<= (32 - offset - len);
|
||||
result >>= (32 - len);
|
||||
return result;
|
||||
} else {
|
||||
// need to fetch both bytes.
|
||||
uint64_t result = ((uint64_t)esp_efuse_read_reg(blk, base + 1) << 32) + esp_efuse_read_reg(blk, base);
|
||||
result &= ((uint64_t)1 << (offset + len)) - 1;
|
||||
result >>= offset;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To save space in EFuse, the calibration values for adc are compressed.
|
||||
* The compression scheme is: for X bits of ADC Efuse data,
|
||||
* The actual ADC reading is: BASE_VALUE + 4*ADC_OFFSET
|
||||
* where ADC_OFFSET = bits X-1:0 in Efuse, the highest bit is the sign bit (0:+, 1:-).
|
||||
*
|
||||
* The following functions do this conversion.
|
||||
* @param efuse_val raw values read from efuse.
|
||||
* @param adc_num Specifies the channel number. The 2 adc channels each have different calibration values.
|
||||
* @param attem Specifies the attenuation. Different attenuation level have different calibration values.
|
||||
*/
|
||||
static uint32_t efuse_low_val_to_d(uint16_t efuse_val, adc_unit_t adc_num, adc_atten_t atten)
|
||||
{
|
||||
// efuse_val is 5 bits + 6th sign bit.
|
||||
int32_t rawoffsetval = efuse_val & ((1 << (Dlow_data_length - 1)) - 1);
|
||||
// if the sign bit is 1, it means it is a negative sign.
|
||||
int32_t offset = (efuse_val & (1 << (Dlow_data_length - 1))) ? (-rawoffsetval * 4) : (rawoffsetval * 4);
|
||||
if (adc_num == ADC_UNIT_1) {
|
||||
return offset + adc1_D_mean_low[atten - ADC_ATTEN_DB_0];
|
||||
} else {
|
||||
return offset + adc2_D_mean_low[atten - ADC_ATTEN_DB_0];
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t efuse_high_val_to_d (uint16_t efuse_val, adc_unit_t adc_num, adc_atten_t atten)
|
||||
{
|
||||
// efuse_val is 7 bits + 8th sign bit.
|
||||
int32_t rawoffsetval = efuse_val & ((1 << (Dhigh_data_length - 1)) - 1);
|
||||
int32_t offset = (efuse_val & (1 << (Dhigh_data_length - 1))) ? (-rawoffsetval * 4) : (rawoffsetval * 4);
|
||||
if (adc_num == ADC_UNIT_1) {
|
||||
return offset + adc1_D_mean_high[atten - ADC_ATTEN_DB_0];
|
||||
} else {
|
||||
return offset + adc2_D_mean_high[atten - ADC_ATTEN_DB_0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* To save space in EFuse, the calibration values for adc are compressed.
|
||||
* The compression scheme is: for X bits of ADC Efuse data,
|
||||
* The actual ADC reading is: BASE_VALUE + 4*ADC_OFFSET
|
||||
* where ADC_OFFSET = bits X-1:0 in Efuse, the highest bit is the sign bit (0:+, 1:-).
|
||||
*
|
||||
* The following functions do the reading.
|
||||
* @param efuse_val raw values read from efuse.
|
||||
* @param adc_num Specifies the channel number. The 2 adc channels each have different calibration values.
|
||||
* @param attem Specifies the attenuation. Different attenuation level have different calibration values.
|
||||
*/
|
||||
static uint32_t read_efuse_tp_low(adc_unit_t adc_num, adc_atten_t atten)
|
||||
{
|
||||
// this fcn retrieves and decodes the calibration value stored in efuse.
|
||||
uint32_t base;
|
||||
int offset;
|
||||
// may need to move magic numbers out
|
||||
if (adc_num == ADC_UNIT_1) {
|
||||
// the first value is at the 16th bit of the 6th word of the efuse block 2, each value is 6 bits long.
|
||||
base = adc1_atten0_Dlow_word_loc;
|
||||
offset = adc1_atten0_Dlow_offset + Dlow_data_length * (atten - ADC_ATTEN_DB_0);
|
||||
|
||||
} else {
|
||||
// the first value is at the 8th bit of the 7th word of the efuse block 2, each value is 6 bits long.
|
||||
base = adc2_atten0_Dlow_word_loc;
|
||||
offset = adc2_atten0_Dlow_offset + Dlow_data_length * (atten - ADC_ATTEN_DB_0);
|
||||
}
|
||||
uint32_t read_result = get_consecutive_bits_from_blk(adc_efuse_block, base, offset, Dlow_data_length);
|
||||
return read_result;
|
||||
}
|
||||
|
||||
static uint32_t read_efuse_tp_high(adc_unit_t adc_num, adc_atten_t atten)
|
||||
{
|
||||
// this fcn retrieves and decodes the calibration value stored in efuse.
|
||||
uint32_t base;
|
||||
int offset;
|
||||
|
||||
if (adc_num == ADC_UNIT_1) {
|
||||
// the first value is at the 16th bit of the 4th word of the efuse block 2, each value is 8 bits long.
|
||||
base = adc1_atten0_Dhigh_word_loc;
|
||||
offset = adc1_atten0_Dhigh_offset + Dhigh_data_length * (atten - ADC_ATTEN_DB_0);
|
||||
|
||||
} else {
|
||||
// the first value is at the 16th bit of the 5th word of the efuse block 2, each value is 8 bits long.
|
||||
base = adc2_atten0_Dhigh_word_loc;
|
||||
offset = adc2_atten0_Dhigh_offset + Dhigh_data_length * (atten - ADC_ATTEN_DB_0);
|
||||
}
|
||||
uint32_t read_result = get_consecutive_bits_from_blk(adc_efuse_block, base, offset, Dhigh_data_length);
|
||||
return read_result;
|
||||
}
|
||||
|
||||
/* ----------------------- Characterization Functions ----------------------- */
|
||||
|
||||
// coeff_a and coeff_b are actually floats
|
||||
// they are scaled to put them into uint32_t so that the headers do not have to be changed
|
||||
static const int coeff_a_scaling = 65536;
|
||||
static const int coeff_b_scaling = 1024;
|
||||
/* -------------------- Characterization Helper Data Types ------------------ */
|
||||
typedef struct {
|
||||
int adc_calib_high;
|
||||
int adc_calib_low;
|
||||
} adc_calib_data_ver1;
|
||||
|
||||
typedef struct {
|
||||
int adc_calib_high; // the reading of adc ...
|
||||
int adc_calib_high_voltage; // ... at this voltage (mV)
|
||||
} adc_calib_data_ver2;
|
||||
|
||||
typedef struct {
|
||||
char version_num;
|
||||
adc_unit_t adc_num;
|
||||
adc_atten_t atten_level;
|
||||
union {
|
||||
adc_calib_data_ver1 ver1;
|
||||
adc_calib_data_ver2 ver2;
|
||||
} efuse_data;
|
||||
} adc_calib_parsed_info;
|
||||
|
||||
static bool prepare_calib_data_for(adc_unit_t adc_num, adc_atten_t atten, adc_calib_parsed_info *parsed_data_storage)
|
||||
{
|
||||
int version_num = esp_efuse_rtc_table_read_calib_version();
|
||||
int tag;
|
||||
parsed_data_storage->version_num = version_num;
|
||||
parsed_data_storage->adc_num = adc_num;
|
||||
parsed_data_storage->atten_level = atten;
|
||||
switch (version_num) {
|
||||
case 1:
|
||||
// note: use the adc_num as in hal, which start from 0.
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VLOW);
|
||||
parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VHIGH);
|
||||
parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
|
||||
break;
|
||||
case 2:
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V2_PARAM_VHIGH);
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
|
||||
switch (parsed_data_storage->atten_level) {
|
||||
case ADC_ATTEN_DB_0:
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 600;
|
||||
break;
|
||||
case ADC_ATTEN_DB_2_5:
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 800;
|
||||
break;
|
||||
case ADC_ATTEN_DB_6:
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 1000;
|
||||
break;
|
||||
case ADC_ATTEN_DB_11:
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 2000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// fall back to case 1 with zeros as params.
|
||||
parsed_data_storage->version_num = 1;
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VLOW);
|
||||
parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true);
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VHIGH);
|
||||
parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ----------------------- Characterization Functions ----------------------- */
|
||||
/**
|
||||
* (Used in V1 of calibration scheme)
|
||||
* The Two Point calibration measures the reading at two specific input voltages, and calculates the (assumed linear) relation
|
||||
* between input voltage and ADC response. (Response = A * Vinput + B)
|
||||
* A and B are scaled ints.
|
||||
@ -202,6 +130,32 @@ static void characterize_using_two_point(adc_unit_t adc_num,
|
||||
*coeff_b = coeff_b_scaling * (v_low * high - v_high[atten] * low) / (high - low);
|
||||
}
|
||||
|
||||
/*
|
||||
* Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
|
||||
* with the previously done measurement when the chip was manufactured.
|
||||
* */
|
||||
static bool calculate_characterization_coefficients(const adc_calib_parsed_info *parsed_data, esp_adc_cal_characteristics_t *chars)
|
||||
{
|
||||
switch (parsed_data->version_num) {
|
||||
case 1:
|
||||
ESP_LOGD(LOG_TAG, "Calib V1, low%dmV, high%dmV\n", parsed_data->efuse_data.ver1.adc_calib_low, parsed_data->efuse_data.ver1.adc_calib_high);
|
||||
|
||||
characterize_using_two_point(parsed_data->adc_num, parsed_data->atten_level,
|
||||
parsed_data->efuse_data.ver1.adc_calib_high, parsed_data->efuse_data.ver1.adc_calib_low,
|
||||
&(chars->coeff_a), &(chars->coeff_b));
|
||||
break;
|
||||
case 2:
|
||||
ESP_LOGD(LOG_TAG, "Calib V2, volt%dmV\n", parsed_data->efuse_data.ver2.adc_calib_high);
|
||||
chars->coeff_a = coeff_a_scaling * parsed_data->efuse_data.ver2.adc_calib_high_voltage /
|
||||
parsed_data->efuse_data.ver2.adc_calib_high;
|
||||
chars->coeff_b = 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------- Public API ------------------------------------- */
|
||||
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
|
||||
@ -209,14 +163,9 @@ esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
|
||||
if (source != ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
uint8_t adc1_atten0_dh = get_consecutive_bits_from_blk(adc_efuse_block, adc1_atten0_Dhigh_word_loc, adc1_atten0_Dhigh_offset, Dhigh_data_length);
|
||||
uint8_t adc2_atten0_dh = get_consecutive_bits_from_blk(adc_efuse_block, adc2_atten0_Dhigh_word_loc, adc2_atten0_Dhigh_offset, Dhigh_data_length);
|
||||
if (!adc1_atten0_dh || !adc2_atten0_dh) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
uint8_t adc_encoding_version = get_consecutive_bits_from_blk(adc_calib_ver_block, adc_calib_ver_word_loc, adc_calib_ver_offset, adc_calib_ver_len);
|
||||
if (adc_encoding_version != 1) {
|
||||
// current version only accepts encoding ver 1.
|
||||
uint8_t adc_encoding_version = esp_efuse_rtc_table_read_calib_version();
|
||||
if (adc_encoding_version != 1 && adc_encoding_version != 2) {
|
||||
// current version only accepts encoding ver 1 and ver 2.
|
||||
return ESP_ERR_INVALID_VERSION;
|
||||
}
|
||||
return ESP_OK;
|
||||
@ -228,24 +177,20 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
|
||||
uint32_t default_vref,
|
||||
esp_adc_cal_characteristics_t *chars)
|
||||
{
|
||||
bool res;
|
||||
adc_calib_parsed_info efuse_parsed_data = {0};
|
||||
// Check parameters
|
||||
assert((adc_num == ADC_UNIT_1) || (adc_num == ADC_UNIT_2));
|
||||
assert(chars != NULL);
|
||||
assert(bit_width == ADC_WIDTH_BIT_13);
|
||||
|
||||
// Characterize based on efuse Two Point values. If these values are not present in efuse,
|
||||
// or efuse values are of a version that we do not recognize, automatically assume default values.
|
||||
uint32_t adc_calib_high, adc_calib_low;
|
||||
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
|
||||
adc_calib_high = read_efuse_tp_high(adc_num, atten);
|
||||
adc_calib_low = read_efuse_tp_low(adc_num, atten);
|
||||
} else {
|
||||
adc_calib_high = 0;
|
||||
adc_calib_low = 0;
|
||||
}
|
||||
uint32_t high = efuse_high_val_to_d(adc_calib_high, adc_num, atten);
|
||||
uint32_t low = efuse_low_val_to_d(adc_calib_low, adc_num, atten);
|
||||
characterize_using_two_point(adc_num, atten, high, low, &(chars->coeff_a), &(chars->coeff_b));
|
||||
// make sure adc is calibrated.
|
||||
res = prepare_calib_data_for(adc_num, atten, &efuse_parsed_data);
|
||||
assert(res);
|
||||
res = calculate_characterization_coefficients(&efuse_parsed_data, chars);
|
||||
assert(res);
|
||||
ESP_LOGD(LOG_TAG, "adc%d (atten leven %d) calibration done: A:%d B:%d\n", adc_num, atten, chars->coeff_a, chars->coeff_b);
|
||||
|
||||
// Initialize remaining fields
|
||||
chars->adc_num = adc_num;
|
||||
chars->atten = atten;
|
||||
|
@ -56,6 +56,8 @@ typedef struct {
|
||||
* burned to the eFuse of the current ESP32
|
||||
*
|
||||
* @param value_type Type of calibration value (ESP_ADC_CAL_VAL_EFUSE_VREF or ESP_ADC_CAL_VAL_EFUSE_TP)
|
||||
* @note in ESP32S2, only ESP_ADC_CAL_VAL_EFUSE_TP is supported. Some old ESP32S2s do not support this, either.
|
||||
* In which case you have to calibrate it manually, possibly by performing your own two-point calibration on the chip.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: The calibration mode is supported in eFuse
|
||||
|
@ -9,6 +9,7 @@ idf_component_register(SRCS "compare_set.c"
|
||||
"cpu_util.c"
|
||||
INCLUDE_DIRS include
|
||||
REQUIRES ${requires}
|
||||
PRIV_REQUIRES efuse
|
||||
LDFRAGMENTS linker.lf)
|
||||
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
@ -37,3 +37,10 @@
|
||||
#define I2C_ULP_BG_O_DONE_FLAG 3
|
||||
#define I2C_ULP_BG_O_DONE_FLAG_MSB 3
|
||||
#define I2C_ULP_BG_O_DONE_FLAG_LSB 3
|
||||
|
||||
#define I2C_ULP_OCODE_ADDR 6
|
||||
#define I2C_ULP_OCODE_ADDR_MSB 7
|
||||
#define I2C_ULP_OCODE_ADDR_LSB 0
|
||||
#define I2C_ULP_IR_FORCE_CODE_ADDR 5
|
||||
#define I2C_ULP_IR_FORCE_CODE_ADDR_MSB 6
|
||||
#define I2C_ULP_IR_FORCE_CODE_ADDR_LSB 6
|
||||
|
@ -21,9 +21,11 @@
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "soc/extmem_reg.h"
|
||||
#include "regi2c_ulp.h"
|
||||
#include "regi2c_ctrl.h"
|
||||
#include "soc_log.h"
|
||||
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
static const char *TAG = "rtc_init";
|
||||
|
||||
void rtc_init(rtc_config_t cfg)
|
||||
@ -146,55 +148,73 @@ void rtc_init(rtc_config_t cfg)
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_NOISO);
|
||||
}
|
||||
if (cfg.cali_ocode)
|
||||
{
|
||||
/*
|
||||
Bangap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration(must close PLL).
|
||||
Method:
|
||||
1. read current cpu config, save in old_config;
|
||||
2. switch cpu to xtal because PLL will be closed when o-code calibration;
|
||||
3. begin o-code calibration;
|
||||
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
|
||||
5. set cpu to old-config.
|
||||
*/
|
||||
rtc_slow_freq_t slow_clk_freq = rtc_clk_slow_freq_get();
|
||||
rtc_slow_freq_t rtc_slow_freq_x32k = RTC_SLOW_FREQ_32K_XTAL;
|
||||
rtc_slow_freq_t rtc_slow_freq_8MD256 = RTC_SLOW_FREQ_8MD256;
|
||||
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
|
||||
if (slow_clk_freq == (rtc_slow_freq_x32k)) {
|
||||
cal_clk = RTC_CAL_32K_XTAL;
|
||||
} else if (slow_clk_freq == rtc_slow_freq_8MD256) {
|
||||
cal_clk = RTC_CAL_8MD256;
|
||||
}
|
||||
|
||||
uint64_t max_delay_time_us = 10000;
|
||||
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
|
||||
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
|
||||
uint64_t cycle0 = rtc_time_get();
|
||||
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
|
||||
uint64_t cycle1 = 0;
|
||||
|
||||
rtc_cpu_freq_config_t old_config;
|
||||
rtc_clk_cpu_freq_get_config(&old_config);
|
||||
rtc_clk_cpu_freq_set_xtal();
|
||||
|
||||
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0);
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1);
|
||||
bool odone_flag = 0;
|
||||
bool bg_odone_flag = 0;
|
||||
while(1) {
|
||||
odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG);
|
||||
bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG);
|
||||
cycle1 = rtc_time_get();
|
||||
if (odone_flag && bg_odone_flag)
|
||||
break;
|
||||
if (cycle1 >= timeout_cycle) {
|
||||
SOC_LOGW(TAG, "o_code calibration fail");
|
||||
break;
|
||||
if (cfg.cali_ocode) {
|
||||
uint32_t rtc_calib_version = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_BLOCK2_VERSION, &rtc_calib_version, 32);
|
||||
if (rtc_calib_version == 2) {
|
||||
// use efuse ocode.
|
||||
uint32_t ocode1 = 0;
|
||||
uint32_t ocode2 = 0;
|
||||
uint32_t ocode;
|
||||
esp_efuse_read_block(2, &ocode1, 16*8, 4);
|
||||
esp_efuse_read_block(2, &ocode2, 18*8, 3);
|
||||
ocode = (ocode2 << 4) + ocode1;
|
||||
if (ocode >> 6) {
|
||||
ocode = 93 - (ocode ^ (1 << 6));
|
||||
} else {
|
||||
ocode = 93 + ocode;
|
||||
}
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_OCODE_ADDR, ocode);
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_CODE_ADDR, 1);
|
||||
} else {
|
||||
/*
|
||||
Bangap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration(must close PLL).
|
||||
Method:
|
||||
1. read current cpu config, save in old_config;
|
||||
2. switch cpu to xtal because PLL will be closed when o-code calibration;
|
||||
3. begin o-code calibration;
|
||||
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
|
||||
5. set cpu to old-config.
|
||||
*/
|
||||
rtc_slow_freq_t slow_clk_freq = rtc_clk_slow_freq_get();
|
||||
rtc_slow_freq_t rtc_slow_freq_x32k = RTC_SLOW_FREQ_32K_XTAL;
|
||||
rtc_slow_freq_t rtc_slow_freq_8MD256 = RTC_SLOW_FREQ_8MD256;
|
||||
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
|
||||
if (slow_clk_freq == (rtc_slow_freq_x32k)) {
|
||||
cal_clk = RTC_CAL_32K_XTAL;
|
||||
} else if (slow_clk_freq == rtc_slow_freq_8MD256) {
|
||||
cal_clk = RTC_CAL_8MD256;
|
||||
}
|
||||
|
||||
uint64_t max_delay_time_us = 10000;
|
||||
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
|
||||
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
|
||||
uint64_t cycle0 = rtc_time_get();
|
||||
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
|
||||
uint64_t cycle1 = 0;
|
||||
|
||||
rtc_cpu_freq_config_t old_config;
|
||||
rtc_clk_cpu_freq_get_config(&old_config);
|
||||
rtc_clk_cpu_freq_set_xtal();
|
||||
|
||||
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0);
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1);
|
||||
bool odone_flag = 0;
|
||||
bool bg_odone_flag = 0;
|
||||
while(1) {
|
||||
odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG);
|
||||
bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG);
|
||||
cycle1 = rtc_time_get();
|
||||
if (odone_flag && bg_odone_flag)
|
||||
break;
|
||||
if (cycle1 >= timeout_cycle) {
|
||||
SOC_LOGW(TAG, "o_code calibration fail");
|
||||
break;
|
||||
}
|
||||
}
|
||||
rtc_clk_cpu_freq_set_config(&old_config);
|
||||
}
|
||||
rtc_clk_cpu_freq_set_config(&old_config);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "hal/adc_hal.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal_conf.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp32s2/esp_efuse_rtc_table.h"
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital controller setting
|
||||
@ -189,13 +191,6 @@ uint32_t adc_hal_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atte
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t code_list[ADC_HAL_CAL_TIMES] = {0};
|
||||
uint32_t code_sum = 0;
|
||||
uint32_t code_h = 0;
|
||||
uint32_t code_l = 0;
|
||||
uint32_t chk_code = 0;
|
||||
uint32_t dout = 0;
|
||||
|
||||
adc_hal_set_power_manage(ADC_POWER_SW_ON);
|
||||
if (adc_n == ADC_NUM_2) {
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
@ -206,56 +201,71 @@ uint32_t adc_hal_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atte
|
||||
// adc_hal_arbiter_config(adc_arbiter_t *config)
|
||||
adc_ll_calibration_prepare(adc_n, channel, internal_gnd);
|
||||
|
||||
/* Enable/disable internal connect GND (for calibration). */
|
||||
if (internal_gnd) {
|
||||
adc_ll_rtc_disable_channel(adc_n, channel);
|
||||
adc_ll_set_atten(adc_n, 0, atten); // Note: when disable all channel, HW auto select channel0 atten param.
|
||||
uint32_t dout = 0;
|
||||
// check if we can fetch the values from eFuse.
|
||||
int version = esp_efuse_rtc_table_read_calib_version();
|
||||
if (version == 2) {
|
||||
int tag = esp_efuse_rtc_table_get_tag(version, adc_n + 1, atten, RTCCALIB_V2_PARAM_VINIT);
|
||||
dout = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
|
||||
} else {
|
||||
adc_ll_rtc_enable_channel(adc_n, channel);
|
||||
adc_ll_set_atten(adc_n, channel, atten);
|
||||
}
|
||||
uint32_t code_list[ADC_HAL_CAL_TIMES] = {0};
|
||||
uint32_t code_sum = 0;
|
||||
uint32_t code_h = 0;
|
||||
uint32_t code_l = 0;
|
||||
uint32_t chk_code = 0;
|
||||
|
||||
for (uint8_t rpt = 0 ; rpt < ADC_HAL_CAL_TIMES ; rpt ++) {
|
||||
code_h = ADC_HAL_CAL_OFFSET_RANGE;
|
||||
code_l = 0;
|
||||
chk_code = (code_h + code_l) / 2;
|
||||
adc_ll_set_calibration_param(adc_n, chk_code);
|
||||
dout = adc_hal_read_self_cal(adc_n, channel);
|
||||
while (code_h - code_l > 1) {
|
||||
if (dout == 0) {
|
||||
code_h = chk_code;
|
||||
} else {
|
||||
code_l = chk_code;
|
||||
}
|
||||
/* Enable/disable internal connect GND (for calibration). */
|
||||
if (internal_gnd) {
|
||||
adc_ll_rtc_disable_channel(adc_n, channel);
|
||||
adc_ll_set_atten(adc_n, 0, atten); // Note: when disable all channel, HW auto select channel0 atten param.
|
||||
} else {
|
||||
adc_ll_rtc_enable_channel(adc_n, channel);
|
||||
adc_ll_set_atten(adc_n, channel, atten);
|
||||
}
|
||||
|
||||
for (uint8_t rpt = 0 ; rpt < ADC_HAL_CAL_TIMES ; rpt ++) {
|
||||
code_h = ADC_HAL_CAL_OFFSET_RANGE;
|
||||
code_l = 0;
|
||||
chk_code = (code_h + code_l) / 2;
|
||||
adc_ll_set_calibration_param(adc_n, chk_code);
|
||||
dout = adc_hal_read_self_cal(adc_n, channel);
|
||||
if ((code_h - code_l == 1)) {
|
||||
chk_code += 1;
|
||||
while (code_h - code_l > 1) {
|
||||
if (dout == 0) {
|
||||
code_h = chk_code;
|
||||
} else {
|
||||
code_l = chk_code;
|
||||
}
|
||||
chk_code = (code_h + code_l) / 2;
|
||||
adc_ll_set_calibration_param(adc_n, chk_code);
|
||||
dout = adc_hal_read_self_cal(adc_n, channel);
|
||||
if ((code_h - code_l == 1)) {
|
||||
chk_code += 1;
|
||||
adc_ll_set_calibration_param(adc_n, chk_code);
|
||||
dout = adc_hal_read_self_cal(adc_n, channel);
|
||||
}
|
||||
}
|
||||
code_list[rpt] = chk_code;
|
||||
code_sum += chk_code;
|
||||
}
|
||||
code_l = code_list[0];
|
||||
code_h = code_list[0];
|
||||
for (uint8_t i = 0 ; i < ADC_HAL_CAL_TIMES ; i++) {
|
||||
if (code_l > code_list[i]) {
|
||||
code_l = code_list[i];
|
||||
}
|
||||
if (code_h < code_list[i]) {
|
||||
code_h = code_list[i];
|
||||
}
|
||||
}
|
||||
code_list[rpt] = chk_code;
|
||||
code_sum += chk_code;
|
||||
}
|
||||
code_l = code_list[0];
|
||||
code_h = code_list[0];
|
||||
for (uint8_t i = 0 ; i < ADC_HAL_CAL_TIMES ; i++) {
|
||||
if (code_l > code_list[i]) {
|
||||
code_l = code_list[i];
|
||||
}
|
||||
if (code_h < code_list[i]) {
|
||||
code_h = code_list[i];
|
||||
}
|
||||
}
|
||||
chk_code = code_h + code_l;
|
||||
dout = ((code_sum - chk_code) % (ADC_HAL_CAL_TIMES - 2) < 4)
|
||||
? (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2)
|
||||
: (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2) + 1;
|
||||
chk_code = code_h + code_l;
|
||||
dout = ((code_sum - chk_code) % (ADC_HAL_CAL_TIMES - 2) < 4)
|
||||
? (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2)
|
||||
|
||||
: (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2) + 1;
|
||||
}
|
||||
adc_ll_set_calibration_param(adc_n, dout);
|
||||
adc_ll_calibration_finish(adc_n);
|
||||
s_adc_cali_param[adc_n][atten] = (uint16_t)dout;
|
||||
|
||||
return dout;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user