Merge branch 'bugfix/deep_sleep' into 'master'

deep sleep related fixes

A few fixes for deep sleep behavior:

- Fix a regression that deep sleep stub crashed if `ESP32_DEEP_SLEEP_WAKEUP_DELAY` option was enabled — the stub called `ets_update_cpu_frequency`, which was recently redefined to be an IRAM function, rather than a ROM one. Fixed by restoring the ROM definition as `ets_update_cpu_frequency_rom`, and using that in the deep sleep stub.

- By default, don't power down RTC_SLOW_MEM if there is any data in .rtc.data or .rtc.bss sections. This provides better out-of-the box experience, as variables attributed to .rtc.data are actually preserved during deep sleep.

- Store boot time in RTC_STORE registers instead of using a variable with RTC_DATA_ATTR. This allows RTC_SLOW_MEM to be powered down in deep sleep if no variables with RTC_DATA_ATTR are present in the program.

Fixes https://github.com/espressif/esp-idf/issues/182


See merge request !409
This commit is contained in:
Ivan Grokhotkov 2017-01-12 15:53:09 +08:00
commit b018a3ce8e
9 changed files with 72 additions and 28 deletions

View File

@ -381,6 +381,8 @@ choice ESP32_TIME_SYSCALL
longer to run.
- If no timers are used, gettimeofday and time functions
return -1 and set errno to ENOSYS.
- When RTC is used for timekeeping, two RTC_STORE registers are
used to keep time in deep sleep mode.
config ESP32_TIME_SYSCALL_USE_RTC
bool "RTC"

View File

@ -91,7 +91,7 @@ void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) {
#if CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY > 0
// ROM code has not started yet, so we need to set delay factor
// used by ets_delay_us first.
ets_update_cpu_frequency(ets_get_detected_xtal_freq() / 1000000);
ets_update_cpu_frequency_rom(ets_get_detected_xtal_freq() / 1000000);
// This delay is configured in menuconfig, it can be used to give
// the flash chip some time to become ready.
ets_delay_us(CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY);
@ -302,12 +302,18 @@ static uint32_t get_power_down_flags()
{
// Where needed, convert AUTO options to ON. Later interpret AUTO as OFF.
// RTC_SLOW_MEM is needed only for the ULP.
// If RTC_SLOW_MEM is Auto, and ULP wakeup isn't enabled, power down RTC_SLOW_MEM.
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] == ESP_PD_OPTION_AUTO) {
if (s_config.wakeup_triggers & RTC_SAR_TRIG_EN) {
s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] = ESP_PD_OPTION_ON;
}
// RTC_SLOW_MEM is needed for the ULP, so keep RTC_SLOW_MEM powered up if ULP
// is used and RTC_SLOW_MEM is Auto.
// If there is any data placed into .rtc.data or .rtc.bss segments, and
// RTC_SLOW_MEM is Auto, keep it powered up as well.
// These labels are defined in the linker script:
extern int _rtc_data_start, _rtc_data_end, _rtc_bss_start, _rtc_bss_end;
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] == ESP_PD_OPTION_AUTO ||
&_rtc_data_end > &_rtc_data_start ||
&_rtc_bss_end > &_rtc_bss_start) {
s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] = ESP_PD_OPTION_ON;
}
// RTC_FAST_MEM is needed for deep sleep stub.

View File

@ -26,7 +26,7 @@
// Forces data into DRAM instead of flash
#define DRAM_ATTR __attribute__((section(".dram1")))
// Forces a string into DRAM instrad of flash
// Forces a string into DRAM instead of flash
// Use as ets_printf(DRAM_STR("Hello world!\n"));
#define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;}))

View File

@ -383,6 +383,18 @@ void ets_delay_us(uint32_t us);
*/
void ets_update_cpu_frequency(uint32_t ticks_per_us);
/**
* @brief Set the real CPU ticks per us to the ets, so that ets_delay_us will be accurate.
*
* @note This function only sets the tick rate for the current CPU. It is located in ROM,
* so the deep sleep stub can use it even if IRAM is not initialized yet.
*
* @param uint32_t ticks_per_us : CPU ticks per us.
*
* @return None
*/
void ets_update_cpu_frequency_rom(uint32_t ticks_per_us);
/**
* @brief Get the real CPU ticks per us to the ets.
* This function do not return real CPU ticks per us, just the record in ets. It can be used to check with the real CPU frequency.

View File

@ -53,16 +53,18 @@ extern "C" {
* Rtc store registers usage
* RTC_CNTL_STORE0_REG
* RTC_CNTL_STORE1_REG
* RTC_CNTL_STORE2_REG
* RTC_CNTL_STORE3_REG
* RTC_CNTL_STORE4_REG Reserved
* RTC_CNTL_STORE5_REG External Xtal Frequency
* RTC_CNTL_STORE2_REG Boot time, low word
* RTC_CNTL_STORE3_REG Boot time, high word
* RTC_CNTL_STORE4_REG External XTAL frequency
* RTC_CNTL_STORE5_REG APB bus frequency
* RTC_CNTL_STORE6_REG FAST_RTC_MEMORY_ENTRY
* RTC_CNTL_STORE7_REG FAST_RTC_MEMORY_CRC
*************************************************************************************
*/
#define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG
#define RTC_MEMORY_CRC_REG RTC_CNTL_STORE7_REG
#define RTC_BOOT_TIME_LOW_REG RTC_CNTL_STORE2_REG
#define RTC_BOOT_TIME_HIGH_REG RTC_CNTL_STORE3_REG
#define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG
#define RTC_MEMORY_CRC_REG RTC_CNTL_STORE7_REG
typedef enum {

View File

@ -19,9 +19,11 @@ SECTIONS
*/
.rtc.data :
{
_rtc_data_start = ABSOLUTE(.);
*(.rtc.data)
*(.rtc.rodata)
*rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*)
_rtc_data_end = ABSOLUTE(.);
} > rtc_slow_seg
/* RTC bss, from any source file named rtc_wake_stub*.c */

View File

@ -202,7 +202,7 @@ PROVIDE ( ets_timer_init = 0x400084e8 );
PROVIDE ( ets_timer_setfn = 0x40008350 );
PROVIDE ( ets_unpack_flash_code = 0x40007018 );
PROVIDE ( ets_unpack_flash_code_legacy = 0x4000694c );
/* PROVIDE ( ets_update_cpu_frequency = 0x40008550 ); */ /* Updates g_ticks_per_us on the current CPU only; not on the other core */
PROVIDE ( ets_update_cpu_frequency_rom = 0x40008550 ); /* Updates g_ticks_per_us on the current CPU only; not on the other core */
PROVIDE ( ets_waiti0 = 0x400067d8 );
PROVIDE ( exc_cause_table = 0x3ff991d0 );
PROVIDE ( _exit_r = 0x4000bd28 );

View File

@ -21,6 +21,7 @@
#include <sys/time.h>
#include <sys/times.h>
#include <sys/lock.h>
#include <rom/rtc.h>
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "soc/soc.h"
@ -58,9 +59,9 @@ static uint64_t get_rtc_time_us()
// s_boot_time: time from Epoch to the first boot time
#ifdef WITH_RTC
static RTC_DATA_ATTR struct timeval s_boot_time;
// when RTC is used to persist time, two RTC_STORE registers are used to store boot time
#elif defined(WITH_FRC1)
static struct timeval s_boot_time;
static uint64_t s_boot_time;
#endif
#if defined(WITH_RTC) || defined(WITH_FRC1)
@ -88,6 +89,31 @@ static void IRAM_ATTR frc_timer_isr()
#endif // WITH_FRC1
static void set_boot_time(uint64_t time_us)
{
_lock_acquire(&s_boot_time_lock);
#ifdef WITH_RTC
REG_WRITE(RTC_BOOT_TIME_LOW_REG, (uint32_t) (time_us & 0xffffffff));
REG_WRITE(RTC_BOOT_TIME_HIGH_REG, (uint32_t) (time_us >> 32));
#else
s_boot_time = time_us;
#endif
_lock_release(&s_boot_time_lock);
}
static uint64_t get_boot_time()
{
uint64_t result;
_lock_acquire(&s_boot_time_lock);
#ifdef WITH_RTC
result = ((uint64_t) REG_READ(RTC_BOOT_TIME_LOW_REG)) + (((uint64_t) REG_READ(RTC_BOOT_TIME_HIGH_REG)) << 32);
#else
result = s_boot_time;
#endif
_lock_release(&s_boot_time_lock);
return result;
}
void esp_setup_time_syscalls()
{
#if defined( WITH_FRC1 )
@ -148,13 +174,10 @@ int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz)
{
(void) tz;
#if defined( WITH_FRC1 ) || defined( WITH_RTC )
uint64_t microseconds = get_time_since_boot();
if (tv) {
_lock_acquire(&s_boot_time_lock);
microseconds += s_boot_time.tv_usec;
tv->tv_sec = s_boot_time.tv_sec + microseconds / 1000000;
uint64_t microseconds = get_boot_time() + get_time_since_boot();
tv->tv_sec = microseconds / 1000000;
tv->tv_usec = microseconds % 1000000;
_lock_release(&s_boot_time_lock);
}
return 0;
#else
@ -168,14 +191,9 @@ int settimeofday(const struct timeval *tv, const struct timezone *tz)
(void) tz;
#if defined( WITH_FRC1 ) || defined( WITH_RTC )
if (tv) {
_lock_acquire(&s_boot_time_lock);
uint64_t now = ((uint64_t) tv->tv_sec) * 1000000LL + tv->tv_usec;
uint64_t since_boot = get_time_since_boot();
uint64_t boot_time = now - since_boot;
s_boot_time.tv_sec = boot_time / 1000000;
s_boot_time.tv_usec = boot_time % 1000000;
_lock_release(&s_boot_time_lock);
set_boot_time(now - since_boot);
}
return 0;
#else

View File

@ -73,6 +73,8 @@ By default, ``esp_deep_sleep_start`` function will power down all RTC power doma
Note: on the first revision of the ESP32, RTC fast memory will always be kept enabled in deep sleep, so that the deep sleep stub can run after reset. This can be overriden, if the application doesn't need clean reset behaviour after deep sleep.
If some variables in the program are placed into RTC slow memory (for example, using ``RTC_DATA_ATTR`` attribute), RTC slow memory will be kept powered on by default. This can be overriden using ``esp_deep_sleep_pd_config`` function, if desired.
.. doxygenfunction:: esp_deep_sleep_pd_config
.. doxygenenum:: esp_deep_sleep_pd_domain_t
.. doxygenenum:: esp_deep_sleep_pd_option_t