diff --git a/components/esp32s2/clk.c b/components/esp32s2/clk.c index 49b8ec135..4d2eb5c46 100644 --- a/components/esp32s2/clk.c +++ b/components/esp32s2/clk.c @@ -79,6 +79,11 @@ static const char *TAG = "clk"; void esp_clk_init(void) { rtc_config_t cfg = RTC_CONFIG_DEFAULT(); + RESET_REASON rst_reas; + rst_reas = rtc_get_reset_reason(0); + if (rst_reas == POWERON_RESET) { + cfg.cali_ocode = 1; + } rtc_init(cfg); assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M); diff --git a/components/soc/soc/esp32s2/i2c_ulp.h b/components/soc/soc/esp32s2/i2c_ulp.h new file mode 100644 index 000000000..e7f4afa08 --- /dev/null +++ b/components/soc/soc/esp32s2/i2c_ulp.h @@ -0,0 +1,39 @@ +// Copyright 2015-2017 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 + +/** + * @file i2c_ulp.h + * @brief Register definitions for analog to calibrate o_code for getting a more precise voltage. + * + * This file lists register fields of ULP, located on an internal configuration + * bus. These definitions are used via macros defined in i2c_rtc_clk.h, by + * rtc_init function in rtc_init.c. + */ + +#define I2C_ULP 0x61 +#define I2C_ULP_HOSTID 1 + +#define I2C_ULP_IR_RESETB 0 +#define I2C_ULP_IR_RESETB_MSB 0 +#define I2C_ULP_IR_RESETB_LSB 0 + +#define I2C_ULP_O_DONE_FLAG 3 +#define I2C_ULP_O_DONE_FLAG_MSB 0 +#define I2C_ULP_O_DONE_FLAG_LSB 0 + +#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 \ No newline at end of file diff --git a/components/soc/soc/esp32s2/include/soc/rtc.h b/components/soc/soc/esp32s2/include/soc/rtc.h index 2c27bd670..5f30be6d2 100644 --- a/components/soc/soc/esp32s2/include/soc/rtc.h +++ b/components/soc/soc/esp32s2/include/soc/rtc.h @@ -751,6 +751,7 @@ typedef struct { uint32_t xtal_fpu : 1; uint32_t bbpll_fpu : 1; uint32_t cpu_waiti_clk_gate : 1; + uint32_t cali_ocode : 1; //!< Calibrate Ocode to make bangap voltage more precise. } rtc_config_t; /** @@ -768,7 +769,8 @@ typedef struct { .rtc_dboost_fpd = 1, \ .xtal_fpu = 0, \ .bbpll_fpu = 0, \ - .cpu_waiti_clk_gate = 1\ + .cpu_waiti_clk_gate = 1, \ + .cali_ocode = 0\ } /** diff --git a/components/soc/src/esp32s2/i2c_rtc_clk.h b/components/soc/src/esp32s2/i2c_rtc_clk.h index 3bc445a31..0fff0eb07 100644 --- a/components/soc/src/esp32s2/i2c_rtc_clk.h +++ b/components/soc/src/esp32s2/i2c_rtc_clk.h @@ -16,6 +16,7 @@ #include "i2c_apll.h" #include "i2c_bbpll.h" +#include "i2c_ulp.h" #ifdef __cplusplus extern "C" { diff --git a/components/soc/src/esp32s2/rtc_init.c b/components/soc/src/esp32s2/rtc_init.c index 0aef6cc9a..fa7a7aa67 100644 --- a/components/soc/src/esp32s2/rtc_init.c +++ b/components/soc/src/esp32s2/rtc_init.c @@ -22,6 +22,9 @@ #include "soc/spi_mem_reg.h" #include "soc/extmem_reg.h" #include "i2c_rtc_clk.h" +#include "soc_log.h" + +static const char *TAG = "rtc_init"; void rtc_init(rtc_config_t cfg) { @@ -143,6 +146,56 @@ 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(); + + + I2C_WRITEREG_MASK_RTC(I2C_ULP, I2C_ULP_IR_RESETB, 0); + I2C_WRITEREG_MASK_RTC(I2C_ULP, I2C_ULP_IR_RESETB, 1); + bool odone_flag = 0; + bool bg_odone_flag = 0; + while(1) { + odone_flag = I2C_READREG_MASK_RTC(I2C_ULP, I2C_ULP_O_DONE_FLAG); + bg_odone_flag = I2C_READREG_MASK_RTC(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_vddsdio_config_t rtc_vddsdio_get_config(void) diff --git a/components/soc/src/esp32s2/rtc_sleep.c b/components/soc/src/esp32s2/rtc_sleep.c index 8a037e36b..b0ceeb79c 100644 --- a/components/soc/src/esp32s2/rtc_sleep.c +++ b/components/soc/src/esp32s2/rtc_sleep.c @@ -107,6 +107,7 @@ void rtc_sleep_init(rtc_sleep_config_t cfg) RTC_CNTL_CKGEN_I2C_PU | RTC_CNTL_PLL_I2C_PU | RTC_CNTL_RFRX_PBUS_PU | RTC_CNTL_TXRF_I2C_PU); } else { + SET_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_REGULATOR_FORCE_PU); CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_DG_WRAP_PD_EN); REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN_DEEP_SLP, RTC_CNTL_DBG_ATTEN_LIGHTSLEEP_DEFAULT); }