]> granicus.if.org Git - esp-idf/commitdiff
esp32: Bootloader wake deep sleep stub
authorAngus Gratton <angus@espressif.com>
Mon, 12 Sep 2016 07:23:15 +0000 (17:23 +1000)
committerWu Jian Gang <wujiangang@espressif.com>
Wed, 28 Sep 2016 03:14:58 +0000 (11:14 +0800)
App can contain a stub program resident in RTC fast memory. Bootloader
will load the stub on initial boot. If the device wakes from deep sleep,
the stub is run immediately (before any other data is loaded, etc.)

To implement a custom wake stub, implement a function in your program:

```
void RTC_IRAM_ATTR esp_wake_deep_sleep(void)
{
  esp_default_wake_deep_sleep();
  // other wake logic
}
```

... and it will replace the default implementation.

12 files changed:
components/bootloader/src/main/bootloader_config.h
components/bootloader/src/main/bootloader_start.c
components/esp32/cpu_start.c
components/esp32/deepsleep.c [new file with mode: 0644]
components/esp32/include/esp_attr.h
components/esp32/include/esp_deepsleep.h [new file with mode: 0644]
components/esp32/include/esp_system.h
components/esp32/include/rom/rtc.h
components/esp32/ld/esp32.bt.ld
components/esp32/ld/esp32.bt.trace.ld
components/esp32/ld/esp32.common.ld
components/esp32/ld/esp32.ld

index 7ad97af6743b258d976432384a4372a67d4944a9..709ff41b1655e1da8edf196ba976df8b3919c427 100644 (file)
@@ -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 {
index 6b3298c29ce1047c6c5171c8513c57eebcbc6035..e0ab7f9e2a23963860fc185c4837f06b18540650 100644 (file)
@@ -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;
index 7b2ccdc609610a977f21657c0be9c45b110ab8f7..fb97cce47efd455f21e667c6c78c0e058bb70977 100644 (file)
@@ -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 (file)
index 0000000..ee188c2
--- /dev/null
@@ -0,0 +1,45 @@
+/* Wake from deep sleep stub
+
+   See esp_deepsleep.h esp_wake_deep_sleep() comments for details.
+*/
+#include <stddef.h>
+#include <sys/lock.h>
+#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);
index 18a611489ba9c62fc849bee3c011fc4ce4c07a4f..156d2957f97d4e93694774d276477fac1d5c2e4e 100644 (file)
@@ -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")))
 // 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 (file)
index 0000000..3683a8e
--- /dev/null
@@ -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 <stdint.h>
+
+#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__ */
index 3a479060b68590399f14bdcb5d4d08a2ca318a79..0a77044cfcb5935a6f95147269dea81be1c86e99 100644 (file)
@@ -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.
   *
index d8c0c789a3a8b8fb277f5ad2665c16c5c416b385..665b97c8ea455e3d7a7b6ddc729b53811d517256 100644 (file)
@@ -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 {
index 90d0f491bc46a1f35aaf20374253ba4fdecf56d2..ccf0821ae130907e42ff08c654711380aa604641 100644 (file)
@@ -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;
index d4d7069eb07371cdfc9efeeb0bbe03d848fc3482..78cedeb290b505b2f1d62187fcd84b48eb9f5ac6 100644 (file)
@@ -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;
index 3fb4ca761c1dbecd1d893f908257f1c64e9a3b58..a3c6367840e84b40da1b2446704575f720272c3e 100644 (file)
@@ -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
 }
index becbc6baac0477dc2469e253ab1f34b0287ffd82..6c67c7d79d5f474d53702aaa4c8476a8393851c0 100644 (file)
@@ -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;