mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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:
commit
03d78e7afb
@ -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__ */
|
||||
|
@ -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 :
|
||||
{
|
||||
@ -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 :
|
||||
{
|
||||
|
123
components/esp32/test/test_noinit.c
Normal file
123
components/esp32/test/test_noinit.c
Normal 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
|
@ -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
|
||||
-----------------------
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user