diff --git a/components/bootloader/src/main/bootloader_config.h b/components/bootloader/src/main/bootloader_config.h index 7ad97af67..709ff41b1 100644 --- a/components/bootloader/src/main/bootloader_config.h +++ b/components/bootloader/src/main/bootloader_config.h @@ -30,6 +30,10 @@ extern "C" #define IROM_HIGH 0x40400000 #define DROM_LOW 0x3F400000 #define DROM_HIGH 0x3F800000 +#define RTC_IRAM_LOW 0x400C0000 +#define RTC_IRAM_HIGH 0x400C2000 +#define RTC_DATA_LOW 0x50000000 +#define RTC_DATA_HIGH 0x50002000 /*spi mode,saved in third byte in flash */ enum { diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index 6b3298c29..e0ab7f9e2 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -22,6 +22,7 @@ #include "rom/ets_sys.h" #include "rom/spi_flash.h" #include "rom/crc.h" +#include "rom/rtc.h" #include "soc/soc.h" #include "soc/cpu.h" @@ -362,11 +363,15 @@ void unpack_load_app(const partition_pos_t* partition) uint32_t irom_load_addr = 0; uint32_t irom_size = 0; + /* Reload the RTC memory sections whenever a non-deepsleep reset + is occuring */ + bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET; + ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic, - image_header.blocks, - image_header.spi_mode, - image_header.spi_size, - (unsigned)image_header.entry_addr); + image_header.blocks, + image_header.spi_mode, + image_header.spi_size, + (unsigned)image_header.entry_addr); for (uint32_t section_index = 0; section_index < image_header.blocks; @@ -406,7 +411,18 @@ void unpack_load_app(const partition_pos_t* partition) map = true; } - ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos, section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":""); + if(!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) { + ESP_LOGD(TAG, "Skipping RTC code section at %08x\n", pos); + load = false; + } + + if(!load_rtc_memory && address >= RTC_DATA_LOW && address < RTC_DATA_HIGH) { + ESP_LOGD(TAG, "Skipping RTC data section at %08x\n", pos); + load = false; + } + + ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos, + section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":""); if (!load) { pos += section_header.data_len; diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 7b2ccdc60..fb97cce47 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -42,6 +42,7 @@ #include "esp_spi_flash.h" #include "esp_ipc.h" #include "esp_log.h" +#include "esp_deepsleep.h" void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))); void start_cpu0_default(void) IRAM_ATTR; diff --git a/components/esp32/deepsleep.c b/components/esp32/deepsleep.c new file mode 100644 index 000000000..ee188c25d --- /dev/null +++ b/components/esp32/deepsleep.c @@ -0,0 +1,45 @@ +/* Wake from deep sleep stub + + See esp_deepsleep.h esp_wake_deep_sleep() comments for details. +*/ +#include +#include +#include "rom/cache.h" +#include "rom/rtc.h" +#include "soc/rtc_cntl_reg.h" +#include "esp_attr.h" +#include "esp_deepsleep.h" + +/* Updating RTC_MEMORY_CRC_REG register via set_rtc_memory_crc() + is not thread-safe. */ +static _lock_t lock_rtc_memory_crc; + +esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void) +{ + _lock_acquire(&lock_rtc_memory_crc); + uint32_t stored_crc = REG_READ(RTC_MEMORY_CRC_REG); + set_rtc_memory_crc(); + uint32_t calc_crc = REG_READ(RTC_MEMORY_CRC_REG); + REG_WRITE(RTC_MEMORY_CRC_REG, stored_crc); + _lock_release(&lock_rtc_memory_crc); + + if(stored_crc == calc_crc) { + return (esp_deep_sleep_wake_stub_fn_t)REG_READ(RTC_ENTRY_ADDR_REG); + } else { + return NULL; + } +} + +void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub) +{ + _lock_acquire(&lock_rtc_memory_crc); + REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)new_stub); + set_rtc_memory_crc(); + _lock_release(&lock_rtc_memory_crc); +} + +void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) { + mmu_init(0); +} + +void __attribute__((weak, alias("esp_default_wake_deep_sleep"))) esp_wake_deep_sleep(void); diff --git a/components/esp32/include/esp_attr.h b/components/esp32/include/esp_attr.h index 18a611489..156d2957f 100644 --- a/components/esp32/include/esp_attr.h +++ b/components/esp32/include/esp_attr.h @@ -17,8 +17,8 @@ #define ROMFN_ATTR //Normally, the linker script will put all code and rodata in flash, -//and all variables in shared RAM. This can be redirected to IRAM if -//needed using these macros. +//and all variables in shared RAM. These macros can be used to redirect +//particular functions/variables to other memory regions. // Forces code into IRAM instead of flash #define IRAM_ATTR __attribute__((section(".iram1"))) @@ -26,4 +26,16 @@ // Forces data into DRAM instead of flash #define DRAM_ATTR __attribute__((section(".dram1"))) +// Forces code into RTC fast memory +#define RTC_IRAM_ATTR __attribute__((section(".rtc.text"))) + +// Forces data into RTC slow memory +// Any variable marked with this attribute will keep its value +// during a deep sleep / wake cycle. +#define RTC_DATA_ATTR __attribute__((section(".rtc.data"))) + +// Forces read-only data into RTC slow memory +// Makes constant data available to RTC wake stubs (see esp_deepsleep.h) +#define RTC_RODATA_ATTR __attribute__((section(".rtc.rodata"))) + #endif /* __ESP_ATTR_H__ */ diff --git a/components/esp32/include/esp_deepsleep.h b/components/esp32/include/esp_deepsleep.h new file mode 100644 index 000000000..3683a8eea --- /dev/null +++ b/components/esp32/include/esp_deepsleep.h @@ -0,0 +1,137 @@ +// Copyright 2015-2016 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. + +#ifndef __ESP_DEEPSLEEP_H__ +#define __ESP_DEEPSLEEP_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup Deep_Sleep_API Deep Sleep API + * @brief API for putting device into deep sleep + */ + +/** @addtogroup Deep_Sleep_API + * @{ + */ + +/** + * @brief Set the chip to deep-sleep mode. + * + * The device will automatically wake up after the deep-sleep time set + * by the users. Upon waking up, the device boots up from user_init. + * + * @attention The parameter time_in_us to be "uint64" is for further development. + * Only the low 32 bits of parameter time_in_us are avalable now. + * + * @param uint64 time_in_us : deep-sleep time, only the low 32bits are avalable now. unit: microsecond + * + * @return null + */ +void system_deep_sleep(uint64_t time_in_us); + +/** + * @brief Default stub to run on wake from deep sleep. + * + * Allows for executing code immediately on wake from sleep, before + * the software bootloader or esp-idf app has started up. + * + * This function is weak-linked, so you can implement your own version + * to run code immediately when the chip wakes from + * sleep. + * + * For example: + * @code + * void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { + * esp_default_wake_deep_sleep(); + * // Add additional functionality here + * } + * + * (Implementing this function is not required for normal operation, + * in the usual case your app will start normally when waking from + * deep sleep.) + * + * esp_wake_deep_sleep() functionality is limited: + * + * - Runs immediately on wake, so most of the SoC is freshly reset - + * flash is unmapped and hardware is otherwise uninitialised. + * + * - Can only call functions implemented in ROM, or marked RTC_IRAM_ATTR. + * + * - Static variables marked RTC_DATA_ATTR will have initial values on + * cold boot, and maintain these values between sleep/wake cycles. + * + * - Read-only data should be marked RTC_RODATA_ATTR. Strings must be + * declared as variables also using RTC_RODATA_ATTR, like this: + * RTC_RODATA_ATTR const char message[] = "Hello from very early boot!\n"; + * + * - Any other static memory will not be initialised (either to zero, + * or to any predefined value). + * + * + * - If you implement your own stub, the first call the stub makes + should be to esp_default_wake_deep_sleep(). + */ +void esp_wake_deep_sleep(void); + +/** + * @brief Function type for stub to run on wake from sleep. + * + */ +typedef void (*esp_deep_sleep_wake_stub_fn_t)(void); + +/** + * @brief Install a new stub at runtime to run on wake from deep sleep + * + * If implementing esp_wake_deep_sleep() then it is not necessary to + * call this function. + * + * However, it is possible to call this function to substitute a + * different deep sleep stub. Any function used as a deep sleep stub + * must be marked RTC_IRAM_ATTR, and must obey the same rules given + * for esp_wake_deep_sleep(). + */ +void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub); + +/** + * @brief Return current wake from deep sleep stub, or NULL if + * no stub is installed. + */ +esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void); + +/* The default esp-idf-provided esp_wake_deep_sleep() stub. + + If you replace esp_wake_deep_sleep() in your program, or use + esp_set_deep_sleep_wake_stub(), then it is recommended you call + esp_default_wake_deep_sleep() as the first function in your stub. +*/ +void esp_default_wake_deep_sleep(void); + +/** + * @} + */ + + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_SYSTEM_H__ */ diff --git a/components/esp32/include/esp_system.h b/components/esp32/include/esp_system.h index 3a479060b..0a77044cf 100644 --- a/components/esp32/include/esp_system.h +++ b/components/esp32/include/esp_system.h @@ -62,21 +62,6 @@ void system_restore(void); */ void system_restart(void); -/** - * @brief Set the chip to deep-sleep mode. - * - * The device will automatically wake up after the deep-sleep time set - * by the users. Upon waking up, the device boots up from user_init. - * - * @attention The parameter time_in_us to be "uint64" is for further development. - * Only the low 32 bits of parameter time_in_us are avalable now. - * - * @param uint64 time_in_us : deep-sleep time, only the low 32bits are avalable now. unit: microsecond - * - * @return null - */ -void system_deep_sleep(uint64_t time_in_us); - /** * @brief Get system time, unit: microsecond. * diff --git a/components/esp32/include/rom/rtc.h b/components/esp32/include/rom/rtc.h index d8c0c789a..665b97c8e 100644 --- a/components/esp32/include/rom/rtc.h +++ b/components/esp32/include/rom/rtc.h @@ -51,18 +51,18 @@ extern "C" { * ************************************************************************************* * Rtc store registers usage - * RTC_STORE0 - * RTC_STORE1 - * RTC_STORE2 - * RTC_STORE3 - * RTC_STORE4 Reserved - * RTC_STORE5 External Xtal Frequency - * RTC_STORE6 FAST_RTC_MEMORY_ENTRY - * RTC_STORE7 FAST_RTC_MEMORY_CRC + * 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_STORE6_REG FAST_RTC_MEMORY_ENTRY + * RTC_CNTL_STORE7_REG FAST_RTC_MEMORY_CRC ************************************************************************************* */ -#define RTC_ENTRY_ADDR RTC_STORE6 -#define RTC_MEMORY_CRC RTC_STORE7 +#define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG +#define RTC_MEMORY_CRC_REG RTC_CNTL_STORE7_REG typedef enum { diff --git a/components/esp32/ld/esp32.bt.ld b/components/esp32/ld/esp32.bt.ld index 90d0f491b..ccf0821ae 100644 --- a/components/esp32/ld/esp32.bt.ld +++ b/components/esp32/ld/esp32.bt.ld @@ -9,6 +9,12 @@ MEMORY iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000 /* Even though the segment name is iram, it is actually mapped to flash */ dram0_0_seg (RW) : org = 0x3FFC0000, len = 0x40000 /* Shared RAM, minus rom bss/data/stack.*/ drom0_0_seg (R) : org = 0x3F400010, len = 0x800000 + + /* RTC fast memory (executable). Persists over deep sleep. + */ + rtc_iram_seg(RWX) : org = 0x400C0000, len = 0x2000 + /* RTC slow memory (data accessible). Persists over deep sleep. */ + rtc_slow_seg(RW) : org = 0x50000000, len = 0x2000 } _heap_end = 0x40000000; diff --git a/components/esp32/ld/esp32.bt.trace.ld b/components/esp32/ld/esp32.bt.trace.ld index d4d7069eb..78cedeb29 100644 --- a/components/esp32/ld/esp32.bt.trace.ld +++ b/components/esp32/ld/esp32.bt.trace.ld @@ -9,6 +9,12 @@ MEMORY iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000 /* Even though the segment name is iram, it is actually mapped to flash */ dram0_0_seg (RW) : org = 0x3FFC0000, len = 0x38000 /* Shared RAM, minus rom bss/data/stack.*/ drom0_0_seg (R) : org = 0x3F400010, len = 0x800000 + + /* RTC fast memory (executable). Persists over deep sleep. + */ + rtc_iram_seg(RWX) : org = 0x400C0000, len = 0x2000 + /* RTC slow memory (data accessible). Persists over deep sleep. */ + rtc_slow_seg(RW) : org = 0x50000000, len = 0x2000 } _heap_end = 0x3FFF8000; diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index 3fb4ca761..a3c636784 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -102,7 +102,7 @@ SECTIONS _rodata_start = ABSOLUTE(.); *(.rodata) *(.rodata.*) - *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); @@ -132,7 +132,7 @@ SECTIONS *(.dynamic) *(.gnu.version_d) _rodata_end = ABSOLUTE(.); - /* Literals are also RO data. */ + /* Literals are also RO data. */ _lit4_start = ABSOLUTE(.); *(*.lit4) *(.lit4.*) @@ -153,4 +153,16 @@ SECTIONS _text_end = ABSOLUTE(.); _etext = .; } >iram0_2_seg + + .rtc.text : + { + . = ALIGN(4); + *(.rtc.literal .rtc.text) + } >rtc_iram_seg + + .rtc.data : + { + *(.rtc.data) + *(.rtc.rodata) + } > rtc_slow_seg } diff --git a/components/esp32/ld/esp32.ld b/components/esp32/ld/esp32.ld index becbc6baa..6c67c7d79 100644 --- a/components/esp32/ld/esp32.ld +++ b/components/esp32/ld/esp32.ld @@ -9,6 +9,12 @@ MEMORY iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000 /* Even though the segment name is iram, it is actually mapped to flash */ dram0_0_seg (RW) : org = 0x3FFB0000, len = 0x50000 /* Shared RAM, minus rom bss/data/stack.*/ drom0_0_seg (R) : org = 0x3F400010, len = 0x800000 + + /* RTC fast memory (executable). Persists over deep sleep. + */ + rtc_iram_seg(RWX) : org = 0x400C0000, len = 0x2000 + /* RTC slow memory (data accessible). Persists over deep sleep. */ + rtc_slow_seg(RW) : org = 0x50000000, len = 0x2000 } _heap_end = 0x40000000;