From b85011c15fdd6a1024769e74b16fe487be2c5b9d Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Fri, 7 Feb 2020 00:00:13 +0000 Subject: [PATCH 1/6] esp32: Add support for noinit variables in SPIRAM Add Kconfig option SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY When enabled, a new linker script rule (from esp32.extram.noinit.ld) places any variables in the .ext_ram.noinit section in SPIRAM. This section is exempted from the startup SPIRAM memory test and is not zero-initialized or added to the malloc pool, making it usable for noinit variables that persist across reset. The EXT_RAM_NOINIT_ATTR macro places variables in this section. --- components/esp32/CMakeLists.txt | 87 ++++++++++++++++++- components/esp32/component.mk | 36 ++++++++ components/esp_common/include/esp_attr.h | 9 +- .../esp_hw_support/Kconfig.spiram.common | 8 ++ .../esp_hw_support/include/soc/esp32/spiram.h | 2 +- components/esp_hw_support/port/esp32/spiram.c | 33 +++++-- .../ld/esp32/esp32.extram.noinit.ld | 14 +++ components/esp_system/port/cpu_start.c | 10 ++- 8 files changed, 186 insertions(+), 13 deletions(-) create mode 100644 components/esp_system/ld/esp32/esp32.extram.noinit.ld diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index a6eaa1b31d..376de09d67 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -3,10 +3,89 @@ if(NOT "${target}" STREQUAL "esp32") return() endif() -if(NOT BOOTLOADER_BUILD) - # [refactor-todo] propagate these requirements for compatibility - # remove in the future - set(legacy_reqs driver efuse soc) +idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER) + +if(BOOTLOADER_BUILD) + # For bootloader, all we need from esp32 is headers + idf_component_register(INCLUDE_DIRS include REQUIRES xtensa) + target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld") +else() + # Regular app build + set(srcs + "cache_sram_mmu.c" + "dport_access.c" + "esp_himem.c" + "spiram.c" + "spiram_psram.c") + + set(include_dirs "include") + + set(requires driver efuse soc xtensa) #unfortunately rom/uart uses SOC registers directly + + # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function. + # esp_timer is added here because cpu_start.c uses esp_timer + set(priv_requires app_trace app_update bootloader_support esp_system log mbedtls nvs_flash pthread + spi_flash vfs espcoredump esp_common perfmon esp_timer esp_ipc esp_pm) + + idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + REQUIRES "${requires}" + PRIV_REQUIRES "${priv_requires}" + REQUIRED_IDF_TARGETS esp32) + + target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") + + if(CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY) + # This has to be linked before esp32.project.ld + target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.extram.noinit.ld") + endif() + + # Process the template file through the linker script generation mechanism, and use the output for linking the + # final binary + target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.project.ld.in" + PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32.project.ld") + + target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld") + target_link_libraries(${COMPONENT_LIB} PUBLIC gcc) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u call_user_start_cpu0") + + idf_build_get_property(config_dir CONFIG_DIR) + # Preprocess esp32.ld linker script to include configuration, becomes esp32_out.ld + set(LD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ld) + add_custom_command( + OUTPUT esp32_out.ld + COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o esp32_out.ld -I ${config_dir} ${LD_DIR}/esp32.ld + MAIN_DEPENDENCY ${LD_DIR}/esp32.ld + DEPENDS ${sdkconfig_header} + COMMENT "Generating linker script..." + VERBATIM) + + add_custom_target(esp32_linker_script DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld) + add_dependencies(${COMPONENT_LIB} esp32_linker_script) + + if(CONFIG_SPIRAM_CACHE_WORKAROUND) + # Note: Adding as a PUBLIC compile option here causes this option to propagate to all + # components that depend on esp32. + # + # To handle some corner cases, the same flag is set in project_include.cmake + target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue) + # also, make sure we link with this option so correct toolchain libs are pulled in + target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue) + # set strategy selected + # note that we don't need to set link options as the library linked is independent of this + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST) + target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst) + target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst) + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW) + target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw) + target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw) + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS) + target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops) + target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops) + endif() + endif() endif() idf_component_register(INCLUDE_DIRS include diff --git a/components/esp32/component.mk b/components/esp32/component.mk index ebd7a7d59b..1b831fd21f 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -1,3 +1,39 @@ # # Component Makefile # + +COMPONENT_SRCDIRS := . + +ifdef CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY + # This linker script must come before esp32.project.ld + LINKER_SCRIPTS += esp32.extram.noinit.ld +endif + +#Linker scripts used to link the final application. +#Warning: These linker scripts are only used when the normal app is compiled; the bootloader +#specifies its own scripts. +LINKER_SCRIPTS += $(COMPONENT_BUILD_DIR)/esp32.project.ld esp32.peripherals.ld + +#ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the +#linker will ignore panic_highint_hdl.S as it has no other files depending on any +#symbols in it. +COMPONENT_ADD_LDFLAGS += -L $(COMPONENT_PATH)/ld \ + -T esp32_out.ld \ + -u ld_include_panic_highint_hdl \ + $(addprefix -T ,$(LINKER_SCRIPTS)) \ + +# final linking of project ELF depends on all binary libraries, and +# all linker scripts (except esp32_out.ld, as this is code generated here.) +COMPONENT_ADD_LINKER_DEPS := $(addprefix ld/, $(filter-out $(COMPONENT_BUILD_DIR)/esp32.project.ld, $(LINKER_SCRIPTS))) \ + $(COMPONENT_BUILD_DIR)/esp32.project.ld + +# Preprocess esp32.ld linker script into esp32_out.ld +# +# The library doesn't really depend on esp32_out.ld, but it +# saves us from having to add the target to a Makefile.projbuild +$(COMPONENT_LIBRARY): esp32_out.ld + +esp32_out.ld: $(COMPONENT_PATH)/ld/esp32.ld ../include/sdkconfig.h + $(CC) -I ../include -C -P -x c -E $< -o $@ + +COMPONENT_EXTRA_CLEAN := esp32_out.ld $(COMPONENT_BUILD_DIR)/esp32.project.ld diff --git a/components/esp_common/include/esp_attr.h b/components/esp_common/include/esp_attr.h index 21e52bd67b..6be0d4e678 100644 --- a/components/esp_common/include/esp_attr.h +++ b/components/esp_common/include/esp_attr.h @@ -72,6 +72,14 @@ extern "C" { #define EXT_RAM_ATTR #endif +#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY +// Forces data into external memory noinit section to avoid initialization after restart. +#define EXT_RAM_NOINIT_ATTR _SECTION_ATTR_IMPL(".ext_ram.noinit", __COUNTER__) +#else +// Place in internal noinit section +#define EXT_RAM_NOINIT_ATTR __NOINIT_ATTR +#endif + // Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst" // Any variable marked with this attribute will keep its value // during a deep sleep / wake cycle. @@ -155,4 +163,3 @@ FORCE_INLINE_ATTR TYPE& operator<<=(TYPE& a, int b) { a <<= b; return a; } } #endif #endif /* __ESP_ATTR_H__ */ - diff --git a/components/esp_hw_support/Kconfig.spiram.common b/components/esp_hw_support/Kconfig.spiram.common index e10d5cf588..adc7872332 100644 --- a/components/esp_hw_support/Kconfig.spiram.common +++ b/components/esp_hw_support/Kconfig.spiram.common @@ -101,3 +101,11 @@ config SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY linker fragment scheme `extram_bss`. Note that the variables placed in SPIRAM using EXT_RAM_ATTR will be zero initialized. + +config SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY + bool "Enable placement of noinit segments in external memory" + default n + depends on SPIRAM + help + If enabled, noinit variables can be placed in PSRAM using EXT_RAM_NOINIT_ATTR. + If disabled, EXT_RAM_NOINIT_ATTR will act like __NOINIT_ATTR. diff --git a/components/esp_hw_support/include/soc/esp32/spiram.h b/components/esp_hw_support/include/soc/esp32/spiram.h index e58712d1fa..b931cb79b0 100644 --- a/components/esp_hw_support/include/soc/esp32/spiram.h +++ b/components/esp_hw_support/include/soc/esp32/spiram.h @@ -59,7 +59,7 @@ void esp_spiram_init_cache(void); * * @return true on success, false on failed memory test */ -bool esp_spiram_test(void); +bool esp_spiram_test(const void* keepout_addr_low, const void* keepout_addr_high); /** diff --git a/components/esp_hw_support/port/esp32/spiram.c b/components/esp_hw_support/port/esp32/spiram.c index eea2a49bc5..8c6da9afe2 100644 --- a/components/esp_hw_support/port/esp32/spiram.c +++ b/components/esp_hw_support/port/esp32/spiram.c @@ -55,6 +55,10 @@ static const char* TAG = "spiram"; #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY extern uint8_t _ext_ram_bss_start, _ext_ram_bss_end; #endif +#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY +extern uint8_t _ext_ram_noinit_start, _ext_ram_noinit_end; +#endif + static bool spiram_inited=false; @@ -79,7 +83,7 @@ static size_t spiram_size_usable_for_malloc(void) true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been initialized (in a two-core system) or after the heap allocator has taken ownership of the memory. */ -bool esp_spiram_test(void) +bool esp_spiram_test(const void* keepout_addr_low, const void* keepout_addr_high) { volatile int *spiram=(volatile int*)SOC_EXTRAM_DATA_LOW; size_t p; @@ -87,9 +91,19 @@ bool esp_spiram_test(void) int errct=0; int initial_err=-1; for (p=0; p<(s/sizeof(int)); p+=8) { + if ((keepout_addr_low <= (const void*)&spiram[p]) && ((const void*)&spiram[p] < keepout_addr_high)) { + continue; + } else if ((keepout_addr_low < (const void*)&spiram[p+1]) && ((const void*)&spiram[p+1] <= keepout_addr_high)) { + continue; + } spiram[p]=p^0xAAAAAAAA; } for (p=0; p<(s/sizeof(int)); p+=8) { + if ((keepout_addr_low <= (const void*)&spiram[p]) && ((const void*)&spiram[p] < keepout_addr_high)) { + continue; + } else if ((keepout_addr_low < (const void*)&spiram[p+1]) && ((const void*)&spiram[p+1] <= keepout_addr_high)) { + continue; + } if (spiram[p]!=(p^0xAAAAAAAA)) { errct++; if (errct==1) initial_err=p*4; @@ -172,13 +186,20 @@ esp_err_t esp_spiram_add_to_heapalloc(void) { //Add entire external RAM region to heap allocator. Heap allocator knows the capabilities of this type of memory, so there's //no need to explicitly specify them. + intptr_t mallocable_ram_start = (intptr_t)SOC_EXTRAM_DATA_LOW; #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (spiram_size_usable_for_malloc() - (&_ext_ram_bss_end - &_ext_ram_bss_start))/1024); - return heap_caps_add_region((intptr_t)&_ext_ram_bss_end, (intptr_t)SOC_EXTRAM_DATA_LOW + spiram_size_usable_for_malloc()-1); -#else - ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", spiram_size_usable_for_malloc()/1024); - return heap_caps_add_region((intptr_t)SOC_EXTRAM_DATA_LOW, (intptr_t)SOC_EXTRAM_DATA_LOW + spiram_size_usable_for_malloc()-1); + if (mallocable_ram_start < (intptr_t)&_ext_ram_bss_end) { + mallocable_ram_start = (intptr_t)&_ext_ram_bss_end; + } #endif +#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY + if (mallocable_ram_start < (intptr_t)&_ext_ram_noinit_end) { + mallocable_ram_start = (intptr_t)&_ext_ram_noinit_end; + } +#endif + intptr_t mallocable_ram_end = (intptr_t)SOC_EXTRAM_DATA_LOW + spiram_size_usable_for_malloc() - 1; + ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (mallocable_ram_end - mallocable_ram_start)/1024); + return heap_caps_add_region(mallocable_ram_start, mallocable_ram_end); } diff --git a/components/esp_system/ld/esp32/esp32.extram.noinit.ld b/components/esp_system/ld/esp32/esp32.extram.noinit.ld new file mode 100644 index 0000000000..86c7b5341c --- /dev/null +++ b/components/esp_system/ld/esp32/esp32.extram.noinit.ld @@ -0,0 +1,14 @@ +/* This section is only included if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY + is set, to link some NOINIT sections in PSRAM */ + +SECTIONS +{ + /* external memory bss, from any global variable with EXT_RAM_NOINIT_ATTR attribute*/ + .ext_ram.noinit (NOLOAD) : + { + _ext_ram_noinit_start = ABSOLUTE(.); + *(.ext_ram.noinit*) + . = ALIGN(4); + _ext_ram_noinit_end = ABSOLUTE(.); + } > extern_ram_seg +} diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index faf2a38eac..3258bdbe6c 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -129,6 +129,10 @@ static const char *TAG = "cpu_start"; extern int _ext_ram_bss_start; extern int _ext_ram_bss_end; #endif +#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY +extern int _ext_ram_noinit_start; +extern int _ext_ram_noinit_end; +#endif #ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY extern int _iram_bss_start; extern int _iram_bss_end; @@ -419,7 +423,11 @@ void IRAM_ATTR call_start_cpu0(void) #if CONFIG_SPIRAM_MEMTEST if (g_spiram_ok) { - bool ext_ram_ok = esp_spiram_test(); +#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY + bool ext_ram_ok = esp_spiram_test(&_ext_ram_noinit_start, &_ext_ram_noinit_end); +#else + bool ext_ram_ok = esp_spiram_test(0, 0); +#endif if (!ext_ram_ok) { ESP_EARLY_LOGE(TAG, "External RAM failed memory test!"); abort(); From a542f1b67d381a0a1e72679942e4dc0b53cbce33 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Fri, 7 Feb 2020 00:00:45 +0000 Subject: [PATCH 2/6] esp32/test: add spiram noinit test case --- components/esp_common/test/test_attr.c | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/components/esp_common/test/test_attr.c b/components/esp_common/test/test_attr.c index 45aeeabe5c..e8cb0e7f2d 100644 --- a/components/esp_common/test/test_attr.c +++ b/components/esp_common/test/test_attr.c @@ -2,6 +2,8 @@ #include "esp_attr.h" #include "esp_log.h" #include "soc/soc.h" +#include "esp_system.h" +#include "esp32/spiram.h" static __NOINIT_ATTR uint32_t s_noinit; static RTC_NOINIT_ATTR uint32_t s_rtc_noinit; @@ -53,3 +55,42 @@ TEST_CASE("Attributes place variables into correct sections", "[ld]") TEST_ASSERT(data_in_segment(&s_rtc_force_fast, (int*) SOC_RTC_DRAM_LOW, (int*) SOC_RTC_DRAM_HIGH)); TEST_ASSERT(data_in_segment(&s_rtc_force_slow, (int*) SOC_RTC_DATA_LOW, (int*) SOC_RTC_DATA_HIGH)); } + + +#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY + +#define TEST_BUFFER_SIZE (16*1024/4) +static EXT_RAM_NOINIT_ATTR uint32_t s_noinit_buffer[TEST_BUFFER_SIZE]; + +static void write_spiram_and_reset(void) +{ + // Fill the noinit buffer + printf("Filling buffer\n"); + for (uint32_t i = 0; i < TEST_BUFFER_SIZE; i++) { + s_noinit_buffer[i] = i ^ 0x55555555U; + } + printf("Flushing cache\n"); + // Flush the cache out to SPIRAM before resetting. + esp_spiram_writeback_cache(); + + printf("Restarting\n"); + // Reset to test that noinit memory is left intact. + esp_restart(); +} + +static void check_spiram_contents(void) +{ + // Confirm that the memory contents are still what we expect + uint32_t error_count = 0; + for (uint32_t i = 0; i < TEST_BUFFER_SIZE; i++) { + if (s_noinit_buffer[i] != (i ^ 0x55555555U)) { + error_count++; + } + } + printf("Found %" PRIu32 " memory errors\n", error_count); + TEST_ASSERT(error_count == 0); +} + +TEST_CASE_MULTIPLE_STAGES("Spiram test noinit memory", "[spiram]", write_spiram_and_reset, check_spiram_contents); + +#endif // CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY From ad8e1a395cfd79e24eab5516ec9b2988fdf299a3 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 27 Jul 2021 16:12:45 +0800 Subject: [PATCH 3/6] memory: port SPIRAM noinit segment support to master --- components/esp32/CMakeLists.txt | 87 +------------------ components/esp32/component.mk | 36 -------- components/esp_common/include/esp_attr.h | 16 ++-- .../esp_hw_support/Kconfig.spiram.common | 10 ++- .../esp_hw_support/include/soc/esp32/spiram.h | 2 +- components/esp_hw_support/port/esp32/spiram.c | 25 ++++-- .../ld/esp32/esp32.extram.noinit.ld | 14 --- components/esp_system/ld/esp32/sections.ld.in | 12 +++ components/esp_system/port/cpu_start.c | 10 +-- 9 files changed, 48 insertions(+), 164 deletions(-) delete mode 100644 components/esp_system/ld/esp32/esp32.extram.noinit.ld diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index 376de09d67..a6eaa1b31d 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -3,89 +3,10 @@ if(NOT "${target}" STREQUAL "esp32") return() endif() -idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER) - -if(BOOTLOADER_BUILD) - # For bootloader, all we need from esp32 is headers - idf_component_register(INCLUDE_DIRS include REQUIRES xtensa) - target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld") -else() - # Regular app build - set(srcs - "cache_sram_mmu.c" - "dport_access.c" - "esp_himem.c" - "spiram.c" - "spiram_psram.c") - - set(include_dirs "include") - - set(requires driver efuse soc xtensa) #unfortunately rom/uart uses SOC registers directly - - # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function. - # esp_timer is added here because cpu_start.c uses esp_timer - set(priv_requires app_trace app_update bootloader_support esp_system log mbedtls nvs_flash pthread - spi_flash vfs espcoredump esp_common perfmon esp_timer esp_ipc esp_pm) - - idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS "${include_dirs}" - REQUIRES "${requires}" - PRIV_REQUIRES "${priv_requires}" - REQUIRED_IDF_TARGETS esp32) - - target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") - - if(CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY) - # This has to be linked before esp32.project.ld - target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.extram.noinit.ld") - endif() - - # Process the template file through the linker script generation mechanism, and use the output for linking the - # final binary - target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.project.ld.in" - PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32.project.ld") - - target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld") - target_link_libraries(${COMPONENT_LIB} PUBLIC gcc) - target_link_libraries(${COMPONENT_LIB} INTERFACE "-u call_user_start_cpu0") - - idf_build_get_property(config_dir CONFIG_DIR) - # Preprocess esp32.ld linker script to include configuration, becomes esp32_out.ld - set(LD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ld) - add_custom_command( - OUTPUT esp32_out.ld - COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o esp32_out.ld -I ${config_dir} ${LD_DIR}/esp32.ld - MAIN_DEPENDENCY ${LD_DIR}/esp32.ld - DEPENDS ${sdkconfig_header} - COMMENT "Generating linker script..." - VERBATIM) - - add_custom_target(esp32_linker_script DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld) - add_dependencies(${COMPONENT_LIB} esp32_linker_script) - - if(CONFIG_SPIRAM_CACHE_WORKAROUND) - # Note: Adding as a PUBLIC compile option here causes this option to propagate to all - # components that depend on esp32. - # - # To handle some corner cases, the same flag is set in project_include.cmake - target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue) - # also, make sure we link with this option so correct toolchain libs are pulled in - target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue) - # set strategy selected - # note that we don't need to set link options as the library linked is independent of this - if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST) - target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst) - target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst) - endif() - if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW) - target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw) - target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw) - endif() - if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS) - target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops) - target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops) - endif() - endif() +if(NOT BOOTLOADER_BUILD) + # [refactor-todo] propagate these requirements for compatibility + # remove in the future + set(legacy_reqs driver efuse soc) endif() idf_component_register(INCLUDE_DIRS include diff --git a/components/esp32/component.mk b/components/esp32/component.mk index 1b831fd21f..ebd7a7d59b 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -1,39 +1,3 @@ # # Component Makefile # - -COMPONENT_SRCDIRS := . - -ifdef CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY - # This linker script must come before esp32.project.ld - LINKER_SCRIPTS += esp32.extram.noinit.ld -endif - -#Linker scripts used to link the final application. -#Warning: These linker scripts are only used when the normal app is compiled; the bootloader -#specifies its own scripts. -LINKER_SCRIPTS += $(COMPONENT_BUILD_DIR)/esp32.project.ld esp32.peripherals.ld - -#ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the -#linker will ignore panic_highint_hdl.S as it has no other files depending on any -#symbols in it. -COMPONENT_ADD_LDFLAGS += -L $(COMPONENT_PATH)/ld \ - -T esp32_out.ld \ - -u ld_include_panic_highint_hdl \ - $(addprefix -T ,$(LINKER_SCRIPTS)) \ - -# final linking of project ELF depends on all binary libraries, and -# all linker scripts (except esp32_out.ld, as this is code generated here.) -COMPONENT_ADD_LINKER_DEPS := $(addprefix ld/, $(filter-out $(COMPONENT_BUILD_DIR)/esp32.project.ld, $(LINKER_SCRIPTS))) \ - $(COMPONENT_BUILD_DIR)/esp32.project.ld - -# Preprocess esp32.ld linker script into esp32_out.ld -# -# The library doesn't really depend on esp32_out.ld, but it -# saves us from having to add the target to a Makefile.projbuild -$(COMPONENT_LIBRARY): esp32_out.ld - -esp32_out.ld: $(COMPONENT_PATH)/ld/esp32.ld ../include/sdkconfig.h - $(CC) -I ../include -C -P -x c -E $< -o $@ - -COMPONENT_EXTRA_CLEAN := esp32_out.ld $(COMPONENT_BUILD_DIR)/esp32.project.ld diff --git a/components/esp_common/include/esp_attr.h b/components/esp_common/include/esp_attr.h index 6be0d4e678..88a230b77c 100644 --- a/components/esp_common/include/esp_attr.h +++ b/components/esp_common/include/esp_attr.h @@ -72,14 +72,6 @@ extern "C" { #define EXT_RAM_ATTR #endif -#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY -// Forces data into external memory noinit section to avoid initialization after restart. -#define EXT_RAM_NOINIT_ATTR _SECTION_ATTR_IMPL(".ext_ram.noinit", __COUNTER__) -#else -// Place in internal noinit section -#define EXT_RAM_NOINIT_ATTR __NOINIT_ATTR -#endif - // Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst" // Any variable marked with this attribute will keep its value // during a deep sleep / wake cycle. @@ -97,6 +89,14 @@ extern "C" { // Forces data into noinit section to avoid initialization after restart. #define __NOINIT_ATTR _SECTION_ATTR_IMPL(".noinit", __COUNTER__) +#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY +// Forces data into external memory noinit section to avoid initialization after restart. +#define EXT_RAM_NOINIT_ATTR _SECTION_ATTR_IMPL(".ext_ram.noinit", __COUNTER__) +#else +// Place in internal noinit section +#define EXT_RAM_NOINIT_ATTR __NOINIT_ATTR +#endif + // 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. diff --git a/components/esp_hw_support/Kconfig.spiram.common b/components/esp_hw_support/Kconfig.spiram.common index adc7872332..c52071dcab 100644 --- a/components/esp_hw_support/Kconfig.spiram.common +++ b/components/esp_hw_support/Kconfig.spiram.common @@ -102,10 +102,12 @@ config SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY Note that the variables placed in SPIRAM using EXT_RAM_ATTR will be zero initialized. -config SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY - bool "Enable placement of noinit segments in external memory" +config SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY + bool "Allow .noinit segment placed in external memory" default n - depends on SPIRAM + depends on SPIRAM && IDF_TARGET_ESP32 help If enabled, noinit variables can be placed in PSRAM using EXT_RAM_NOINIT_ATTR. - If disabled, EXT_RAM_NOINIT_ATTR will act like __NOINIT_ATTR. + + Note the values placed into this section will not be initialized at startup and should keep its value + after software restart. diff --git a/components/esp_hw_support/include/soc/esp32/spiram.h b/components/esp_hw_support/include/soc/esp32/spiram.h index b931cb79b0..e58712d1fa 100644 --- a/components/esp_hw_support/include/soc/esp32/spiram.h +++ b/components/esp_hw_support/include/soc/esp32/spiram.h @@ -59,7 +59,7 @@ void esp_spiram_init_cache(void); * * @return true on success, false on failed memory test */ -bool esp_spiram_test(const void* keepout_addr_low, const void* keepout_addr_high); +bool esp_spiram_test(void); /** diff --git a/components/esp_hw_support/port/esp32/spiram.c b/components/esp_hw_support/port/esp32/spiram.c index 8c6da9afe2..d0806f16ef 100644 --- a/components/esp_hw_support/port/esp32/spiram.c +++ b/components/esp_hw_support/port/esp32/spiram.c @@ -55,7 +55,7 @@ static const char* TAG = "spiram"; #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY extern uint8_t _ext_ram_bss_start, _ext_ram_bss_end; #endif -#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY +#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY extern uint8_t _ext_ram_noinit_start, _ext_ram_noinit_end; #endif @@ -83,25 +83,32 @@ static size_t spiram_size_usable_for_malloc(void) true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been initialized (in a two-core system) or after the heap allocator has taken ownership of the memory. */ -bool esp_spiram_test(const void* keepout_addr_low, const void* keepout_addr_high) +bool esp_spiram_test(void) { + +#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY + const void *keepout_addr_low = (const void*)&_ext_ram_noinit_start; + const void *keepout_addr_high = (const void*)&_ext_ram_noinit_end; +#else + const void *keepout_addr_low = 0; + const void *keepout_addr_high = 0; +#endif + volatile int *spiram=(volatile int*)SOC_EXTRAM_DATA_LOW; size_t p; size_t s=spiram_size_usable_for_malloc(); int errct=0; int initial_err=-1; for (p=0; p<(s/sizeof(int)); p+=8) { - if ((keepout_addr_low <= (const void*)&spiram[p]) && ((const void*)&spiram[p] < keepout_addr_high)) { - continue; - } else if ((keepout_addr_low < (const void*)&spiram[p+1]) && ((const void*)&spiram[p+1] <= keepout_addr_high)) { + const void *addr = (const void *)&spiram[p]; + if ((keepout_addr_low <= addr) && (addr < keepout_addr_high)) { continue; } spiram[p]=p^0xAAAAAAAA; } for (p=0; p<(s/sizeof(int)); p+=8) { - if ((keepout_addr_low <= (const void*)&spiram[p]) && ((const void*)&spiram[p] < keepout_addr_high)) { - continue; - } else if ((keepout_addr_low < (const void*)&spiram[p+1]) && ((const void*)&spiram[p+1] <= keepout_addr_high)) { + const void *addr = (const void *)&spiram[p]; + if ((keepout_addr_low <= addr) && (addr < keepout_addr_high)) { continue; } if (spiram[p]!=(p^0xAAAAAAAA)) { @@ -192,7 +199,7 @@ esp_err_t esp_spiram_add_to_heapalloc(void) mallocable_ram_start = (intptr_t)&_ext_ram_bss_end; } #endif -#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY +#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY if (mallocable_ram_start < (intptr_t)&_ext_ram_noinit_end) { mallocable_ram_start = (intptr_t)&_ext_ram_noinit_end; } diff --git a/components/esp_system/ld/esp32/esp32.extram.noinit.ld b/components/esp_system/ld/esp32/esp32.extram.noinit.ld deleted file mode 100644 index 86c7b5341c..0000000000 --- a/components/esp_system/ld/esp32/esp32.extram.noinit.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* This section is only included if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY - is set, to link some NOINIT sections in PSRAM */ - -SECTIONS -{ - /* external memory bss, from any global variable with EXT_RAM_NOINIT_ATTR attribute*/ - .ext_ram.noinit (NOLOAD) : - { - _ext_ram_noinit_start = ABSOLUTE(.); - *(.ext_ram.noinit*) - . = ALIGN(4); - _ext_ram_noinit_end = ABSOLUTE(.); - } > extern_ram_seg -} diff --git a/components/esp_system/ld/esp32/sections.ld.in b/components/esp_system/ld/esp32/sections.ld.in index b60a4a12e0..f3fb5026dd 100644 --- a/components/esp_system/ld/esp32/sections.ld.in +++ b/components/esp_system/ld/esp32/sections.ld.in @@ -197,6 +197,18 @@ SECTIONS . = ALIGN(4); } > dram0_0_seg + /** + * This section holds data that won't be initialised when startup. + * This section locates in External RAM region. + */ + .ext_ram.noinit (NOLOAD) : + { + _ext_ram_noinit_start = ABSOLUTE(.); + *(.ext_ram.noinit*) + . = ALIGN(4); + _ext_ram_noinit_end = ABSOLUTE(.); + } > extern_ram_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. diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 3258bdbe6c..faf2a38eac 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -129,10 +129,6 @@ static const char *TAG = "cpu_start"; extern int _ext_ram_bss_start; extern int _ext_ram_bss_end; #endif -#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY -extern int _ext_ram_noinit_start; -extern int _ext_ram_noinit_end; -#endif #ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY extern int _iram_bss_start; extern int _iram_bss_end; @@ -423,11 +419,7 @@ void IRAM_ATTR call_start_cpu0(void) #if CONFIG_SPIRAM_MEMTEST if (g_spiram_ok) { -#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY - bool ext_ram_ok = esp_spiram_test(&_ext_ram_noinit_start, &_ext_ram_noinit_end); -#else - bool ext_ram_ok = esp_spiram_test(0, 0); -#endif + bool ext_ram_ok = esp_spiram_test(); if (!ext_ram_ok) { ESP_EARLY_LOGE(TAG, "External RAM failed memory test!"); abort(); From 65aa737b1500c6fc91fc2964ea9ae66e8aeec966 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 27 Jul 2021 16:22:24 +0800 Subject: [PATCH 4/6] esp_common: add a case to test EXT_RAM_ATTR attribute --- components/esp_common/test/test_attr.c | 30 +++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/components/esp_common/test/test_attr.c b/components/esp_common/test/test_attr.c index e8cb0e7f2d..2b41ad1371 100644 --- a/components/esp_common/test/test_attr.c +++ b/components/esp_common/test/test_attr.c @@ -1,9 +1,12 @@ +#include "inttypes.h" #include "unity.h" #include "esp_attr.h" #include "esp_log.h" #include "soc/soc.h" #include "esp_system.h" -#include "esp32/spiram.h" +#if CONFIG_IDF_TARGET_ESP32 +#include "spiram.h" +#endif static __NOINIT_ATTR uint32_t s_noinit; static RTC_NOINIT_ATTR uint32_t s_rtc_noinit; @@ -11,6 +14,9 @@ static RTC_DATA_ATTR uint32_t s_rtc_data; static RTC_RODATA_ATTR uint32_t s_rtc_rodata; static RTC_FAST_ATTR uint32_t s_rtc_force_fast; static RTC_SLOW_ATTR uint32_t s_rtc_force_slow; +#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY +static EXT_RAM_NOINIT_ATTR uint32_t s_noinit_ext; +#endif extern int _rtc_noinit_start; extern int _rtc_noinit_end; @@ -22,6 +28,10 @@ extern int _rtc_force_fast_start; extern int _rtc_force_fast_end; extern int _rtc_force_slow_start; extern int _rtc_force_slow_end; +extern int _ext_ram_noinit_start; +extern int _ext_ram_noinit_end; +extern int _ext_ram_bss_start; +extern int _ext_ram_bss_end; static bool data_in_segment(void *ptr, int *seg_start, int *seg_end) @@ -54,6 +64,10 @@ TEST_CASE("Attributes place variables into correct sections", "[ld]") TEST_ASSERT(data_in_segment(&s_rtc_force_fast, (int*) SOC_RTC_DRAM_LOW, (int*) SOC_RTC_DRAM_HIGH)); TEST_ASSERT(data_in_segment(&s_rtc_force_slow, (int*) SOC_RTC_DATA_LOW, (int*) SOC_RTC_DATA_HIGH)); + +#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY + TEST_ASSERT(data_in_segment(&s_noinit_ext, &_ext_ram_noinit_start, &_ext_ram_noinit_end)); +#endif } @@ -94,3 +108,17 @@ static void check_spiram_contents(void) TEST_CASE_MULTIPLE_STAGES("Spiram test noinit memory", "[spiram]", write_spiram_and_reset, check_spiram_contents); #endif // CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY + + +#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY +#define TEST_BSS_NUM 256 +static EXT_RAM_ATTR uint32_t s_bss_buffer[TEST_BSS_NUM]; + +TEST_CASE("Test variables placed in external .bss segment", "[ld]") +{ + for (int i = 0; i < TEST_BSS_NUM; i++) { + TEST_ASSERT(data_in_segment(&s_bss_buffer[i], &_ext_ram_bss_start, &_ext_ram_bss_end)); + TEST_ASSERT_EQUAL(0, s_bss_buffer[i]); + } +} +#endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY From e0acefbb7890036c8e748a0faa356f6be791e933 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 27 Jul 2021 16:22:56 +0800 Subject: [PATCH 5/6] docs: add docs to .bss and .noinit segments on spiram --- docs/en/api-guides/external-ram.rst | 9 +++++++++ docs/en/api-guides/memory-types.rst | 8 ++++++-- docs/zh_CN/api-guides/external-ram.rst | 8 ++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/en/api-guides/external-ram.rst b/docs/en/api-guides/external-ram.rst index 9cfeb0abb4..baf27e64c2 100644 --- a/docs/en/api-guides/external-ram.rst +++ b/docs/en/api-guides/external-ram.rst @@ -38,6 +38,7 @@ ESP-IDF fully supports the use of external memory in applications. Once the exte * :ref:`external_ram_config_capability_allocator` * :ref:`external_ram_config_malloc` (default) :esp32: * :ref:`external_ram_config_bss` + :esp32: * :ref:`external_ram_config_noinit` .. _external_ram_config_memory_map: @@ -104,6 +105,14 @@ Because some buffers can only be allocated in internal memory, a second configur Remaining external RAM can also be added to the capability heap allocator using the method shown above. + .. _external_ram_config_noinit: + + Allow .noinit segment placed in external memory + ----------------------------------------------- + + Enable this option by checking :ref:`CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY`. If enabled, a region of the address space provided in external RAM will be used to store non-initialized data. The values placed in this segment will not be initialized or modified even during startup or restart. + + By applying the macro ``EXT_RAM_NOINIT_ATTR``, data could be moved from the internal NOINIT segment to external RAM. Remaining external RAM can still be added to the capability heap allocator using the method shown above, :ref:`external_ram_config_capability_allocator`. Restrictions ============ diff --git a/docs/en/api-guides/memory-types.rst b/docs/en/api-guides/memory-types.rst index 002ea365aa..dcea174e5d 100644 --- a/docs/en/api-guides/memory-types.rst +++ b/docs/en/api-guides/memory-types.rst @@ -16,6 +16,8 @@ Non-constant static data (.data) and zero-initialized data (.bss) is placed by t .. only:: esp32 + By applying the ``EXT_RAM_ATTR`` macro, zero-initialized data can also be placed into external RAM. To use this macro, the :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` needs to be enabled. See :ref:`external_ram_config_bss`. + The available size of the internal DRAM region is reduced by 64kB (by shifting start address to ``0x3FFC0000``) if Bluetooth stack is used. Length of this region is also reduced by 16 kB or 32kB if trace memory is used. Due to some memory fragmentation issues caused by ROM, it is also not possible to use all available DRAM for static allocations - however the remaining DRAM is still available as heap at runtime. .. only:: not esp32 @@ -31,6 +33,10 @@ Constant data may also be placed into DRAM, for example if it is used in an non- 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 should keep its value after software restart. +.. only:: esp32 + + By applying the ``EXT_RAM_NOINIT_ATTR`` macro, Non-initialized value could also be placed in external RAM. To do this, the :ref:`CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY` needs to be enabled. See :ref:`external_ram_config_noinit`. If the :ref:`CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY` is not enabled, ``EXT_RAM_NOINIT_ATTR`` will behave just as ``__NOINIT_ATTR``, it will make data to be placed into ``.noinit`` segment in internal RAM. + Example:: __NOINIT_ATTR uint32_t noinit_data; @@ -209,5 +215,3 @@ Placing DMA buffers in the stack is possible but discouraged. If doing so, pay a spi_device_transmit(spi, &temp); // other stuff } - - diff --git a/docs/zh_CN/api-guides/external-ram.rst b/docs/zh_CN/api-guides/external-ram.rst index 7261cce121..4672106f6f 100644 --- a/docs/zh_CN/api-guides/external-ram.rst +++ b/docs/zh_CN/api-guides/external-ram.rst @@ -121,7 +121,7 @@ ESP-IDF 启动过程中,片外 RAM 被映射到以 0x3F800000 起始的数据 .. only:: esp32 可以使用 :ref:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` 选项将任务堆栈放入片外存储器。这时,必须使用 :cpp:func:`xTaskCreateStatic` 指定从片外存储器分配的任务堆栈缓冲区,否则任务堆栈将会从片上存储器分配。 - + 初始化失败 ===================== @@ -129,12 +129,12 @@ ESP-IDF 启动过程中,片外 RAM 被映射到以 0x3F800000 起始的数据 .. only:: esp32 - 如果启用 :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY`,忽略失败的选项将无法使用,这是因为在链接时,链接器已经向片外存储器分配符号。 - + 如果启用 :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY`,忽略失败的选项将无法使用,这是因为在链接时,链接器已经向片外存储器分配符号。 + .. only:: esp32 .. include:: inc/external-ram-esp32-notes.rst .. _ESP32 ECO: https://www.espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_cn.pdf -.. _ESP32 ECO V3 User Guide: https://www.espressif.com/sites/default/files/documentation/ESP32_ECO_V3_User_Guide__CN.pdf \ No newline at end of file +.. _ESP32 ECO V3 User Guide: https://www.espressif.com/sites/default/files/documentation/ESP32_ECO_V3_User_Guide__CN.pdf From f2bfdec20f8eab5dd7ff34b61b8a297e6aa36d39 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 30 Jul 2021 17:03:39 +0800 Subject: [PATCH 6/6] ci: enable external bss and external noinit test cases --- tools/unit-test-app/configs/psram | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/unit-test-app/configs/psram b/tools/unit-test-app/configs/psram index 2184966329..02921a3590 100644 --- a/tools/unit-test-app/configs/psram +++ b/tools/unit-test-app/configs/psram @@ -8,3 +8,5 @@ CONFIG_ESP32_WIFI_IRAM_OPT=n CONFIG_ESP_TIMER_PROFILING=n # Disable encrypted flash reads/writes to save IRAM in this build configuration CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=n +CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY=y +CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y