. = ALIGN(4);
*(.rtc.literal .rtc.text)
*rtc_wake_stub*.o(.literal .text .literal.* .text.*)
- } >rtc_iram_seg
+ } > rtc_iram_seg
/* RTC slow memory holds RTC wake stub
data/rodata, including from any source file
_rtc_bss_end = ABSOLUTE(.);
} > rtc_slow_seg
+ /* This section holds data that should not be initialized at power up
+ and will be retained during deep sleep. The section located in
+ RTC SLOW Memory area. User data marked with RTC_NOINIT_ATTR will be placed
+ into this section. See the file "esp_attr.h" for more information.
+ */
+ .rtc_noinit (NOLOAD):
+ {
+ . = ALIGN(4);
+ _rtc_noinit_start = ABSOLUTE(.);
+ *(.rtc_noinit .rtc_noinit.*)
+ . = ALIGN(4) ;
+ _rtc_noinit_end = ABSOLUTE(.);
+ } > rtc_slow_seg
+
/* Send .iram0 code to iram */
.iram0.vectors :
{
INCLUDE esp32.spiram.rom-functions-iram.ld
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
-
+
.dram0.data :
{
_data_start = ABSOLUTE(.);
INCLUDE esp32.spiram.rom-functions-dram.ld
_data_end = ABSOLUTE(.);
. = ALIGN(4);
- } >dram0_0_seg
+ } > dram0_0_seg
+
+ /*This section holds data that should not be initialized at power up.
+ The section located in Internal SRAM memory region. The macro _NOINIT
+ can be used as attribute to place data into this section.
+ See the esp_attr.h file for more information.
+ */
+ .noinit (NOLOAD):
+ {
+ . = ALIGN(4);
+ _noinit_start = ABSOLUTE(.);
+ *(.noinit .noinit.*)
+ . = ALIGN(4) ;
+ _noinit_end = ABSOLUTE(.);
+ } > dram0_0_seg
/* Shared RAM */
.dram0.bss (NOLOAD) :
*(COMMON)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
+ /* The heap starts right after end of this section */
_heap_start = ABSOLUTE(.);
- } >dram0_0_seg
+ } > dram0_0_seg
.flash.rodata :
{
--- /dev/null
+#include "unity.h"
+#include "esp_system.h"
+#include "rom/rtc.h"
+#include "esp_log.h"
+
+// This is a test sequence to test behavior of .rtc_noinit and .noinit sections.
+// The values placed into .rtc_noinit section go to RTC SLOW Memory segment and
+// keep their value after reset and deep sleep. Use new added attribute macro
+// RTC_NOINIT_ATTR for this behavior. The second macro - __NOINIT_ATTR places value
+// into .noinit section which goes to SRAM and will not be initialized after reset.
+
+#define RTC_NOINIT_PATTERN 0xAAAAAAAA
+#define _NOINIT_PATTERN 0x55555555
+
+static __NOINIT_ATTR uint32_t noinit_data;
+static RTC_NOINIT_ATTR uint32_t rtc_noinit_data;
+
+extern int _rtc_noinit_start;
+extern int _rtc_noinit_end;
+extern int _noinit_start;
+extern int _noinit_end;
+
+// Pointers to the values
+uint32_t *noinit_val_addr = (uint32_t*)&noinit_data;
+uint32_t *rtc_noinit_val_addr = (uint32_t*)&rtc_noinit_data;
+
+static const char* tag = "noinit_UnitTestMain";
+
+static esp_err_t check_data_seg(uint32_t *value_address, \
+ uint32_t *seg_start, uint32_t *seg_end)
+{
+ esp_err_t result = ESP_FAIL;
+ if (((uint32_t)value_address <= (uint32_t)seg_end) && \
+ ((uint32_t)value_address >= (uint32_t)seg_start)){
+ result = ESP_OK;
+ }
+ return result;
+}
+
+static void setup_attributes(void)
+{
+ rtc_noinit_data = RTC_NOINIT_PATTERN;
+ noinit_data = _NOINIT_PATTERN;
+}
+
+static void init_attributes(void)
+{
+ setup_attributes();
+ printf("noinit_data = 0x%X \n", (uint32_t)*noinit_val_addr);
+ printf("rtc_noinit_data = 0x%X \n", (uint32_t)*rtc_noinit_val_addr);
+ TEST_ASSERT(*noinit_val_addr == noinit_data);
+ TEST_ASSERT(*rtc_noinit_val_addr == rtc_noinit_data);
+}
+
+static void reset_reason_power_on(void)
+{
+ printf("This test case checks behavior of noinit variables POWERON_RESET sequence. \n");
+ RESET_REASON reason = rtc_get_reset_reason(0);
+ ESP_LOGI(tag, "POWERON_RESET reset values = (0x%X), (0x%X), reset reason=(%d)\n", \
+ (uint32_t)*noinit_val_addr, (uint32_t)*rtc_noinit_val_addr, (uint16_t)reason);
+ TEST_ASSERT((reason == POWERON_RESET) || (reason == RTCWDT_RTC_RESET));
+
+ init_attributes();
+ TEST_ASSERT(check_data_seg(noinit_val_addr, \
+ (uint32_t*)&_noinit_start, \
+ (uint32_t*)&_noinit_end) == ESP_OK);
+ TEST_ASSERT(check_data_seg(rtc_noinit_val_addr, \
+ (uint32_t*)&_rtc_noinit_start, \
+ (uint32_t*)&_rtc_noinit_end) == ESP_OK);
+ TEST_ASSERT(_NOINIT_PATTERN == *noinit_val_addr);
+ TEST_ASSERT(RTC_NOINIT_PATTERN == *rtc_noinit_val_addr);
+
+ printf("Next test case will check SOFTWARE_RESET behavior. \n");
+ esp_restart();
+}
+
+static void reset_reason_sw_reset(void)
+{
+ printf("This test case checks behavior of noinit variables after software reset sequence. \n");
+ RESET_REASON reason = rtc_get_reset_reason(0);
+ ESP_LOGI(tag, "SW_CPU_RESET reset values = (0x%X), (0x%X), reset reason=(%d)\n", \
+ (uint32_t)*noinit_val_addr, (uint32_t)*rtc_noinit_val_addr, (uint16_t)reason);
+ TEST_ASSERT(reason == SW_CPU_RESET);
+ TEST_ASSERT(check_data_seg(noinit_val_addr, \
+ (uint32_t*)&_noinit_start, \
+ (uint32_t*)&_noinit_end) == ESP_OK);
+ TEST_ASSERT(check_data_seg(rtc_noinit_val_addr, \
+ (uint32_t*)&_rtc_noinit_start, \
+ (uint32_t*)&_rtc_noinit_end) == ESP_OK);
+ // The ROM bootloader behavior may apply to this assert.
+ // TEST_ASSERT(0x55555555 == *noinit_val_addr);
+ TEST_ASSERT(RTC_NOINIT_PATTERN == *rtc_noinit_val_addr);
+ printf("Go to deep sleep to check DEEP_SLEEP_RESET behavior. \n");
+ esp_sleep_enable_timer_wakeup(2000000);
+ esp_deep_sleep_start();
+}
+
+static void reset_reason_deep_sleep(void)
+{
+ printf("This test case checks behavior of noinit variables after deep sleep reset. \n");
+ RESET_REASON reason = rtc_get_reset_reason(0);
+ ESP_LOGI(tag, "DEEP_SLEEP_RESET reset values = (0x%X), (0x%X), reset reason=(%d)\n", \
+ (uint32_t)*noinit_val_addr, (uint32_t)*rtc_noinit_val_addr, (uint16_t)reason);
+ TEST_ASSERT(reason == DEEPSLEEP_RESET);
+ TEST_ASSERT(check_data_seg(noinit_val_addr, \
+ (uint32_t*)&_noinit_start, \
+ (uint32_t*)&_noinit_end) == ESP_OK);
+ TEST_ASSERT(check_data_seg(rtc_noinit_val_addr, \
+ (uint32_t*)&_rtc_noinit_start, \
+ (uint32_t*)&_rtc_noinit_end) == ESP_OK);
+ TEST_ASSERT(RTC_NOINIT_PATTERN == *rtc_noinit_val_addr);
+ printf("The noinit test cases are done.. \n");
+}
+
+// The lines below are required to suppress GCC warnings about casting of function pointers
+// in unity macro expansion. These warnings may be treated as errors during automated test.
+#pragma GCC diagnostic push // required for GCC
+#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
+// The multiple stages test case to check values after certain reset reason
+TEST_CASE_MULTIPLE_STAGES("NOINIT attributes behavior",
+ "[restart][reset=SW_CPU_RESET, DEEPSLEEP_RESET]",
+ reset_reason_power_on, reset_reason_sw_reset, reset_reason_deep_sleep);
+#pragma GCC diagnostic pop // require GCC