adjust lightsleep overhead time and cali slowclk

This commit is contained in:
ninh 2020-11-06 17:28:57 +08:00 committed by bot
parent e908a32381
commit dc7bdb9857
9 changed files with 297 additions and 89 deletions

View File

@ -30,27 +30,20 @@
#define MHZ (1000000)
/* Various delays to be programmed into power control state machines */
#define RTC_CNTL_XTL_BUF_WAIT_SLP 2
#define RTC_CNTL_PLL_BUF_WAIT_SLP 2
#define RTC_CNTL_CK8M_WAIT_SLP 4
#define OTHER_BLOCKS_POWERUP 1
#define OTHER_BLOCKS_WAIT 1
#define ROM_RAM_POWERUP_CYCLES RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES
#define ROM_RAM_WAIT_CYCLES RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES
#define ROM_RAM_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
#define ROM_RAM_WAIT_CYCLES OTHER_BLOCKS_WAIT
#define WIFI_POWERUP_CYCLES RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES
#define WIFI_WAIT_CYCLES RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES
#define WIFI_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
#define WIFI_WAIT_CYCLES OTHER_BLOCKS_WAIT
#define RTC_POWERUP_CYCLES RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES
#define RTC_WAIT_CYCLES RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES
#define RTC_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
#define RTC_WAIT_CYCLES OTHER_BLOCKS_WAIT
#define DG_WRAP_POWERUP_CYCLES RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES
#define DG_WRAP_WAIT_CYCLES RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES
#define DG_WRAP_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
#define DG_WRAP_WAIT_CYCLES OTHER_BLOCKS_WAIT
#define RTC_MEM_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
#define RTC_MEM_WAIT_CYCLES OTHER_BLOCKS_WAIT
#define RTC_MEM_POWERUP_CYCLES RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES
#define RTC_MEM_WAIT_CYCLES RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES
/**
* @brief Power down flags for rtc_sleep_pd function
@ -101,11 +94,6 @@ static void rtc_sleep_pd(rtc_sleep_pd_config_t cfg)
void rtc_sleep_init(rtc_sleep_config_t cfg)
{
// set 5 PWC state machine times to fit in main state machine time
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, RTC_CNTL_PLL_BUF_WAIT_SLP);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, RTC_CNTL_XTL_BUF_WAIT_SLP);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_SLP);
// set shortest possible sleep time limit
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_MIN_SLP_VAL, RTC_CNTL_MIN_SLP_VAL_MIN);
@ -220,6 +208,14 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_SLP, cfg.dig_dbias_slp);
}
void rtc_sleep_low_init(uint32_t slowclk_period)
{
// set 5 PWC state machine times to fit in main state machine time
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, RTC_CNTL_PLL_BUF_WAIT_SLP_CYCLES);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, rtc_time_us_to_slowclk(RTC_CNTL_XTL_BUF_WAIT_SLP_US, slowclk_period));
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_SLP_CYCLES);
}
void rtc_sleep_set_wakeup_time(uint64_t t)
{
rtc_cntl_ll_set_wakeup_timer(t);

View File

@ -127,6 +127,13 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
REG_SET_FIELD(RTC_CNTL_SLP_REJECT_CONF_REG, RTC_CNTL_LIGHT_SLP_REJECT_EN, cfg.light_slp_reject);
}
void rtc_sleep_low_init(uint32_t slowclk_period)
{
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, RTC_CNTL_PLL_BUF_WAIT_SLP_CYCLES);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_SLP_CYCLES);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, rtc_time_us_to_slowclk(RTC_CNTL_XTL_BUF_WAIT_SLP_US, slowclk_period));
}
void rtc_sleep_set_wakeup_time(uint64_t t)
{
rtc_cntl_ll_set_wakeup_timer(t);

View File

@ -31,35 +31,13 @@
*/
/**
* @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
* @brief One-off clock calibration function used by rtc_clk_cal_internal
* @param cal_clk which clock to calibrate
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal_oneoff(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
/* On ESP32S2, choosing RTC_CAL_RTC_MUX results in calibration of
* the 90k RTC clock regardless of the currenlty selected SLOW_CLK.
* On the ESP32, it used the currently selected SLOW_CLK.
* The following code emulates ESP32 behavior:
*/
if (cal_clk == RTC_CAL_RTC_MUX) {
rtc_slow_freq_t slow_freq = rtc_clk_slow_freq_get();
if (slow_freq == RTC_SLOW_FREQ_32K_XTAL) {
cal_clk = RTC_CAL_32K_XTAL;
} else if (slow_freq == RTC_SLOW_FREQ_8MD256) {
cal_clk = RTC_CAL_8MD256;
}
}
/* Enable requested clock (150k clock is always on) */
int dig_32k_xtal_state = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_state) {
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
}
if (cal_clk == RTC_CAL_8MD256) {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
/* There may be another calibration process already running during we call this function,
@ -104,6 +82,91 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
break;
}
}
return cal_val;
}
/**
* @brief Cycling clock calibration function used by rtc_clk_cal_internal
* @param cal_clk which clock to calibrate
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
static uint32_t rtc_clk_cal_internal_cycling(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
/* Get which slowclk is in calibration and max cali cycles */
rtc_cal_sel_t in_calibration_clk;
in_calibration_clk = REG_GET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL);
uint32_t cali_slowclk_cycles = REG_GET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX);
/* If no calibration in process or calibration period equal to 0, use slowclk_cycles cycles to calibrate slowclk */
if (cali_slowclk_cycles == 0 || !GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING) || in_calibration_clk != cal_clk) {
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
SET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
cali_slowclk_cycles = slowclk_cycles;
}
/* Wait for calibration finished */
while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_CYCLING_DATA_VLD));
uint32_t cal_val = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE);
return cal_val;
}
/**
* @brief Slowclk period calculating funtion used by rtc_clk_cal and rtc_clk_cal_cycling
* @param xtal_cycles number of xtal cycles count
* @param slowclk_cycles number of slow clock cycles to count
* @return slow clock period
*/
static uint32_t rtc_clk_xtal_to_slowclk(uint64_t xtal_cycles, uint32_t slowclk_cycles)
{
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles;
uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider;
uint32_t period = (uint32_t)(period_64 & UINT32_MAX);
return period;
}
/**
* @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
* @param cal_clk which clock to calibrate
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles, uint32_t cal_mode)
{
/* On ESP32S2, choosing RTC_CAL_RTC_MUX results in calibration of
* the 90k RTC clock regardless of the currenlty selected SLOW_CLK.
* On the ESP32, it used the currently selected SLOW_CLK.
* The following code emulates ESP32 behavior:
*/
if (cal_clk == RTC_CAL_RTC_MUX) {
rtc_slow_freq_t slow_freq = rtc_clk_slow_freq_get();
if (slow_freq == RTC_SLOW_FREQ_32K_XTAL) {
cal_clk = RTC_CAL_32K_XTAL;
} else if (slow_freq == RTC_SLOW_FREQ_8MD256) {
cal_clk = RTC_CAL_8MD256;
}
}
/* Enable requested clock (150k clock is always on) */
int dig_32k_xtal_state = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_state) {
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
}
if (cal_clk == RTC_CAL_8MD256) {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
}
uint32_t cal_val;
if (cal_mode == RTC_TIME_CAL_ONEOFF_MODE) {
cal_val = rtc_clk_cal_internal_oneoff(cal_clk, slowclk_cycles);
} else {
cal_val = rtc_clk_cal_internal_cycling(cal_clk, slowclk_cycles);
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, dig_32k_xtal_state);
@ -117,7 +180,7 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles, RTC_TIME_CAL_ONEOFF_MODE);
uint64_t ratio_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT)) / slowclk_cycles;
uint32_t ratio = (uint32_t)(ratio_64 & UINT32_MAX);
return ratio;
@ -125,11 +188,15 @@ uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles;
uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider;
uint32_t period = (uint32_t)(period_64 & UINT32_MAX);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles, RTC_TIME_CAL_ONEOFF_MODE);
uint32_t period = rtc_clk_xtal_to_slowclk(xtal_cycles, slowclk_cycles);
return period;
}
uint32_t rtc_clk_cal_cycling(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles, RTC_TIME_CAL_CYCLING_MODE);
uint32_t period = rtc_clk_xtal_to_slowclk(xtal_cycles, slowclk_cycles);
return period;
}

View File

@ -136,6 +136,14 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
REG_SET_FIELD(RTC_CNTL_SLP_REJECT_CONF_REG, RTC_CNTL_LIGHT_SLP_REJECT_EN, cfg.light_slp_reject);
}
void rtc_sleep_low_init(uint32_t slowclk_period)
{
// set 5 PWC state machine times to fit in main state machine time
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, RTC_CNTL_PLL_BUF_WAIT_SLP_CYCLES);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, rtc_time_us_to_slowclk(RTC_CNTL_XTL_BUF_WAIT_SLP_US, slowclk_period));
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_SLP_CYCLES);
}
void rtc_sleep_set_wakeup_time(uint64_t t)
{
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX);

View File

@ -79,4 +79,12 @@ menu "ESP System Settings"
heap initialization order by early startup services and scheduler related code. Speed
wise RTC fast memory operates on APB clock and hence does not have much performance impact.
config ESP_SYSTEM_PD_FLASH
bool "PD flash at light sleep when there is no SPIRAM"
depends on !SPIRAM
default y
help
If enabled, chip will try to power down flash at light sleep, which costs more time when chip wakes up.
Only can be enabled if there is no SPIRAM configured.
endmenu # ESP System Settings

View File

@ -76,33 +76,32 @@
// Time from VDD_SDIO power up to first flash read in ROM code
#define VDD_SDIO_POWERUP_TO_FLASH_READ_US 700
// Cycles for RTC Timer clock source (internal oscillator) calibrate
#define RTC_CLK_SRC_CAL_CYCLES (10)
#ifdef CONFIG_IDF_TARGET_ESP32
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (212)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (60)
#elif CONFIG_IDF_TARGET_ESP32S2
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (147)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (28)
#elif CONFIG_IDF_TARGET_ESP32S3
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (0)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (0)
#elif CONFIG_IDF_TARGET_ESP32C3
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ
#endif
#if defined(CONFIG_IDF_TARGET_ESP32)
#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS)
#define LIGHT_SLEEP_TIME_OVERHEAD_US (650 + 30 * 240 / DEFAULT_CPU_FREQ_MHZ)
#define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / DEFAULT_CPU_FREQ_MHZ)
#else // CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS
#define LIGHT_SLEEP_TIME_OVERHEAD_US (250 + 30 * 240 / DEFAULT_CPU_FREQ_MHZ)
#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / DEFAULT_CPU_FREQ_MHZ)
#endif // CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#if defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS)
#define LIGHT_SLEEP_TIME_OVERHEAD_US (1650 + 30 * 240 / DEFAULT_CPU_FREQ_MHZ)
#define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / DEFAULT_CPU_FREQ_MHZ)
#else // CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS
#define LIGHT_SLEEP_TIME_OVERHEAD_US (1250 + 30 * 240 / DEFAULT_CPU_FREQ_MHZ)
#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / DEFAULT_CPU_FREQ_MHZ)
#endif // CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS
#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2)
#define LIGHT_SLEEP_TIME_OVERHEAD_US DEFAULT_HARDWARE_OUT_OVERHEAD_US
#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS) || defined (CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS)
#define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / DEFAULT_CPU_FREQ_MHZ)
#else
#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / DEFAULT_CPU_FREQ_MHZ)
#endif // defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS) || defined (CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS)
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
#ifdef CONFIG_ESP32C3_RTC_CLK_SRC_EXT_CRYS
@ -113,11 +112,10 @@
#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ)
#endif // CONFIG_ESP32C3_RTC_CLK_SRC_EXT_CRYS
#else // other target
#else // other target
#define LIGHT_SLEEP_TIME_OVERHEAD_US 0
#define DEEP_SLEEP_TIME_OVERHEAD_US 0
#endif // CONFIG_IDF_TARGET_*
#endif // CONFIG_IDF_TARGET_*
#if defined(CONFIG_IDF_TARGET_ESP32) && defined(CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY)
#define DEEP_SLEEP_WAKEUP_DELAY CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY
@ -126,7 +124,9 @@
#endif
// Minimal amount of time we can sleep for
#define LIGHT_SLEEP_MIN_TIME_US 200
#define LIGHT_SLEEP_MIN_TIME_US 200
#define RTC_MODULE_SLEEP_PREPARE_CYCLES (6)
#define CHECK_SOURCE(source, value, mask) ((s_config.wakeup_triggers & mask) && \
(source == value))
@ -143,11 +143,16 @@ typedef struct {
uint32_t ext0_trigger_level : 1;
uint32_t ext0_rtc_gpio_num : 5;
uint32_t sleep_time_adjustment;
uint32_t ccount_ticks_record;
uint32_t sleep_time_overhead_out;
uint32_t rtc_clk_cal_period;
uint64_t rtc_ticks_at_sleep_start;
} sleep_config_t;
static sleep_config_t s_config = {
.pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO },
.ccount_ticks_record = 0,
.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US,
.wakeup_triggers = 0
};
@ -344,6 +349,11 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
rtc_sleep_config_t config = RTC_SLEEP_CONFIG_DEFAULT(pd_flags);
rtc_sleep_init(config);
// Set state machine time for light sleep
if(!deep_sleep) {
rtc_sleep_low_init(s_config.rtc_clk_cal_period);
}
// Configure timer wakeup
if ((s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) &&
s_config.sleep_duration > 0) {
@ -377,6 +387,10 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
// Restore CPU frequency
rtc_clk_cpu_freq_set_config(&cpu_freq_config);
if (!deep_sleep) {
s_config.ccount_ticks_record = cpu_ll_get_cycle_count();
}
// re-enable UART output
resume_uarts();
@ -407,6 +421,8 @@ void IRAM_ATTR esp_deep_sleep_start(void)
// Decide which power domains can be powered down
uint32_t pd_flags = get_power_down_flags();
s_config.rtc_clk_cal_period = esp_clk_slowclk_cal_get();
// Correct the sleep time
s_config.sleep_time_adjustment = DEEP_SLEEP_TIME_OVERHEAD_US;
@ -458,30 +474,73 @@ esp_err_t esp_light_sleep_start(void)
* lock, otherwise there will be deadlock.
*/
esp_timer_private_lock();
s_config.rtc_ticks_at_sleep_start = rtc_time_get();
uint32_t ccount_at_sleep_start = cpu_ll_get_cycle_count();
uint64_t frc_time_at_start = esp_system_get_time();
uint32_t sleep_time_overhead_in = (ccount_at_sleep_start-s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);
DPORT_STALL_OTHER_CPU_START();
// Decide which power domains can be powered down
uint32_t pd_flags = get_power_down_flags();
// Amount of time to subtract from actual sleep time.
// This is spent on entering and leaving light sleep.
s_config.sleep_time_adjustment = LIGHT_SLEEP_TIME_OVERHEAD_US;
// Re-calibrate the RTC Timer clock
#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS) || defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS)
uint64_t time_per_us = 1000000ULL;
s_config.rtc_clk_cal_period = (time_per_us << RTC_CLK_CAL_FRACT) / rtc_clk_slow_freq_get_hz();
#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_INT_RC)
s_config.rtc_clk_cal_period = rtc_clk_cal_cycling(RTC_CAL_RTC_MUX, RTC_CLK_SRC_CAL_CYCLES);
esp_clk_slowclk_cal_set(s_config.rtc_clk_cal_period);
#else
s_config.rtc_clk_cal_period = rtc_clk_cal(RTC_CAL_RTC_MUX, RTC_CLK_SRC_CAL_CYCLES);
#endif
/*
* Adjustment time consists of parts below:
* 1. Hardware time waiting for internal 8M oscilate clock and XTAL;
* 2. Hardware state swithing time of the rtc main state machine;
* 3. Code execution time when clock is not stable;
* 4. Code execution time which can be measured;
*/
uint32_t rtc_cntl_xtl_buf_wait_slp_cycles = rtc_time_us_to_slowclk(RTC_CNTL_XTL_BUF_WAIT_SLP_US, s_config.rtc_clk_cal_period);
s_config.sleep_time_adjustment = LIGHT_SLEEP_TIME_OVERHEAD_US + sleep_time_overhead_in + s_config.sleep_time_overhead_out
+ rtc_time_slowclk_to_us(rtc_cntl_xtl_buf_wait_slp_cycles + RTC_CNTL_CK8M_WAIT_SLP_CYCLES + RTC_CNTL_WAKEUP_DELAY_CYCLES, s_config.rtc_clk_cal_period);
// Decide if VDD_SDIO needs to be powered down;
// If it needs to be powered down, adjust sleep time.
const uint32_t flash_enable_time_us = VDD_SDIO_POWERUP_TO_FLASH_READ_US + DEEP_SLEEP_WAKEUP_DELAY;
#ifndef CONFIG_SPIRAM
#if CONFIG_ESP_SYSTEM_PD_FLASH
/*
* When SPIRAM is disabled in menuconfig, the minimum sleep time of the
* system needs to meet the sum below:
* 1. Wait time for the flash power-on after waking up;
* 2. The execution time of codes between RTC Timer get start time
* with hardware starts to switch state to sleep;
* 3. The hardware state switching time of the rtc state machine during
* sleep and wake-up. This process requires 6 cycles to complete.
* The specific hardware state switching process and the cycles
* consumed are rtc_cpu_run_stall(1), cut_pll_rtl(2), cut_8m(1),
* min_protect(2);
* 4. All the adjustment time which is s_config.sleep_time_adjustment below.
*/
const uint32_t vddsdio_pd_sleep_duration = MAX(FLASH_PD_MIN_SLEEP_TIME_US,
flash_enable_time_us + LIGHT_SLEEP_TIME_OVERHEAD_US + LIGHT_SLEEP_MIN_TIME_US);
flash_enable_time_us + LIGHT_SLEEP_MIN_TIME_US + s_config.sleep_time_adjustment
+ rtc_time_slowclk_to_us(RTC_MODULE_SLEEP_PREPARE_CYCLES, s_config.rtc_clk_cal_period));
if (s_config.sleep_duration > vddsdio_pd_sleep_duration) {
pd_flags |= RTC_SLEEP_PD_VDDSDIO;
s_config.sleep_time_adjustment += flash_enable_time_us;
if (s_config.sleep_time_overhead_out < flash_enable_time_us) {
s_config.sleep_time_adjustment += flash_enable_time_us;
}
} else {
if (s_config.sleep_time_overhead_out > flash_enable_time_us) {
s_config.sleep_time_adjustment -= flash_enable_time_us;
}
}
#endif //CONFIG_SPIRAM
#endif //CONFIG_ESP_SYSTEM_PD_FLASH
rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
@ -507,8 +566,7 @@ esp_err_t esp_light_sleep_start(void)
uint64_t rtc_ticks_at_end = rtc_time_get();
uint64_t frc_time_at_end = esp_system_get_time();
uint64_t rtc_time_diff = rtc_time_slowclk_to_us(rtc_ticks_at_end - s_config.rtc_ticks_at_sleep_start,
esp_clk_slowclk_cal_get());
uint64_t rtc_time_diff = rtc_time_slowclk_to_us(rtc_ticks_at_end - s_config.rtc_ticks_at_sleep_start, s_config.rtc_clk_cal_period);
uint64_t frc_time_diff = frc_time_at_end - frc_time_at_start;
int64_t time_diff = rtc_time_diff - frc_time_diff;
@ -529,6 +587,7 @@ esp_err_t esp_light_sleep_start(void)
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
}
portEXIT_CRITICAL(&light_sleep_lock);
s_config.sleep_time_overhead_out = (cpu_ll_get_cycle_count() - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);
return err;
}
@ -594,6 +653,7 @@ esp_err_t esp_sleep_enable_ulp_wakeup(void)
esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
{
s_config.ccount_ticks_record = cpu_ll_get_cycle_count();
s_config.wakeup_triggers |= RTC_TIMER_TRIG_EN;
s_config.sleep_duration = time_in_us;
return ESP_OK;
@ -601,13 +661,12 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
static void timer_wakeup_prepare(void)
{
uint32_t period = esp_clk_slowclk_cal_get();
int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment;
if (sleep_duration < 0) {
sleep_duration = 0;
}
int64_t ticks = rtc_time_us_to_slowclk(sleep_duration, period);
int64_t ticks = rtc_time_us_to_slowclk(sleep_duration, s_config.rtc_clk_cal_period);
rtc_hal_set_wakeup_timer(s_config.rtc_ticks_at_sleep_start + ticks);
}

View File

@ -541,6 +541,14 @@ typedef struct rtc_sleep_config_s {
#define RTC_SLEEP_PD_VDDSDIO BIT(5) //!< Power down VDDSDIO regulator
#define RTC_SLEEP_PD_XTAL BIT(6) //!< Power down main XTAL
/* Various delays to be programmed into power control state machines */
#define RTC_CNTL_XTL_BUF_WAIT_SLP_US (500)
#define RTC_CNTL_PLL_BUF_WAIT_SLP_CYCLES (1)
#define RTC_CNTL_CK8M_WAIT_SLP_CYCLES (4)
#define RTC_CNTL_WAKEUP_DELAY_CYCLES (7)
#define RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES (1)
#define RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES (1)
/**
* @brief Prepare the chip to enter sleep mode
*
@ -556,6 +564,17 @@ typedef struct rtc_sleep_config_s {
*/
void rtc_sleep_init(rtc_sleep_config_t cfg);
/**
* @brief Low level initialize for rtc state machine waiting cycles after waking up
*
* This function configures the cycles chip need to wait for internal 8MHz
* oscillator and external 40MHz crystal. As we configure fixed time for waiting
* crystal, we need to pass period to calculate cycles. Now this function only
* used in lightsleep mode.
*
* @param slowclk_period re-calibrated slow clock period
*/
void rtc_sleep_low_init(uint32_t slowclk_period);
/**
* @brief Set target value of RTC counter for RTC_TIMER_TRIG_EN wakeup source

View File

@ -104,6 +104,12 @@ extern "C" {
#define RTC_CNTL_CK8M_WAIT_DEFAULT 20
#define RTC_CK8M_ENABLE_WAIT_DEFAULT 1
/* Various delays to be programmed into power control state machines */
#define RTC_CNTL_PLL_BUF_WAIT_SLP_CYCLES (1)
#define RTC_CNTL_XTL_BUF_WAIT_SLP_US (1000)
#define RTC_CNTL_CK8M_WAIT_SLP_CYCLES (4)
#define RTC_CNTL_WAKEUP_DELAY_CYCLES (4)
#define RTC_CNTL_CK8M_DFREQ_DEFAULT 172
#define RTC_CNTL_SCK_DCAP_DEFAULT 255
@ -288,6 +294,10 @@ typedef struct {
.rtc_mem_wait_cycles = OTHER_BLOCKS_WAIT, \
}
/* Two different calibration mode for slow clock */
#define RTC_TIME_CAL_ONEOFF_MODE 0
#define RTC_TIME_CAL_CYCLING_MODE 1
void rtc_clk_divider_set(uint32_t div);
void rtc_clk_8m_divider_set(uint32_t div);
@ -518,7 +528,7 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq);
*/
uint32_t rtc_clk_apb_freq_get(void);
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles, uint32_t cal_mode);
/**
* @brief Measure RTC slow clock's period, based on main XTAL frequency
@ -709,6 +719,17 @@ typedef struct {
*/
void rtc_sleep_init(rtc_sleep_config_t cfg);
/**
* @brief Low level initialize for rtc state machine waiting cycles after waking up
*
* This function configures the cycles chip need to wait for internal 8MHz
* oscillator and external 40MHz crystal. As we configure fixed time for waiting
* crystal, we need to pass period to calculate cycles. Now this function only
* used in lightsleep mode.
*
* @param slowclk_period re-calibrated slow clock period
*/
void rtc_sleep_low_init(uint32_t slowclk_period);
#define RTC_EXT0_TRIG_EN BIT(0) //!< EXT0 GPIO wakeup
#define RTC_EXT1_TRIG_EN BIT(1) //!< EXT1 GPIO wakeup
@ -850,7 +871,13 @@ rtc_vddsdio_config_t rtc_vddsdio_get_config(void);
*/
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config);
/**
* Using valid hardware calibration value to calibrate slowclk
* If there is no hardware calibration in process, start hardware calibration and wait for calibration finished
* @param cal_clk clock to be measured
* @param slowclk_cycles if no hardware calibration in process, use this amount of slow cycles to calibrate slowclk.
*/
uint32_t rtc_clk_cal_cycling(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
#ifdef __cplusplus
}
#endif

View File

@ -106,6 +106,12 @@ extern "C" {
#define RTC_CNTL_CK8M_WAIT_DEFAULT 20
#define RTC_CK8M_ENABLE_WAIT_DEFAULT 5
/* Various delays to be programmed into power control state machines */
#define RTC_CNTL_PLL_BUF_WAIT_SLP_CYCLES RTC_CNTL_PLL_BUF_WAIT_DEFAULT
#define RTC_CNTL_XTL_BUF_WAIT_SLP_US RTC_CNTL_XTL_BUF_WAIT_DEFAULT
#define RTC_CNTL_CK8M_WAIT_SLP_CYCLES RTC_CNTL_CK8M_WAIT_DEFAULT
#define RTC_CNTL_WAKEUP_DELAY_CYCLES (0)
#define RTC_CNTL_CK8M_DFREQ_DEFAULT 100
#define RTC_CNTL_SCK_DCAP_DEFAULT 255
@ -687,6 +693,17 @@ typedef struct {
*/
void rtc_sleep_init(rtc_sleep_config_t cfg);
/**
* @brief Low level initialize for rtc state machine waiting cycles after waking up
*
* This function configures the cycles chip need to wait for internal 8MHz
* oscillator and external 40MHz crystal. As we configure fixed time for waiting
* crystal, we need to pass period to calculate cycles. Now this function only
* used in lightsleep mode.
*
* @param slowclk_period re-calibrated slow clock period
*/
void rtc_sleep_low_init(uint32_t slowclk_period);
/**
* @brief Set target value of RTC counter for RTC_TIMER_TRIG_EN wakeup source