From a39869416c5ee675c2214e44ba09f4144b0eea69 Mon Sep 17 00:00:00 2001 From: zhaokeke Date: Sun, 8 Oct 2023 16:08:47 +0800 Subject: [PATCH] feat(bt): Frees BLE memory when no longer in use It will free libble.a & libbt all txt, data and bss segment memory. This memory is combined into one large memory and put into the heap pool. --- components/bt/CMakeLists.txt | 13 ++-- components/bt/Kconfig | 11 ++++ components/bt/controller/esp32c2/Kconfig.in | 4 ++ components/bt/controller/esp32c2/bt.c | 56 ++++++++--------- components/bt/linker.lf.esp32c2 | 60 +++++++++++++++++++ .../esp_system/ld/esp32c2/sections.ld.in | 32 +++++++++- components/esp_system/port/cpu_start.c | 10 +++- docs/en/api-guides/performance/ram-usage.rst | 1 + .../api-guides/performance/ram-usage.rst | 1 + 9 files changed, 150 insertions(+), 38 deletions(-) create mode 100644 components/bt/linker.lf.esp32c2 diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 9f39dcf57b..f675d7989d 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -2,6 +2,7 @@ if(CONFIG_BT_ENABLED) set(srcs "") set(include_dirs "") + set(ldfragments "linker.lf") if(CONFIG_IDF_TARGET_ESP32) list(APPEND srcs "controller/esp32/bt.c" @@ -18,6 +19,7 @@ if(CONFIG_BT_ENABLED) list(APPEND include_dirs include/esp32c3/include) elseif(CONFIG_IDF_TARGET_ESP32C2) + set(ldfragments "linker.lf.esp32c2") list(APPEND srcs "controller/esp32c2/bt.c") list(APPEND include_dirs include/esp32c2/include) @@ -726,13 +728,12 @@ if(CONFIG_BT_ENABLED) endif() -# requirements can't depend on config idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS "${include_dirs}" - PRIV_INCLUDE_DIRS "${priv_include_dirs}" - REQUIRES esp_timer esp_wifi - PRIV_REQUIRES nvs_flash soc esp_pm esp_phy esp_coex mbedtls driver vfs - LDFRAGMENTS "linker.lf") + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES esp_timer esp_wifi + PRIV_REQUIRES nvs_flash soc esp_pm esp_phy esp_coex mbedtls driver vfs + LDFRAGMENTS "${ldfragments}") if(CONFIG_BT_ENABLED) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough -Wno-unused-const-variable) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 8f98c38eaf..152ce7b386 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -68,6 +68,17 @@ menu "Bluetooth" source "$IDF_PATH/components/bt/controller/$IDF_TARGET/Kconfig.in" endmenu + config BT_RELEASE_IRAM + depends on BT_ENABLED && BT_LE_RELEASE_IRAM_SUPPORTED + bool "Release Bluetooth text (READ DOCS FIRST)" + default n + help + This option release Bluetooth text section and merge Bluetooth data, bss & text into + a large free heap region when esp_bt_mem_release is called, total saving ~21kB or more of IRAM. + ESP32-C2 only 3 configurable PMP entries available, rest of them are hard-coded. + We cannot split the memory into 3 different regions (IRAM, BLE-IRAM, DRAM). + So this option will disable the PMP (ESP_SYSTEM_PMP_IDRAM_SPLIT) + endmenu menuconfig BLE_MESH diff --git a/components/bt/controller/esp32c2/Kconfig.in b/components/bt/controller/esp32c2/Kconfig.in index ca1902ca94..ac95c42e34 100644 --- a/components/bt/controller/esp32c2/Kconfig.in +++ b/components/bt/controller/esp32c2/Kconfig.in @@ -425,3 +425,7 @@ config BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD of ADV packets lost in the controller reaches this threshold. It is better to set a larger value. If you set `BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it may cause adv packets lost more. + +config BT_LE_RELEASE_IRAM_SUPPORTED + bool + default y diff --git a/components/bt/controller/esp32c2/bt.c b/components/bt/controller/esp32c2/bt.c index 25c585bd34..0698f8ebd7 100644 --- a/components/bt/controller/esp32c2/bt.c +++ b/components/bt/controller/esp32c2/bt.c @@ -156,14 +156,14 @@ extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t hand extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); extern void bt_track_pll_cap(void); -extern uint32_t _bt_bss_start; + +#if CONFIG_BT_RELEASE_IRAM +extern uint32_t _iram_bt_text_start; +extern uint32_t _bss_bt_end; +#else extern uint32_t _bt_bss_end; -extern uint32_t _nimble_bss_start; -extern uint32_t _nimble_bss_end; -extern uint32_t _nimble_data_start; -extern uint32_t _nimble_data_end; -extern uint32_t _bt_data_start; -extern uint32_t _bt_data_end; +extern uint32_t _bt_controller_data_start; +#endif /* Local Function Declaration ********************************************************************* @@ -828,32 +828,28 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) { intptr_t mem_start, mem_end; +#if CONFIG_BT_RELEASE_IRAM && CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT + /* Release Bluetooth text section and merge Bluetooth data, bss & text into a large free heap + * region when esp_bt_mem_release is called, total saving ~21kB or more of IRAM. ESP32-C2 has + * only 3 configurable PMP entries available, rest of them are hard-coded. We cannot split the + * memory into 3 different regions (IRAM, BLE-IRAM, DRAM). So `ESP_SYSTEM_PMP_IDRAM_SPLIT` needs + * to be disabled. + */ + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "`ESP_SYSTEM_PMP_IDRAM_SPLIT` should be disabled!"); + assert(0); +#endif // CONFIG_BT_RELEASE_IRAM && CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT + if (mode & ESP_BT_MODE_BLE) { - mem_start = (intptr_t)&_bt_bss_start; +#if CONFIG_BT_RELEASE_IRAM + mem_start = (intptr_t)MAP_IRAM_TO_DRAM((intptr_t)&_iram_bt_text_start); + mem_end = (intptr_t)&_bss_bt_end; +#else + mem_start = (intptr_t)&_bt_controller_data_start; mem_end = (intptr_t)&_bt_bss_end; +#endif // CONFIG_BT_RELEASE_IRAM if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x]", mem_start, mem_end); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_bt_data_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x]", mem_start, mem_end); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - - mem_start = (intptr_t)&_nimble_bss_start; - mem_end = (intptr_t)&_nimble_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release NimBLE BSS [0x%08x] - [0x%08x]", mem_start, mem_end); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - - mem_start = (intptr_t)&_nimble_data_start; - mem_end = (intptr_t)&_nimble_data_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release NimBLE Data [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Release BLE [0x%08x] - [0x%08x], len %d", mem_start, + mem_end, mem_end - mem_start); ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); } } diff --git a/components/bt/linker.lf.esp32c2 b/components/bt/linker.lf.esp32c2 new file mode 100644 index 0000000000..40d8a56303 --- /dev/null +++ b/components/bt/linker.lf.esp32c2 @@ -0,0 +1,60 @@ +[sections:bt_text] +entries: + .iram1+ + +[sections:bt_bss] +entries: + .bss+ + .sbss+ + +[sections:bt_data] +entries: + .data+ + .sdata+ + .dram1+ + +[sections:bt_common] +entries: + COMMON + +[scheme:bt_start_end] +entries: + bt_text -> iram0_bt_text + bt_bss -> dram0_bt_bss + bt_common -> dram0_bt_bss + bt_data -> dram0_bt_data + +# For the following fragments, order matters for +# 'ALIGN(4) ALIGN(4, post) SURROUND(sym)', which generates: +# +# . = ALIGN(4) +# _sym_start +# ... +# . = ALIGN(4) +# _sym_end + +[mapping:bt] +archive: libbt.a +entries: + * (bt_start_end); + bt_bss -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_bss), + bt_common -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_common), + bt_data -> dram0_bt_data ALIGN(4) ALIGN(4, post) SURROUND(bt_data) + if ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY = y: + * (extram_bss) + +[mapping:btdm] +archive: libbtdm_app.a +entries: + * (bt_start_end); + bt_bss -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(btdm_bss), + bt_common -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(btdm_common), + bt_data -> dram0_bt_data ALIGN(4) ALIGN(4, post) SURROUND(btdm_data) + +[mapping:bt_controller] +archive: libble_app.a +entries: + * (bt_start_end); + bt_bss -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_bss), + bt_common -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_common), + bt_data -> dram0_bt_data ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_data) diff --git a/components/esp_system/ld/esp32c2/sections.ld.in b/components/esp_system/ld/esp32c2/sections.ld.in index bef77f82eb..f42334f87b 100644 --- a/components/esp_system/ld/esp32c2/sections.ld.in +++ b/components/esp_system/ld/esp32c2/sections.ld.in @@ -36,9 +36,27 @@ SECTIONS . = ORIGIN(dram0_0_seg) + _iram_end - _iram_start; } > dram0_0_seg - .dram0.data : + /** + * This section MUST be placed at the beginning of the DRAM0, + * which will be released along with iram0_bt.text when Bluetooth is no longer in use + */ + .dram0.bt.data : { _data_start = ABSOLUTE(.); + mapping[dram0_bt_data] + . = ALIGN(8); + } > dram0_0_seg + + .dram0.bt.bss (NOLOAD) : + { + . = ALIGN (8); + _bss_bt_start = ABSOLUTE(.); + mapping[dram0_bt_bss] + _bss_bt_end = ABSOLUTE(.); + } > dram0_0_seg + + .dram0.data : + { *(.gnu.linkonce.d.*) *(.data1) __global_pointer$ = . + 0x800; @@ -290,6 +308,18 @@ SECTIONS mapping[iram0_bss] _iram_bss_end = ABSOLUTE(.); + } > iram0_0_seg + + /** + * This section needs to be placed at the end of the IRAM0, + * which will be released along with dram0_bt_data and dram0_bt_bss when Bluetooth is no longer in use + */ + .iram0.bt.text : + { + . = ALIGN(16); + _iram_bt_text_start = ABSOLUTE(.); + mapping[iram0_bt_text] + . = ALIGN(16); _iram_end = ABSOLUTE(.); } > iram0_0_seg diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index b5c0fb417e..5f8817d142 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -113,7 +113,10 @@ extern int _bss_start; extern int _bss_end; extern int _rtc_bss_start; extern int _rtc_bss_end; - +#if CONFIG_BT_LE_RELEASE_IRAM_SUPPORTED +extern int _bss_bt_start; +extern int _bss_bt_end; +#endif // CONFIG_BT_LE_RELEASE_IRAM_SUPPORTED extern int _instruction_reserved_start; extern int _instruction_reserved_end; extern int _rodata_reserved_start; @@ -415,6 +418,11 @@ void IRAM_ATTR call_start_cpu0(void) //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); +#if CONFIG_BT_LE_RELEASE_IRAM_SUPPORTED + // Clear Bluetooth bss + memset(&_bss_bt_start, 0, (&_bss_bt_end - &_bss_bt_start) * sizeof(_bss_bt_start)); +#endif // CONFIG_BT_LE_RELEASE_IRAM_SUPPORTED + #if defined(CONFIG_IDF_TARGET_ESP32) && defined(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY) // Clear IRAM BSS memset(&_iram_bss_start, 0, (&_iram_bss_end - &_iram_bss_start) * sizeof(_iram_bss_start)); diff --git a/docs/en/api-guides/performance/ram-usage.rst b/docs/en/api-guides/performance/ram-usage.rst index 33b89d4275..3959a8d65f 100644 --- a/docs/en/api-guides/performance/ram-usage.rst +++ b/docs/en/api-guides/performance/ram-usage.rst @@ -161,6 +161,7 @@ The following options will reduce IRAM usage of some ESP-IDF features: - Setting :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL` to disable assertion for HAL component saves some IRAM, especially for HAL code who calls ``HAL_ASSERT`` a lot and resides in IRAM. - Refer to the sdkconfig menu ``Auto-detect Flash chips``, and you can disable flash drivers which you do not need to save some IRAM. - Enable :ref:`CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH`. Provided that :ref:`CONFIG_SPI_MASTER_ISR_IN_IRAM` is not enabled and the heap functions are not incorrectly used from ISRs, this option is safe to enable in all configurations. + :esp32c2: - Enable :ref:`CONFIG_BT_RELEASE_IRAM`. Release BT text section and merge BT data, bss & text into a large free heap region when ``esp_bt_mem_release`` is called. This makes Bluetooth unavailable until the next restart, but saving ~22 KB or more of IRAM. .. only:: esp32 diff --git a/docs/zh_CN/api-guides/performance/ram-usage.rst b/docs/zh_CN/api-guides/performance/ram-usage.rst index 23c9c14b19..a12d2db7b5 100644 --- a/docs/zh_CN/api-guides/performance/ram-usage.rst +++ b/docs/zh_CN/api-guides/performance/ram-usage.rst @@ -161,6 +161,7 @@ IRAM 优化 - 设置 :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL` 为禁用 HAL 组件的断言,可以节省 IRAM 空间,对于经常调用 ``HAL_ASSERT`` 且位于 IRAM 中的 HAL 代码尤为如此。 - 要禁用不需要的 flash 驱动程序,节省 IRAM 空间,请参阅 sdkconfig 菜单中的 ``Auto-detect Flash chips`` 选项。 - 启用 :ref:`CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH`。只要未启用 :ref:`CONFIG_SPI_MASTER_ISR_IN_IRAM` 选项,且没有从 ISR 中错误地调用堆函数,就可以在所有配置中安全启用此选项。 + :esp32c2: - 启用 :ref:`CONFIG_BT_RELEASE_IRAM`。 蓝牙所使用的 data,bss 和 text 段已经被分配在连续的RAM区间。当调用 ``esp_bt_mem_release`` 时,这些段都会被添加到 Heap 中。 这将节省约 22 KB 的 RAM。但要再次使用蓝牙功能,需要重启程序。 .. only:: esp32