Merge branch 'feature/Add_noinit_rtc_noinit_sections' into 'master'

esp32: Add .noinit and .rtc_noinit sections to the linker script

See merge request idf/esp-idf!1996
This commit is contained in:
Ivan Grokhotkov 2018-06-08 16:01:30 +08:00
commit 03d78e7afb
4 changed files with 176 additions and 4 deletions

View file

@ -47,4 +47,12 @@
// Forces read-only data into RTC slow memory. See "docs/deep-sleep-stub.rst"
#define RTC_RODATA_ATTR __attribute__((section(".rtc.rodata")))
// Forces data into noinit section to avoid initialization after restart.
#define __NOINIT_ATTR __attribute__((section(".noinit")))
// Forces data into RTC slow memory of .noinit section.
// Any variable marked with this attribute will keep its value
// after restart or during a deep sleep / wake cycle.
#define RTC_NOINIT_ATTR __attribute__((section(".rtc_noinit")))
#endif /* __ESP_ATTR_H__ */

View file

@ -11,7 +11,7 @@ SECTIONS
. = 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
@ -35,6 +35,20 @@ SECTIONS
_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 :
{
@ -98,7 +112,7 @@ SECTIONS
INCLUDE esp32.spiram.rom-functions-iram.ld
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
.dram0.data :
{
_data_start = ABSOLUTE(.);
@ -124,7 +138,21 @@ SECTIONS
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) :
@ -147,8 +175,9 @@ SECTIONS
*(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 :
{

View file

@ -0,0 +1,123 @@
#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

View file

@ -111,6 +111,12 @@ Constant data may also be placed into DRAM, for example if it is used in an ISR
Needless to say, it is not advised to use ``printf`` and other output functions in ISRs. For debugging purposes, use ``ESP_EARLY_LOGx`` macros when logging from ISRs. Make sure that both ``TAG`` and format string are placed into ``DRAM`` in that case.
The macro ``__NOINIT_ATTR`` can be used as attribute to place data into ``.noinit`` section. The values placed into this section will not be initialized at startup and keep its value after software restart.
Example::
__NOINIT_ATTR uint32_t noinit_data;
DROM (data stored in Flash)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -121,6 +127,12 @@ RTC slow memory
Global and static variables used by code which runs from RTC memory (i.e. deep sleep stub code) must be placed into RTC slow memory. Please check detailed description in :doc:`deep sleep <deep-sleep-stub>` documentation.
The attribute macro named ``RTC_NOINIT_ATTR`` can be used to place data into this type of memory. The values placed into this section keep their value after waking from deep sleep.
Example::
RTC_NOINIT_ATTR uint32_t rtc_noinit_data;
DMA Capable Requirement
-----------------------