diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index e0ae5af7fd..007a6c4358 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -74,7 +74,13 @@ else() target_link_libraries(esp32 coexist core espnow mesh net80211 phy pp rtc smartconfig wpa2 wpa wps) endif() target_linker_script(esp32 "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") - target_linker_script(esp32 "${CMAKE_CURRENT_BINARY_DIR}/esp32.common_out.ld") + + if(CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY) + # This has to be linked before esp32.common.ld + target_linker_script(esp32 "ld/esp32.extram.bss.ld") + endif() + + target_linker_script(esp32 "ld/esp32.common.ld") target_linker_script(esp32 "ld/esp32.rom.ld" @@ -114,14 +120,7 @@ else() COMMENT "Generating linker script..." VERBATIM) - # Preprocess esp32.common.ld linker script to include configuration, becomes esp32.common_out.ld - add_custom_command( - OUTPUT esp32.common_out.ld - COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o esp32.common_out.ld -I ${CONFIG_DIR} ${LD_DIR}/esp32.common.ld - MAIN_DEPENDENCY ${LD_DIR}/esp32.common.ld ${SDKCONFIG_H} - COMMENT "Generating linker script..." - VERBATIM) - add_custom_target(esp32_linker_script DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld ${CMAKE_CURRENT_BINARY_DIR}/esp32.common_out.ld) + add_custom_target(esp32_linker_script DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld) add_dependencies(esp32 esp32_linker_script) if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index a5be995c35..fd5386f1af 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -41,7 +41,7 @@ config SPIRAM_BOOT_INIT config SPIRAM_IGNORE_NOTFOUND bool "Ignore PSRAM when not found" default "n" - depends on SPIRAM_BOOT_INIT + depends on SPIRAM_BOOT_INIT && !SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY help Normally, if psram initialization is enabled during compile time but not found at runtime, it is seen as an error making the ESP32 panic. If this is enabled, the ESP32 will keep on @@ -178,7 +178,8 @@ config SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY depends on SPIRAM_SUPPORT help If enabled the option,and add EXT_RAM_ATTR defined your variable,then your variable will be placed - in PSRAM instead of internal memory. + in PSRAM instead of internal memory, and placed most of variables of lwip,net802.11,pp,bluedroid library + to external memory defaultly. endmenu diff --git a/components/esp32/component.mk b/components/esp32/component.mk index 9900213b68..605bb56373 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -8,11 +8,15 @@ ifndef CONFIG_NO_BLOBS LIBS += core rtc net80211 pp wpa smartconfig coexist wps wpa2 espnow phy mesh endif +ifdef CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY + # This linker script must come before esp32.common.ld + LINKER_SCRIPTS += esp32.extram.bss.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 += esp32.rom.ld esp32.peripherals.ld +LINKER_SCRIPTS += esp32.common.ld esp32.rom.ld esp32.peripherals.ld #Force pure functions from libgcc.a to be linked from ROM LINKER_SCRIPTS += esp32.rom.libgcc.ld @@ -39,7 +43,6 @@ COMPONENT_ADD_LDFLAGS += $(COMPONENT_PATH)/libhal.a \ $(addprefix -l,$(LIBS)) \ -L $(COMPONENT_PATH)/ld \ -T esp32_out.ld \ - -T esp32.common_out.ld \ -u ld_include_panic_highint_hdl \ $(addprefix -T ,$(LINKER_SCRIPTS)) @@ -55,17 +58,12 @@ COMPONENT_ADD_LINKER_DEPS := $(ALL_LIB_FILES) $(addprefix ld/,$(LINKER_SCRIPTS)) # # 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.common_out.ld +$(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 $@ -# Preprocess esp32.common.ld linker script to include configuration, becomes esp32.common_out.ld -esp32.common_out.ld: $(COMPONENT_PATH)/ld/esp32.common.ld ../include/sdkconfig.h - $(CC) -I ../include -C -P -x c -E $< -o $@ - -COMPONENT_EXTRA_CLEAN := esp32_out.ld -COMPONENT_EXTRA_CLEAN += esp32.common_out.ld +COMPONENT_EXTRA_CLEAN := esp32_out.ld # disable stack protection in files which are involved in initialization of that feature stack_check.o: CFLAGS := $(filter-out -fstack-protector%, $(CFLAGS)) diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 6475c728f9..1fc9a2697c 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -158,7 +158,7 @@ void IRAM_ATTR call_start_cpu0() esp_spiram_init_cache(); if (esp_spiram_init() != ESP_OK) { #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - ESP_EARLY_LOGE(TAG, "Failed to init external RAM and place some block started symbol in it"); + ESP_EARLY_LOGE(TAG, "Failed to init external RAM, needed for external .bss segment"); abort(); #endif diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index 0a36143275..d698a76662 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -1,5 +1,3 @@ -#include "sdkconfig.h" - /* Default entry point: */ ENTRY(call_start_cpu0); @@ -52,20 +50,6 @@ SECTIONS _rtc_noinit_end = ABSOLUTE(.); } > rtc_slow_seg -#ifdef CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - /* external memory bss, from any global variable with EXT_RAM_ATTR attribute*/ - .ext_ram.bss (NOLOAD) : - { - _ext_ram_bss_start = ABSOLUTE(.); - *(.ext_ram.bss) - *libnet80211.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON) - *libpp.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON) - *liblwip.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON) - *libbt.a:(EXCLUDE_FILE (libbtdm_app.a) .dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON) - _ext_ram_bss_end = ABSOLUTE(.); - } > extern_ram_seg -#endif - /* Send .iram0 code to iram */ .iram0.vectors : { @@ -183,7 +167,7 @@ SECTIONS { . = ALIGN (8); _bss_start = ABSOLUTE(.); - *(.ext_ram.bss) + *(.ext_ram.bss*) _bt_bss_start = ABSOLUTE(.); *libbt.a:(.bss .bss.* COMMON) . = ALIGN (4); diff --git a/components/esp32/ld/esp32.extram.bss.ld b/components/esp32/ld/esp32.extram.bss.ld new file mode 100644 index 0000000000..6e0ab496e5 --- /dev/null +++ b/components/esp32/ld/esp32.extram.bss.ld @@ -0,0 +1,17 @@ +/* This section is only included if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY + is set, to link some sections to BSS in PSRAM */ + +SECTIONS +{ + /* external memory bss, from any global variable with EXT_RAM_ATTR attribute*/ + .ext_ram.bss (NOLOAD) : + { + _ext_ram_bss_start = ABSOLUTE(.); + *(.ext_ram.bss*) + *libnet80211.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON) + *libpp.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON) + *liblwip.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON) + *libbt.a:(EXCLUDE_FILE (libbtdm_app.a) .dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON) + _ext_ram_bss_end = ABSOLUTE(.); + } > extern_ram_seg +} diff --git a/docs/en/api-guides/external-ram.rst b/docs/en/api-guides/external-ram.rst index 15438072b6..5cd4b6ab22 100644 --- a/docs/en/api-guides/external-ram.rst +++ b/docs/en/api-guides/external-ram.rst @@ -46,6 +46,9 @@ ESP-IDF fully supports integrating external memory use into your applications. E ``heap_caps_malloc(size, MALLOC_CAP_SPIRAM)``. This memory can be used and subsequently freed using a normal ``free()`` call. * Initialize RAM, add it to the capability allocator and add memory to the pool of RAM that can be returned by ``malloc()``. This allows any application to use the external RAM without having to rewrite the code to use ``heap_caps_malloc``. + * Initialize RAM, use a region start from 0x3F800000 for storing zero initialized data(BSS segment) of lwip,net802.11,pp,bluedroid library + by enabling :ref: `CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` in menuconfig,this way can save some internal memory,because the BSS segment + originally stored in internal memory,and the rest of external RAM can be add the capability allocator and add memory to the pool of RAM as above way All these options can be selected from the menuconfig menu. @@ -67,7 +70,11 @@ The use of external RAM has a few restrictions: for stack and task TCBs and xTaskCreateStatic-type functions will check if the buffers passed are internal. However, for tasks not calling on code in ROM in any way, directly or indirectly, the menuconfig option :envvar:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` will eliminate the check in xTaskCreateStatic, allowing task stack in external RAM. Using this is not advised, however. - + * External RAM initialized failed can not be ignored if enabled :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY`; because of this, some BSS segment + can not be placed into external memory if PSRAM can't work normally and can not be moved to internal memory at runtime because the address of + them is defined by linkfile, the :ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND` can't handle this situation,if you want to enable :ref: + `CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` the :ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND` will be disabled, and if initialize SPIRAM failed,the system + will invoke abort. Because there are a fair few situations that have a specific need for internal memory, but it is also possible to use malloc() to exhaust internal memory, there is a pool reserved specifically for requests that cannot be resolved from external memory; allocating task