Merge branch 'bugfix/light_sleep_fixes' into 'master'
light sleep fixes See merge request idf/esp-idf!2242
This commit is contained in:
commit
0d65f3b7f9
14 changed files with 329 additions and 113 deletions
|
@ -467,6 +467,18 @@ esp_err_t esp_timer_dump(FILE* stream)
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t IRAM_ATTR esp_timer_get_next_alarm()
|
||||||
|
{
|
||||||
|
int64_t next_alarm = INT64_MAX;
|
||||||
|
timer_list_lock();
|
||||||
|
esp_timer_handle_t it = LIST_FIRST(&s_timers);
|
||||||
|
if (it) {
|
||||||
|
next_alarm = it->alarm;
|
||||||
|
}
|
||||||
|
timer_list_unlock();
|
||||||
|
return next_alarm;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t IRAM_ATTR esp_timer_get_time()
|
int64_t IRAM_ATTR esp_timer_get_time()
|
||||||
{
|
{
|
||||||
return (int64_t) esp_timer_impl_get_time();
|
return (int64_t) esp_timer_impl_get_time();
|
||||||
|
|
|
@ -311,6 +311,18 @@ void IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us)
|
||||||
portEXIT_CRITICAL_ISR(&s_time_update_lock);
|
portEXIT_CRITICAL_ISR(&s_time_update_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void esp_timer_impl_advance(int64_t time_us)
|
||||||
|
{
|
||||||
|
assert(time_us > 0 && "negative adjustments not supported yet");
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&s_time_update_lock);
|
||||||
|
uint64_t count = REG_READ(FRC_TIMER_COUNT_REG(1));
|
||||||
|
REG_WRITE(FRC_TIMER_LOAD_REG(1), 0);
|
||||||
|
s_time_base_us += count / s_timer_ticks_per_us + time_us;
|
||||||
|
esp_timer_impl_set_alarm(esp_timer_get_next_alarm());
|
||||||
|
portEXIT_CRITICAL(&s_time_update_lock);
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler)
|
esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler)
|
||||||
{
|
{
|
||||||
s_alarm_handler = alarm_handler;
|
s_alarm_handler = alarm_handler;
|
||||||
|
|
|
@ -60,6 +60,15 @@ void esp_timer_impl_set_alarm(uint64_t timestamp);
|
||||||
*/
|
*/
|
||||||
void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us);
|
void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adjust current esp_timer time by a certain value
|
||||||
|
*
|
||||||
|
* Called from light sleep code to synchronize esp_timer time with RTC time.
|
||||||
|
*
|
||||||
|
* @param time_us adjustment to apply to esp_timer time, in microseconds
|
||||||
|
*/
|
||||||
|
void esp_timer_impl_advance(int64_t time_us);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get time, in microseconds, since esp_timer_impl_init was called
|
* @brief Get time, in microseconds, since esp_timer_impl_init was called
|
||||||
* @return timestamp in microseconds
|
* @return timestamp in microseconds
|
||||||
|
|
|
@ -38,6 +38,7 @@ typedef enum {
|
||||||
ESP_PD_DOMAIN_RTC_PERIPH, //!< RTC IO, sensors and ULP co-processor
|
ESP_PD_DOMAIN_RTC_PERIPH, //!< RTC IO, sensors and ULP co-processor
|
||||||
ESP_PD_DOMAIN_RTC_SLOW_MEM, //!< RTC slow memory
|
ESP_PD_DOMAIN_RTC_SLOW_MEM, //!< RTC slow memory
|
||||||
ESP_PD_DOMAIN_RTC_FAST_MEM, //!< RTC fast memory
|
ESP_PD_DOMAIN_RTC_FAST_MEM, //!< RTC fast memory
|
||||||
|
ESP_PD_DOMAIN_XTAL, //!< XTAL oscillator
|
||||||
ESP_PD_DOMAIN_MAX //!< Number of domains
|
ESP_PD_DOMAIN_MAX //!< Number of domains
|
||||||
} esp_sleep_pd_domain_t;
|
} esp_sleep_pd_domain_t;
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,13 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer);
|
||||||
*/
|
*/
|
||||||
int64_t esp_timer_get_time();
|
int64_t esp_timer_get_time();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the timestamp when the next timeout is expected to occur
|
||||||
|
* @return Timestamp of the nearest timer event, in microseconds.
|
||||||
|
* The timebase is the same as for the values returned by esp_timer_get_time.
|
||||||
|
*/
|
||||||
|
int64_t esp_timer_get_next_alarm();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Dump the list of timers to a stream
|
* @brief Dump the list of timers to a stream
|
||||||
*
|
*
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_sleep.h"
|
#include "esp_sleep.h"
|
||||||
|
#include "esp_timer_impl.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_clk.h"
|
#include "esp_clk.h"
|
||||||
#include "esp_newlib.h"
|
#include "esp_newlib.h"
|
||||||
|
@ -42,6 +43,19 @@
|
||||||
// Time from VDD_SDIO power up to first flash read in ROM code
|
// Time from VDD_SDIO power up to first flash read in ROM code
|
||||||
#define VDD_SDIO_POWERUP_TO_FLASH_READ_US 700
|
#define VDD_SDIO_POWERUP_TO_FLASH_READ_US 700
|
||||||
|
|
||||||
|
// Extra time it takes to enter and exit light sleep and deep sleep
|
||||||
|
// For deep sleep, this is until the wake stub runs (not the app).
|
||||||
|
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||||
|
#define LIGHT_SLEEP_TIME_OVERHEAD_US (650 + 30 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
|
||||||
|
#define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
|
||||||
|
#else
|
||||||
|
#define LIGHT_SLEEP_TIME_OVERHEAD_US (250 + 30 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
|
||||||
|
#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
|
||||||
|
#endif // CONFIG_ESP32_RTC_CLOCK_SOURCE
|
||||||
|
|
||||||
|
// Minimal amount of time we can sleep for
|
||||||
|
#define LIGHT_SLEEP_MIN_TIME_US 200
|
||||||
|
|
||||||
#define CHECK_SOURCE(source, value, mask) ((s_config.wakeup_triggers & mask) && \
|
#define CHECK_SOURCE(source, value, mask) ((s_config.wakeup_triggers & mask) && \
|
||||||
(source == value))
|
(source == value))
|
||||||
|
|
||||||
|
@ -56,9 +70,11 @@ typedef struct {
|
||||||
uint32_t ext1_rtc_gpio_mask : 18;
|
uint32_t ext1_rtc_gpio_mask : 18;
|
||||||
uint32_t ext0_trigger_level : 1;
|
uint32_t ext0_trigger_level : 1;
|
||||||
uint32_t ext0_rtc_gpio_num : 5;
|
uint32_t ext0_rtc_gpio_num : 5;
|
||||||
} deep_sleep_config_t;
|
uint32_t sleep_time_adjustment;
|
||||||
|
uint64_t rtc_ticks_at_sleep_start;
|
||||||
|
} sleep_config_t;
|
||||||
|
|
||||||
static deep_sleep_config_t s_config = {
|
static sleep_config_t s_config = {
|
||||||
.pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO },
|
.pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO },
|
||||||
.wakeup_triggers = 0
|
.wakeup_triggers = 0
|
||||||
};
|
};
|
||||||
|
@ -125,12 +141,31 @@ void esp_deep_sleep(uint64_t time_in_us)
|
||||||
esp_deep_sleep_start();
|
esp_deep_sleep_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void IRAM_ATTR suspend_uarts()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
|
||||||
|
uart_tx_wait_idle(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IRAM_ATTR resume_uarts()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
|
||||||
|
REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
|
||||||
|
REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
|
static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
|
||||||
{
|
{
|
||||||
// Flush UARTs so that output is not lost due to APB frequency change
|
// Stop UART output so that output is not lost due to APB frequency change
|
||||||
uart_tx_wait_idle(0);
|
suspend_uarts();
|
||||||
uart_tx_wait_idle(1);
|
|
||||||
uart_tx_wait_idle(2);
|
// Save current frequency and switch to XTAL
|
||||||
|
rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get();
|
||||||
|
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
|
||||||
|
|
||||||
// Configure pins for external wakeup
|
// Configure pins for external wakeup
|
||||||
if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) {
|
if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) {
|
||||||
|
@ -143,20 +178,32 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
|
||||||
if (s_config.wakeup_triggers & RTC_ULP_TRIG_EN) {
|
if (s_config.wakeup_triggers & RTC_ULP_TRIG_EN) {
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_WAKEUP_FORCE_EN);
|
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_WAKEUP_FORCE_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enter sleep
|
||||||
|
rtc_sleep_config_t config = RTC_SLEEP_CONFIG_DEFAULT(pd_flags);
|
||||||
|
rtc_sleep_init(config);
|
||||||
|
|
||||||
// Configure timer wakeup
|
// Configure timer wakeup
|
||||||
if ((s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) &&
|
if ((s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) &&
|
||||||
s_config.sleep_duration > 0) {
|
s_config.sleep_duration > 0) {
|
||||||
timer_wakeup_prepare();
|
timer_wakeup_prepare();
|
||||||
}
|
}
|
||||||
|
uint32_t result = rtc_sleep_start(s_config.wakeup_triggers, 0);
|
||||||
|
|
||||||
// Enter sleep
|
// Restore CPU frequency
|
||||||
rtc_sleep_config_t config = RTC_SLEEP_CONFIG_DEFAULT(pd_flags);
|
rtc_clk_cpu_freq_set(cpu_freq);
|
||||||
rtc_sleep_init(config);
|
|
||||||
return rtc_sleep_start(s_config.wakeup_triggers, 0);
|
// re-enable UART output
|
||||||
|
resume_uarts();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR esp_deep_sleep_start()
|
void IRAM_ATTR esp_deep_sleep_start()
|
||||||
{
|
{
|
||||||
|
// record current RTC time
|
||||||
|
s_config.rtc_ticks_at_sleep_start = rtc_time_get();
|
||||||
|
|
||||||
// Configure wake stub
|
// Configure wake stub
|
||||||
if (esp_get_deep_sleep_wake_stub() == NULL) {
|
if (esp_get_deep_sleep_wake_stub() == NULL) {
|
||||||
esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep);
|
esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep);
|
||||||
|
@ -165,8 +212,11 @@ void IRAM_ATTR esp_deep_sleep_start()
|
||||||
// Decide which power domains can be powered down
|
// Decide which power domains can be powered down
|
||||||
uint32_t pd_flags = get_power_down_flags();
|
uint32_t pd_flags = get_power_down_flags();
|
||||||
|
|
||||||
|
// Correct the sleep time
|
||||||
|
s_config.sleep_time_adjustment = DEEP_SLEEP_TIME_OVERHEAD_US;
|
||||||
|
|
||||||
// Enter sleep
|
// Enter sleep
|
||||||
esp_sleep_start(RTC_SLEEP_PD_DIG | RTC_SLEEP_PD_VDDSDIO | pd_flags);
|
esp_sleep_start(RTC_SLEEP_PD_DIG | RTC_SLEEP_PD_VDDSDIO | RTC_SLEEP_PD_XTAL | pd_flags);
|
||||||
|
|
||||||
// Because RTC is in a slower clock domain than the CPU, it
|
// Because RTC is in a slower clock domain than the CPU, it
|
||||||
// can take several CPU cycles for the sleep mode to start.
|
// can take several CPU cycles for the sleep mode to start.
|
||||||
|
@ -201,11 +251,11 @@ static void rtc_wdt_disable()
|
||||||
* Placed into IRAM as flash may need some time to be powered on.
|
* Placed into IRAM as flash may need some time to be powered on.
|
||||||
*/
|
*/
|
||||||
static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
|
static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
|
||||||
rtc_cpu_freq_t cpu_freq, uint32_t flash_enable_time_us,
|
uint32_t flash_enable_time_us,
|
||||||
rtc_vddsdio_config_t vddsdio_config) IRAM_ATTR __attribute__((noinline));
|
rtc_vddsdio_config_t vddsdio_config) IRAM_ATTR __attribute__((noinline));
|
||||||
|
|
||||||
static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
|
static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
|
||||||
rtc_cpu_freq_t cpu_freq, uint32_t flash_enable_time_us,
|
uint32_t flash_enable_time_us,
|
||||||
rtc_vddsdio_config_t vddsdio_config)
|
rtc_vddsdio_config_t vddsdio_config)
|
||||||
{
|
{
|
||||||
// Enter sleep
|
// Enter sleep
|
||||||
|
@ -217,9 +267,6 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
|
||||||
rtc_vddsdio_set_config(vddsdio_config);
|
rtc_vddsdio_set_config(vddsdio_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore CPU frequency
|
|
||||||
rtc_clk_cpu_freq_set(cpu_freq);
|
|
||||||
|
|
||||||
// If SPI flash was powered down, wait for it to become ready
|
// If SPI flash was powered down, wait for it to become ready
|
||||||
if (pd_flags & RTC_SLEEP_PD_VDDSDIO) {
|
if (pd_flags & RTC_SLEEP_PD_VDDSDIO) {
|
||||||
// Wait for the flash chip to start up
|
// Wait for the flash chip to start up
|
||||||
|
@ -231,53 +278,61 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
|
||||||
esp_err_t esp_light_sleep_start()
|
esp_err_t esp_light_sleep_start()
|
||||||
{
|
{
|
||||||
static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED;
|
static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
portENTER_CRITICAL(&light_sleep_lock);
|
portENTER_CRITICAL(&light_sleep_lock);
|
||||||
int other_cpu = xPortGetCoreID() ? 0 : 1;
|
s_config.rtc_ticks_at_sleep_start = rtc_time_get();
|
||||||
esp_cpu_stall(other_cpu);
|
uint64_t frc_time_at_start = esp_timer_get_time();
|
||||||
|
DPORT_STALL_OTHER_CPU_START();
|
||||||
// Other CPU is stalled, need to disable DPORT protection
|
|
||||||
esp_dport_access_int_pause();
|
|
||||||
|
|
||||||
// Decide which power domains can be powered down
|
// Decide which power domains can be powered down
|
||||||
uint32_t pd_flags = get_power_down_flags();
|
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;
|
||||||
|
|
||||||
// Decide if VDD_SDIO needs to be powered down;
|
// Decide if VDD_SDIO needs to be powered down;
|
||||||
// If it needs to be powered down, adjust sleep time.
|
// If it needs to be powered down, adjust sleep time.
|
||||||
const uint32_t flash_enable_time_us = VDD_SDIO_POWERUP_TO_FLASH_READ_US
|
const uint32_t flash_enable_time_us = VDD_SDIO_POWERUP_TO_FLASH_READ_US
|
||||||
+ CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY;
|
+ CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY;
|
||||||
|
|
||||||
// Don't power down VDD_SDIO if pSRAM is used.
|
|
||||||
#ifndef CONFIG_SPIRAM_SUPPORT
|
#ifndef CONFIG_SPIRAM_SUPPORT
|
||||||
if (s_config.sleep_duration > FLASH_PD_MIN_SLEEP_TIME_US &&
|
const uint32_t vddsdio_pd_sleep_duration = MAX(FLASH_PD_MIN_SLEEP_TIME_US,
|
||||||
s_config.sleep_duration > flash_enable_time_us) {
|
flash_enable_time_us + LIGHT_SLEEP_TIME_OVERHEAD_US + LIGHT_SLEEP_MIN_TIME_US);
|
||||||
|
|
||||||
|
if (s_config.sleep_duration > vddsdio_pd_sleep_duration) {
|
||||||
pd_flags |= RTC_SLEEP_PD_VDDSDIO;
|
pd_flags |= RTC_SLEEP_PD_VDDSDIO;
|
||||||
s_config.sleep_duration -= flash_enable_time_us;
|
s_config.sleep_time_adjustment += flash_enable_time_us;
|
||||||
}
|
}
|
||||||
#endif //CONFIG_SPIRAM_SUPPORT
|
#endif //CONFIG_SPIRAM_SUPPORT
|
||||||
|
|
||||||
rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
|
rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
|
||||||
|
|
||||||
// Safety net: enable WDT in case exit from light sleep fails
|
// Safety net: enable WDT in case exit from light sleep fails
|
||||||
rtc_wdt_enable(1000);
|
rtc_wdt_enable(1000);
|
||||||
|
|
||||||
// Save current CPU frequency, light sleep will switch to XTAL
|
|
||||||
rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get();
|
|
||||||
|
|
||||||
// Enter sleep, then wait for flash to be ready on wakeup
|
// Enter sleep, then wait for flash to be ready on wakeup
|
||||||
esp_err_t err = esp_light_sleep_inner(pd_flags, cpu_freq,
|
esp_err_t err = esp_light_sleep_inner(pd_flags,
|
||||||
flash_enable_time_us, vddsdio_config);
|
flash_enable_time_us, vddsdio_config);
|
||||||
|
|
||||||
// At this point, if FRC1 is used for timekeeping, time will be lagging behind.
|
// FRC1 has been clock gated for the duration of the sleep, correct for that.
|
||||||
// This will update the microsecond count based on RTC timer.
|
uint64_t rtc_ticks_at_end = rtc_time_get();
|
||||||
|
uint64_t frc_time_at_end = esp_timer_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 frc_time_diff = frc_time_at_end - frc_time_at_start;
|
||||||
|
|
||||||
|
int64_t time_diff = rtc_time_diff - frc_time_diff;
|
||||||
|
/* Small negative values (up to 1 RTC_SLOW clock period) are possible,
|
||||||
|
* for very small values of sleep_duration. Ignore those to keep esp_timer
|
||||||
|
* monotonic.
|
||||||
|
*/
|
||||||
|
if (time_diff > 0) {
|
||||||
|
esp_timer_impl_advance(time_diff);
|
||||||
|
}
|
||||||
esp_set_time_from_rtc();
|
esp_set_time_from_rtc();
|
||||||
|
|
||||||
// However, we do not advance RTOS ticks here; doing so would be rather messy,
|
DPORT_STALL_OTHER_CPU_END();
|
||||||
// as ticks can only be advanced on CPU0.
|
|
||||||
// If this is needed by the application, automatic light sleep (tickless idle)
|
|
||||||
// will handle that better.
|
|
||||||
|
|
||||||
esp_cpu_unstall(other_cpu);
|
|
||||||
esp_dport_access_int_resume();
|
|
||||||
rtc_wdt_disable();
|
rtc_wdt_disable();
|
||||||
portEXIT_CRITICAL(&light_sleep_lock);
|
portEXIT_CRITICAL(&light_sleep_lock);
|
||||||
return err;
|
return err;
|
||||||
|
@ -343,9 +398,13 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
|
||||||
static void timer_wakeup_prepare()
|
static void timer_wakeup_prepare()
|
||||||
{
|
{
|
||||||
uint32_t period = esp_clk_slowclk_cal_get();
|
uint32_t period = esp_clk_slowclk_cal_get();
|
||||||
uint64_t rtc_count_delta = rtc_time_us_to_slowclk(s_config.sleep_duration, period);
|
int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment;
|
||||||
uint64_t cur_rtc_count = rtc_time_get();
|
if (sleep_duration < 0) {
|
||||||
rtc_sleep_set_wakeup_time(cur_rtc_count + rtc_count_delta);
|
sleep_duration = 0;
|
||||||
|
}
|
||||||
|
int64_t rtc_count_delta = rtc_time_us_to_slowclk(sleep_duration, period);
|
||||||
|
|
||||||
|
rtc_sleep_set_wakeup_time(s_config.rtc_ticks_at_sleep_start + rtc_count_delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_sleep_enable_touchpad_wakeup()
|
esp_err_t esp_sleep_enable_touchpad_wakeup()
|
||||||
|
@ -561,6 +620,10 @@ static uint32_t get_power_down_flags()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s_config.pd_options[ESP_PD_DOMAIN_XTAL] == ESP_PD_OPTION_AUTO) {
|
||||||
|
s_config.pd_options[ESP_PD_DOMAIN_XTAL] = ESP_PD_OPTION_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
const char* option_str[] = {"OFF", "ON", "AUTO(OFF)" /* Auto works as OFF */};
|
const char* option_str[] = {"OFF", "ON", "AUTO(OFF)" /* Auto works as OFF */};
|
||||||
ESP_LOGD(TAG, "RTC_PERIPH: %s, RTC_SLOW_MEM: %s, RTC_FAST_MEM: %s",
|
ESP_LOGD(TAG, "RTC_PERIPH: %s, RTC_SLOW_MEM: %s, RTC_FAST_MEM: %s",
|
||||||
option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH]],
|
option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH]],
|
||||||
|
@ -578,5 +641,8 @@ static uint32_t get_power_down_flags()
|
||||||
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] != ESP_PD_OPTION_ON) {
|
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] != ESP_PD_OPTION_ON) {
|
||||||
pd_flags |= RTC_SLEEP_PD_RTC_PERIPH;
|
pd_flags |= RTC_SLEEP_PD_RTC_PERIPH;
|
||||||
}
|
}
|
||||||
|
if (s_config.pd_options[ESP_PD_DOMAIN_XTAL] != ESP_PD_OPTION_ON) {
|
||||||
|
pd_flags |= RTC_SLEEP_PD_XTAL;
|
||||||
|
}
|
||||||
return pd_flags;
|
return pd_flags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
#include "unity.h"
|
#include "unity.h"
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include "esp_sleep.h"
|
#include "esp_sleep.h"
|
||||||
|
#include "esp_clk.h"
|
||||||
#include "driver/rtc_io.h"
|
#include "driver/rtc_io.h"
|
||||||
|
#include "soc/gpio_reg.h"
|
||||||
|
#include "soc/rtc.h"
|
||||||
|
#include "soc/uart_reg.h"
|
||||||
|
#include "rom/uart.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
#include "soc/rtc.h" // for wakeup trigger defines
|
#include "soc/rtc.h" // for wakeup trigger defines
|
||||||
#include "soc/rtc_cntl_reg.h" // for read rtc registers directly (cause)
|
#include "soc/rtc_cntl_reg.h" // for read rtc registers directly (cause)
|
||||||
#include "soc/soc.h" // for direct register read macros
|
#include "soc/soc.h" // for direct register read macros
|
||||||
|
@ -14,10 +20,6 @@
|
||||||
|
|
||||||
static struct timeval tv_start, tv_stop;
|
static struct timeval tv_start, tv_stop;
|
||||||
|
|
||||||
TEST_CASE("esp_deepsleep works", "[deepsleep][reset=DEEPSLEEP_RESET]")
|
|
||||||
{
|
|
||||||
esp_deep_sleep(2000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void deep_sleep_task(void *arg)
|
static void deep_sleep_task(void *arg)
|
||||||
{
|
{
|
||||||
|
@ -36,12 +38,19 @@ static void do_deep_sleep_from_app_cpu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("wake up using timer", "[deepsleep][reset=DEEPSLEEP_RESET]")
|
TEST_CASE("wake up from deep sleep using timer", "[deepsleep][reset=DEEPSLEEP_RESET]")
|
||||||
{
|
{
|
||||||
esp_sleep_enable_timer_wakeup(2000000);
|
esp_sleep_enable_timer_wakeup(2000000);
|
||||||
esp_deep_sleep_start();
|
esp_deep_sleep_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("light sleep followed by deep sleep", "[deepsleep][reset=DEEPSLEEP_RESET]")
|
||||||
|
{
|
||||||
|
esp_sleep_enable_timer_wakeup(1000000);
|
||||||
|
esp_light_sleep_start();
|
||||||
|
esp_deep_sleep_start();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("wake up from light sleep using timer", "[deepsleep]")
|
TEST_CASE("wake up from light sleep using timer", "[deepsleep]")
|
||||||
{
|
{
|
||||||
esp_sleep_enable_timer_wakeup(2000000);
|
esp_sleep_enable_timer_wakeup(2000000);
|
||||||
|
@ -54,6 +63,103 @@ TEST_CASE("wake up from light sleep using timer", "[deepsleep]")
|
||||||
TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt);
|
TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_light_sleep(void* arg)
|
||||||
|
{
|
||||||
|
vTaskDelay(2);
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
printf("%d %d\n", xPortGetCoreID(), i);
|
||||||
|
fflush(stdout);
|
||||||
|
esp_light_sleep_start();
|
||||||
|
}
|
||||||
|
SemaphoreHandle_t done = (SemaphoreHandle_t) arg;
|
||||||
|
xSemaphoreGive(done);
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("light sleep stress test", "[deepsleep]")
|
||||||
|
{
|
||||||
|
SemaphoreHandle_t done = xSemaphoreCreateCounting(2, 0);
|
||||||
|
esp_sleep_enable_timer_wakeup(1000);
|
||||||
|
xTaskCreatePinnedToCore(&test_light_sleep, "ls0", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 0);
|
||||||
|
#if portNUM_PROCESSORS == 2
|
||||||
|
xTaskCreatePinnedToCore(&test_light_sleep, "ls1", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 1);
|
||||||
|
#endif
|
||||||
|
xSemaphoreTake(done, portMAX_DELAY);
|
||||||
|
#if portNUM_PROCESSORS == 2
|
||||||
|
xSemaphoreTake(done, portMAX_DELAY);
|
||||||
|
#endif
|
||||||
|
vSemaphoreDelete(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||||
|
#define MAX_SLEEP_TIME_ERROR_US 200
|
||||||
|
#else
|
||||||
|
#define MAX_SLEEP_TIME_ERROR_US 100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("light sleep duration is correct", "[deepsleep]")
|
||||||
|
{
|
||||||
|
// don't power down XTAL — powering it up takes different time on
|
||||||
|
// different boards
|
||||||
|
esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON);
|
||||||
|
|
||||||
|
// run one light sleep without checking timing, to warm up the cache
|
||||||
|
esp_sleep_enable_timer_wakeup(1000);
|
||||||
|
esp_light_sleep_start();
|
||||||
|
|
||||||
|
const int sleep_intervals_ms[] = {
|
||||||
|
1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 15,
|
||||||
|
20, 25, 50, 100, 200, 500,
|
||||||
|
};
|
||||||
|
|
||||||
|
const int sleep_intervals_count = sizeof(sleep_intervals_ms)/sizeof(sleep_intervals_ms[0]);
|
||||||
|
for (int i = 0; i < sleep_intervals_count; ++i) {
|
||||||
|
uint64_t sleep_time = sleep_intervals_ms[i] * 1000;
|
||||||
|
esp_sleep_enable_timer_wakeup(sleep_time);
|
||||||
|
for (int repeat = 0; repeat < 5; ++repeat) {
|
||||||
|
uint64_t start = esp_clk_rtc_time();
|
||||||
|
int64_t start_hs = esp_timer_get_time();
|
||||||
|
esp_light_sleep_start();
|
||||||
|
int64_t stop_hs = esp_timer_get_time();
|
||||||
|
uint64_t stop = esp_clk_rtc_time();
|
||||||
|
|
||||||
|
int diff_us = (int) (stop - start);
|
||||||
|
int diff_hs_us = (int) (stop_hs - start_hs);
|
||||||
|
printf("%lld %d\n", sleep_time, (int) (diff_us - sleep_time));
|
||||||
|
int32_t threshold = MAX(sleep_time / 100, MAX_SLEEP_TIME_ERROR_US);
|
||||||
|
TEST_ASSERT_INT32_WITHIN(threshold, sleep_time, diff_us);
|
||||||
|
TEST_ASSERT_INT32_WITHIN(threshold, sleep_time, diff_hs_us);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(10/portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("light sleep and frequency switching", "[deepsleep]")
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_PM_ENABLE
|
||||||
|
const int uart_clk_freq = REF_CLK_FREQ;
|
||||||
|
CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON);
|
||||||
|
uart_div_modify(CONFIG_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_CONSOLE_UART_BAUDRATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
esp_sleep_enable_timer_wakeup(1000);
|
||||||
|
rtc_cpu_freq_t default_freq = rtc_clk_cpu_freq_get();
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
rtc_clk_cpu_freq_set_fast(RTC_CPU_FREQ_XTAL);
|
||||||
|
} else {
|
||||||
|
rtc_clk_cpu_freq_set_fast(default_freq);
|
||||||
|
}
|
||||||
|
printf("%d\n", i);
|
||||||
|
fflush(stdout);
|
||||||
|
esp_light_sleep_start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_FREERTOS_UNICORE
|
#ifndef CONFIG_FREERTOS_UNICORE
|
||||||
TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep][reset=DEEPSLEEP_RESET]")
|
TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep][reset=DEEPSLEEP_RESET]")
|
||||||
{
|
{
|
||||||
|
@ -138,7 +244,7 @@ TEST_CASE("disable source trigger behavior", "[deepsleep]")
|
||||||
{
|
{
|
||||||
float dt = 0;
|
float dt = 0;
|
||||||
|
|
||||||
printf("Setup timer and ext0 to wakeup imediately from GPIO_13 \n");
|
printf("Setup timer and ext0 to wake up immediately from GPIO_13 \n");
|
||||||
|
|
||||||
// Setup ext0 configuration to wake up almost immediately
|
// Setup ext0 configuration to wake up almost immediately
|
||||||
// The wakeup time is proportional to input capacitance * pullup resistance
|
// The wakeup time is proportional to input capacitance * pullup resistance
|
||||||
|
@ -159,7 +265,7 @@ TEST_CASE("disable source trigger behavior", "[deepsleep]")
|
||||||
|
|
||||||
// Check wakeup from Ext0 using time measurement because wakeup cause is
|
// Check wakeup from Ext0 using time measurement because wakeup cause is
|
||||||
// not available in light sleep mode
|
// not available in light sleep mode
|
||||||
TEST_ASSERT_INT32_WITHIN(299, 300, (int) dt);
|
TEST_ASSERT_INT32_WITHIN(100, 100, (int) dt);
|
||||||
|
|
||||||
TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0);
|
TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0);
|
||||||
|
|
||||||
|
@ -175,7 +281,7 @@ TEST_CASE("disable source trigger behavior", "[deepsleep]")
|
||||||
|
|
||||||
TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt);
|
TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt);
|
||||||
|
|
||||||
// Additionaly check wakeup cause
|
// Additionally check wakeup cause
|
||||||
TEST_ASSERT((get_cause() & RTC_TIMER_TRIG_EN) != 0);
|
TEST_ASSERT((get_cause() & RTC_TIMER_TRIG_EN) != 0);
|
||||||
|
|
||||||
// Disable timer source.
|
// Disable timer source.
|
||||||
|
@ -195,12 +301,11 @@ TEST_CASE("disable source trigger behavior", "[deepsleep]")
|
||||||
dt = get_time_ms();
|
dt = get_time_ms();
|
||||||
printf("Ext0 sleep time = %d \n", (int) dt);
|
printf("Ext0 sleep time = %d \n", (int) dt);
|
||||||
|
|
||||||
TEST_ASSERT_INT32_WITHIN(199, 200, (int) dt);
|
TEST_ASSERT_INT32_WITHIN(100, 100, (int) dt);
|
||||||
TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0);
|
TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0);
|
||||||
|
|
||||||
// Check error message when source is already disabled
|
// Check error message when source is already disabled
|
||||||
esp_err_t err_code = esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
|
esp_err_t err_code = esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
|
||||||
TEST_ASSERT(err_code == ESP_ERR_INVALID_STATE);
|
TEST_ASSERT(err_code == ESP_ERR_INVALID_STATE);
|
||||||
printf("Test case completed successfully.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -427,7 +427,6 @@ void rtc_clk_wait_for_slow_cycle();
|
||||||
* @brief sleep configuration for rtc_sleep_init function
|
* @brief sleep configuration for rtc_sleep_init function
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t soc_clk_sel : 2; //!< SoC clock select, see RTC_CNTL_SOC_CLK_SEL
|
|
||||||
uint32_t lslp_mem_inf_fpu : 1; //!< force normal voltage in sleep mode (digital domain memory)
|
uint32_t lslp_mem_inf_fpu : 1; //!< force normal voltage in sleep mode (digital domain memory)
|
||||||
uint32_t rtc_mem_inf_fpu : 1; //!< force normal voltage in sleep mode (RTC memory)
|
uint32_t rtc_mem_inf_fpu : 1; //!< force normal voltage in sleep mode (RTC memory)
|
||||||
uint32_t rtc_mem_inf_follow_cpu : 1;//!< keep low voltage in sleep mode (even if ULP/touch is used)
|
uint32_t rtc_mem_inf_follow_cpu : 1;//!< keep low voltage in sleep mode (even if ULP/touch is used)
|
||||||
|
@ -444,6 +443,7 @@ typedef struct {
|
||||||
uint32_t rtc_dbias_slp : 3; //!< set bias for RTC domain, in sleep mode
|
uint32_t rtc_dbias_slp : 3; //!< set bias for RTC domain, in sleep mode
|
||||||
uint32_t lslp_meminf_pd : 1; //!< remove all peripheral force power up flags
|
uint32_t lslp_meminf_pd : 1; //!< remove all peripheral force power up flags
|
||||||
uint32_t vddsdio_pd_en : 1; //!< power down VDDSDIO regulator
|
uint32_t vddsdio_pd_en : 1; //!< power down VDDSDIO regulator
|
||||||
|
uint32_t xtal_fpu : 1; //!< keep main XTAL powered up in sleep
|
||||||
} rtc_sleep_config_t;
|
} rtc_sleep_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -455,7 +455,6 @@ typedef struct {
|
||||||
* @param RTC_SLEEP_PD_x flags combined using bitwise OR
|
* @param RTC_SLEEP_PD_x flags combined using bitwise OR
|
||||||
*/
|
*/
|
||||||
#define RTC_SLEEP_CONFIG_DEFAULT(sleep_flags) { \
|
#define RTC_SLEEP_CONFIG_DEFAULT(sleep_flags) { \
|
||||||
.soc_clk_sel = RTC_CNTL_SOC_CLK_SEL_XTL, \
|
|
||||||
.lslp_mem_inf_fpu = 0, \
|
.lslp_mem_inf_fpu = 0, \
|
||||||
.rtc_mem_inf_fpu = 0, \
|
.rtc_mem_inf_fpu = 0, \
|
||||||
.rtc_mem_inf_follow_cpu = ((sleep_flags) & RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU) ? 1 : 0, \
|
.rtc_mem_inf_follow_cpu = ((sleep_flags) & RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU) ? 1 : 0, \
|
||||||
|
@ -468,10 +467,11 @@ typedef struct {
|
||||||
.wdt_flashboot_mod_en = 0, \
|
.wdt_flashboot_mod_en = 0, \
|
||||||
.dig_dbias_wak = RTC_CNTL_DBIAS_1V10, \
|
.dig_dbias_wak = RTC_CNTL_DBIAS_1V10, \
|
||||||
.dig_dbias_slp = RTC_CNTL_DBIAS_0V90, \
|
.dig_dbias_slp = RTC_CNTL_DBIAS_0V90, \
|
||||||
.rtc_dbias_wak = RTC_CNTL_DBIAS_0V90, \
|
.rtc_dbias_wak = RTC_CNTL_DBIAS_1V10, \
|
||||||
.rtc_dbias_slp = RTC_CNTL_DBIAS_0V90, \
|
.rtc_dbias_slp = RTC_CNTL_DBIAS_0V90, \
|
||||||
.lslp_meminf_pd = 1, \
|
.lslp_meminf_pd = 1, \
|
||||||
.vddsdio_pd_en = ((sleep_flags) & RTC_SLEEP_PD_VDDSDIO) ? 1 : 0, \
|
.vddsdio_pd_en = ((sleep_flags) & RTC_SLEEP_PD_VDDSDIO) ? 1 : 0, \
|
||||||
|
.xtal_fpu = ((sleep_flags) & RTC_SLEEP_PD_XTAL) ? 0 : 1 \
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RTC_SLEEP_PD_DIG BIT(0) //!< Deep sleep (power down digital domain)
|
#define RTC_SLEEP_PD_DIG BIT(0) //!< Deep sleep (power down digital domain)
|
||||||
|
@ -480,6 +480,7 @@ typedef struct {
|
||||||
#define RTC_SLEEP_PD_RTC_FAST_MEM BIT(3) //!< Power down RTC FAST memory
|
#define RTC_SLEEP_PD_RTC_FAST_MEM BIT(3) //!< Power down RTC FAST memory
|
||||||
#define RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU BIT(4) //!< RTC FAST and SLOW memories are automatically powered up and down along with the CPU
|
#define RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU BIT(4) //!< RTC FAST and SLOW memories are automatically powered up and down along with the CPU
|
||||||
#define RTC_SLEEP_PD_VDDSDIO BIT(5) //!< Power down VDDSDIO regulator
|
#define RTC_SLEEP_PD_VDDSDIO BIT(5) //!< Power down VDDSDIO regulator
|
||||||
|
#define RTC_SLEEP_PD_XTAL BIT(6) //!< Power down main XTAL
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Prepare the chip to enter sleep mode
|
* @brief Prepare the chip to enter sleep mode
|
||||||
|
|
|
@ -1070,7 +1070,7 @@
|
||||||
#define RTC_CNTL_DBG_ATTEN_M ((RTC_CNTL_DBG_ATTEN_V)<<(RTC_CNTL_DBG_ATTEN_S))
|
#define RTC_CNTL_DBG_ATTEN_M ((RTC_CNTL_DBG_ATTEN_V)<<(RTC_CNTL_DBG_ATTEN_S))
|
||||||
#define RTC_CNTL_DBG_ATTEN_V 0x3
|
#define RTC_CNTL_DBG_ATTEN_V 0x3
|
||||||
#define RTC_CNTL_DBG_ATTEN_S 24
|
#define RTC_CNTL_DBG_ATTEN_S 24
|
||||||
|
#define RTC_CNTL_DBG_ATTEN_DEFAULT 3
|
||||||
#define RTC_CNTL_REG (DR_REG_RTCCNTL_BASE + 0x7c)
|
#define RTC_CNTL_REG (DR_REG_RTCCNTL_BASE + 0x7c)
|
||||||
/* RTC_CNTL_FORCE_PU : R/W ;bitpos:[31] ;default: 1'd1 ; */
|
/* RTC_CNTL_FORCE_PU : R/W ;bitpos:[31] ;default: 1'd1 ; */
|
||||||
/*description: RTC_REG force power up*/
|
/*description: RTC_REG force power up*/
|
||||||
|
|
|
@ -30,7 +30,7 @@ void rtc_init(rtc_config_t cfg)
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, cfg.xtal_wait);
|
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, cfg.xtal_wait);
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, cfg.ck8m_wait);
|
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, cfg.ck8m_wait);
|
||||||
|
|
||||||
REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, 0x3);
|
REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, RTC_CNTL_DBG_ATTEN_DEFAULT);
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_BIAS_CONF_REG,
|
SET_PERI_REG_MASK(RTC_CNTL_BIAS_CONF_REG,
|
||||||
RTC_CNTL_DEC_HEARTBEAT_WIDTH | RTC_CNTL_INC_HEARTBEAT_PERIOD);
|
RTC_CNTL_DEC_HEARTBEAT_WIDTH | RTC_CNTL_INC_HEARTBEAT_PERIOD);
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@ pm_sw_reject_t pm_set_sleep_mode(pm_sleep_mode_t sleep_mode, void(*pmac_save_par
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_sleep_config_t cfg = { 0 };
|
rtc_sleep_config_t cfg = { 0 };
|
||||||
cfg.soc_clk_sel = RTC_CNTL_SOC_CLK_SEL_XTL;
|
|
||||||
|
|
||||||
switch (sleep_mode) {
|
switch (sleep_mode) {
|
||||||
case PM_LIGHT_SLEEP:
|
case PM_LIGHT_SLEEP:
|
||||||
|
|
|
@ -29,16 +29,26 @@
|
||||||
#define MHZ (1000000)
|
#define MHZ (1000000)
|
||||||
|
|
||||||
/* Various delays to be programmed into power control state machines */
|
/* Various delays to be programmed into power control state machines */
|
||||||
#define ROM_RAM_POWERUP_DELAY 3
|
#define RTC_CNTL_XTL_BUF_WAIT_SLP 2
|
||||||
#define ROM_RAM_WAIT_DELAY 3
|
#define RTC_CNTL_PLL_BUF_WAIT_SLP 2
|
||||||
#define WIFI_POWERUP_DELAY 3
|
#define RTC_CNTL_CK8M_WAIT_SLP 4
|
||||||
#define WIFI_WAIT_DELAY 3
|
#define OTHER_BLOCKS_POWERUP 1
|
||||||
#define RTC_POWERUP_DELAY 3
|
#define OTHER_BLOCKS_WAIT 1
|
||||||
#define RTC_WAIT_DELAY 3
|
|
||||||
#define DG_WRAP_POWERUP_DELAY 3
|
#define ROM_RAM_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
|
||||||
#define DG_WRAP_WAIT_DELAY 3
|
#define ROM_RAM_WAIT_CYCLES OTHER_BLOCKS_WAIT
|
||||||
#define RTC_MEM_POWERUP_DELAY 3
|
|
||||||
#define RTC_MEM_WAIT_DELAY 3
|
#define WIFI_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
|
||||||
|
#define WIFI_WAIT_CYCLES OTHER_BLOCKS_WAIT
|
||||||
|
|
||||||
|
#define RTC_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
|
||||||
|
#define RTC_WAIT_CYCLES OTHER_BLOCKS_WAIT
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Power down flags for rtc_sleep_pd function
|
* @brief Power down flags for rtc_sleep_pd function
|
||||||
|
@ -89,44 +99,31 @@ static void rtc_sleep_pd(rtc_sleep_pd_config_t cfg)
|
||||||
|
|
||||||
void rtc_sleep_init(rtc_sleep_config_t cfg)
|
void rtc_sleep_init(rtc_sleep_config_t cfg)
|
||||||
{
|
{
|
||||||
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
|
// set 5 PWC state machine times to fit in main state machine time
|
||||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, cfg.soc_clk_sel);
|
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 5 PWC state machine times to fit in main state machine time
|
// set shortest possible sleep time limit
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, 1);
|
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_MIN_SLP_VAL, RTC_CNTL_MIN_SLP_VAL_MIN);
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, RTC_CNTL_XTL_BUF_WAIT_DEFAULT);
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
|
|
||||||
//set rom&ram timer
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_POWERUP_TIMER, ROM_RAM_POWERUP_DELAY);
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_WAIT_TIMER, ROM_RAM_WAIT_DELAY);
|
|
||||||
//set wifi timer
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_POWERUP_TIMER, WIFI_POWERUP_DELAY);
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_WAIT_TIMER, WIFI_WAIT_DELAY);
|
|
||||||
//set rtc peri timer
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_POWERUP_TIMER, RTC_POWERUP_DELAY);
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_WAIT_TIMER, RTC_WAIT_DELAY);
|
|
||||||
//set digital wrap timer
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_POWERUP_TIMER, DG_WRAP_POWERUP_DELAY);
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_WAIT_TIMER, DG_WRAP_WAIT_DELAY);
|
|
||||||
//set rtc memory timer
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_POWERUP_TIMER, RTC_MEM_POWERUP_DELAY);
|
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_WAIT_TIMER, RTC_MEM_WAIT_DELAY);
|
|
||||||
|
|
||||||
if (cfg.soc_clk_sel == RTC_CNTL_SOC_CLK_SEL_PLL) {
|
// set rom&ram timer
|
||||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, RTC_CNTL_PLL_BUF_WAIT_DEFAULT);
|
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_POWERUP_TIMER, ROM_RAM_POWERUP_CYCLES);
|
||||||
} else if (cfg.soc_clk_sel == RTC_CNTL_SOC_CLK_SEL_XTL) {
|
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_WAIT_TIMER, ROM_RAM_WAIT_CYCLES);
|
||||||
ets_update_cpu_frequency(xtal_freq);
|
// set wifi timer
|
||||||
rtc_clk_apb_freq_update(xtal_freq * MHZ);
|
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_POWERUP_TIMER, WIFI_POWERUP_CYCLES);
|
||||||
} else if (cfg.soc_clk_sel == RTC_CNTL_SOC_CLK_SEL_8M) {
|
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_WAIT_TIMER, WIFI_WAIT_CYCLES);
|
||||||
ets_update_cpu_frequency(8);
|
// set rtc peri timer
|
||||||
rtc_clk_apb_freq_update(8 * MHZ);
|
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_POWERUP_TIMER, RTC_POWERUP_CYCLES);
|
||||||
}
|
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_WAIT_TIMER, RTC_WAIT_CYCLES);
|
||||||
|
// set digital wrap timer
|
||||||
|
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_POWERUP_TIMER, DG_WRAP_POWERUP_CYCLES);
|
||||||
|
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_WAIT_TIMER, DG_WRAP_WAIT_CYCLES);
|
||||||
|
// set rtc memory timer
|
||||||
|
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_POWERUP_TIMER, RTC_MEM_POWERUP_CYCLES);
|
||||||
|
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_WAIT_TIMER, RTC_MEM_WAIT_CYCLES);
|
||||||
|
|
||||||
if (cfg.lslp_mem_inf_fpu) {
|
REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU, cfg.lslp_mem_inf_fpu);
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU);
|
|
||||||
} else {
|
|
||||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU);
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc_sleep_pd_config_t pd_cfg = RTC_SLEEP_PD_CONFIG_ALL(cfg.lslp_meminf_pd);
|
rtc_sleep_pd_config_t pd_cfg = RTC_SLEEP_PD_CONFIG_ALL(cfg.lslp_meminf_pd);
|
||||||
rtc_sleep_pd(pd_cfg);
|
rtc_sleep_pd(pd_cfg);
|
||||||
|
@ -198,6 +195,8 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
|
||||||
REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, 0);
|
REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REG_SET_FIELD(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_XTL_FORCE_PU, cfg.xtal_fpu);
|
||||||
|
|
||||||
/* enable VDDSDIO control by state machine */
|
/* enable VDDSDIO control by state machine */
|
||||||
REG_CLR_BIT(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE);
|
REG_CLR_BIT(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE);
|
||||||
REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN, cfg.vddsdio_pd_en);
|
REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN, cfg.vddsdio_pd_en);
|
||||||
|
@ -230,5 +229,8 @@ uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
|
||||||
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);
|
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG,
|
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG,
|
||||||
RTC_CNTL_SLP_REJECT_INT_CLR | RTC_CNTL_SLP_WAKEUP_INT_CLR);
|
RTC_CNTL_SLP_REJECT_INT_CLR | RTC_CNTL_SLP_WAKEUP_INT_CLR);
|
||||||
|
|
||||||
|
/* restore DBG_ATTEN to the default value */
|
||||||
|
REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, RTC_CNTL_DBG_ATTEN_DEFAULT);
|
||||||
return reject;
|
return reject;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
#include "esp_heap_trace.h"
|
#include "esp_heap_trace.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define unity_printf ets_printf
|
|
||||||
|
|
||||||
// Pointers to the head and tail of linked list of test description structs:
|
// Pointers to the head and tail of linked list of test description structs:
|
||||||
static struct test_desc_t* s_unity_tests_first = NULL;
|
static struct test_desc_t* s_unity_tests_first = NULL;
|
||||||
static struct test_desc_t* s_unity_tests_last = NULL;
|
static struct test_desc_t* s_unity_tests_last = NULL;
|
||||||
|
@ -153,10 +151,10 @@ void unity_testcase_register(struct test_desc_t* desc)
|
||||||
* */
|
* */
|
||||||
static void print_multiple_function_test_menu(const struct test_desc_t* test_ms)
|
static void print_multiple_function_test_menu(const struct test_desc_t* test_ms)
|
||||||
{
|
{
|
||||||
unity_printf("%s\n", test_ms->name);
|
printf("%s\n", test_ms->name);
|
||||||
for (int i = 0; i < test_ms->test_fn_count; i++)
|
for (int i = 0; i < test_ms->test_fn_count; i++)
|
||||||
{
|
{
|
||||||
unity_printf("\t(%d)\t\"%s\"\n", i+1, test_ms->test_fn_name[i]);
|
printf("\t(%d)\t\"%s\"\n", i+1, test_ms->test_fn_name[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +187,10 @@ void multiple_function_option(const struct test_desc_t* test_ms)
|
||||||
static void unity_run_single_test(const struct test_desc_t* test)
|
static void unity_run_single_test(const struct test_desc_t* test)
|
||||||
{
|
{
|
||||||
printf("Running %s...\n", test->name);
|
printf("Running %s...\n", test->name);
|
||||||
|
// Unit test runner expects to see test name before the test starts
|
||||||
|
fflush(stdout);
|
||||||
|
uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
|
||||||
|
|
||||||
Unity.TestFile = test->file;
|
Unity.TestFile = test->file;
|
||||||
Unity.CurrentDetail1 = test->desc;
|
Unity.CurrentDetail1 = test->desc;
|
||||||
if(test->test_fn_count == 1) {
|
if(test->test_fn_count == 1) {
|
||||||
|
@ -293,17 +295,17 @@ static void trim_trailing_space(char* str)
|
||||||
static int print_test_menu(void)
|
static int print_test_menu(void)
|
||||||
{
|
{
|
||||||
int test_counter = 0;
|
int test_counter = 0;
|
||||||
unity_printf("\n\nHere's the test menu, pick your combo:\n");
|
printf("\n\nHere's the test menu, pick your combo:\n");
|
||||||
for (const struct test_desc_t* test = s_unity_tests_first;
|
for (const struct test_desc_t* test = s_unity_tests_first;
|
||||||
test != NULL;
|
test != NULL;
|
||||||
test = test->next, ++test_counter)
|
test = test->next, ++test_counter)
|
||||||
{
|
{
|
||||||
unity_printf("(%d)\t\"%s\" %s\n", test_counter + 1, test->name, test->desc);
|
printf("(%d)\t\"%s\" %s\n", test_counter + 1, test->name, test->desc);
|
||||||
if(test->test_fn_count > 1)
|
if(test->test_fn_count > 1)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < test->test_fn_count; i++)
|
for (int i = 0; i < test->test_fn_count; i++)
|
||||||
{
|
{
|
||||||
unity_printf("\t(%d)\t\"%s\"\n", i+1, test->test_fn_name[i]);
|
printf("\t(%d)\t\"%s\"\n", i+1, test->test_fn_name[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,7 +326,7 @@ static int get_test_count(void)
|
||||||
|
|
||||||
void unity_run_menu()
|
void unity_run_menu()
|
||||||
{
|
{
|
||||||
unity_printf("\n\nPress ENTER to see the list of tests.\n");
|
printf("\n\nPress ENTER to see the list of tests.\n");
|
||||||
int test_count = get_test_count();
|
int test_count = get_test_count();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|
|
@ -142,7 +142,7 @@ def run_unit_test_cases(env, extra_data):
|
||||||
# to determine if DUT is ready to test.
|
# to determine if DUT is ready to test.
|
||||||
dut.write("-", flush=False)
|
dut.write("-", flush=False)
|
||||||
dut.expect_any(UT_APP_BOOT_UP_DONE,
|
dut.expect_any(UT_APP_BOOT_UP_DONE,
|
||||||
"0 Tests 0 Failures 0 Ignored")
|
"0 Tests 0 Failures 0 Ignored", timeout=UT_TIMEOUT)
|
||||||
|
|
||||||
# run test case
|
# run test case
|
||||||
dut.write("\"{}\"".format(one_case["name"]))
|
dut.write("\"{}\"".format(one_case["name"]))
|
||||||
|
|
Loading…
Reference in a new issue