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.
This commit is contained in:
Shen Weilong 2023-08-17 12:13:12 +08:00
parent 55d3bc2d37
commit ea06b047c2
9 changed files with 150 additions and 39 deletions

View File

@ -2,6 +2,7 @@ if(CONFIG_BT_ENABLED)
set(srcs "") set(srcs "")
set(include_dirs "") set(include_dirs "")
set(ldfragments "linker.lf")
if(CONFIG_IDF_TARGET_ESP32) if(CONFIG_IDF_TARGET_ESP32)
list(APPEND srcs "controller/esp32/bt.c" list(APPEND srcs "controller/esp32/bt.c"
@ -18,6 +19,7 @@ if(CONFIG_BT_ENABLED)
list(APPEND include_dirs include/esp32c3/include) list(APPEND include_dirs include/esp32c3/include)
elseif(CONFIG_IDF_TARGET_ESP32C2) elseif(CONFIG_IDF_TARGET_ESP32C2)
set(ldfragments "linker.lf.esp32c2")
list(APPEND srcs "controller/esp32c2/bt.c") list(APPEND srcs "controller/esp32c2/bt.c")
list(APPEND include_dirs include/esp32c2/include) list(APPEND include_dirs include/esp32c2/include)
@ -695,13 +697,12 @@ if(CONFIG_BT_ENABLED)
endif() endif()
# requirements can't depend on config
idf_component_register(SRCS "${srcs}" idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}" INCLUDE_DIRS "${include_dirs}"
PRIV_INCLUDE_DIRS "${priv_include_dirs}" PRIV_INCLUDE_DIRS "${priv_include_dirs}"
REQUIRES esp_timer esp_wifi REQUIRES esp_timer esp_wifi
PRIV_REQUIRES nvs_flash soc esp_pm esp_phy esp_coex mbedtls driver vfs PRIV_REQUIRES nvs_flash soc esp_pm esp_phy esp_coex mbedtls driver vfs
LDFRAGMENTS "linker.lf") LDFRAGMENTS "${ldfragments}")
if(CONFIG_BT_ENABLED) if(CONFIG_BT_ENABLED)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough -Wno-unused-const-variable) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough -Wno-unused-const-variable)

View File

@ -68,6 +68,17 @@ menu "Bluetooth"
source "$IDF_PATH/components/bt/controller/$IDF_TARGET/Kconfig.in" source "$IDF_PATH/components/bt/controller/$IDF_TARGET/Kconfig.in"
endmenu 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 endmenu
menuconfig BLE_MESH menuconfig BLE_MESH

View File

@ -425,3 +425,6 @@ 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. 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 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. may cause adv packets lost more.
config BT_LE_RELEASE_IRAM_SUPPORTED
bool
default y

View File

@ -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_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 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 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 _bt_bss_end;
extern uint32_t _nimble_bss_start; extern uint32_t _bt_controller_data_start;
extern uint32_t _nimble_bss_end; #endif
extern uint32_t _nimble_data_start;
extern uint32_t _nimble_data_end;
extern uint32_t _bt_data_start;
extern uint32_t _bt_data_end;
/* Local Function Declaration /* Local Function Declaration
********************************************************************* *********************************************************************
@ -832,32 +832,28 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode)
{ {
intptr_t mem_start, mem_end; 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) { 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; mem_end = (intptr_t)&_bt_bss_end;
#endif // CONFIG_BT_RELEASE_IRAM
if (mem_start != mem_end) { if (mem_start != mem_end) {
ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x]", mem_start, mem_end); ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Release BLE [0x%08x] - [0x%08x], len %d", mem_start,
ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); mem_end, mem_end - mem_start);
}
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_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end));
} }
} }

View File

@ -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)

View File

@ -35,9 +35,27 @@ SECTIONS
. = ORIGIN(dram0_0_seg) + _iram_end - _iram_start; . = ORIGIN(dram0_0_seg) + _iram_end - _iram_start;
} > dram0_0_seg } > 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(.); _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.*) *(.gnu.linkonce.d.*)
*(.data1) *(.data1)
__global_pointer$ = . + 0x800; __global_pointer$ = . + 0x800;
@ -289,6 +307,18 @@ SECTIONS
mapping[iram0_bss] mapping[iram0_bss]
_iram_bss_end = ABSOLUTE(.); _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); . = ALIGN(16);
_iram_end = ABSOLUTE(.); _iram_end = ABSOLUTE(.);
} > iram0_0_seg } > iram0_0_seg

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -108,7 +108,10 @@ extern int _bss_start;
extern int _bss_end; extern int _bss_end;
extern int _rtc_bss_start; extern int _rtc_bss_start;
extern int _rtc_bss_end; 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_start;
extern int _instruction_reserved_end; extern int _instruction_reserved_end;
extern int _rodata_reserved_start; extern int _rodata_reserved_start;
@ -328,6 +331,11 @@ void IRAM_ATTR call_start_cpu0(void)
//Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. //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)); 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) #if defined(CONFIG_IDF_TARGET_ESP32) && defined(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY)
// Clear IRAM BSS // Clear IRAM BSS
memset(&_iram_bss_start, 0, (&_iram_bss_end - &_iram_bss_start) * sizeof(_iram_bss_start)); memset(&_iram_bss_start, 0, (&_iram_bss_end - &_iram_bss_start) * sizeof(_iram_bss_start));

View File

@ -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. - 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. - 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. - 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 .. only:: esp32

View File

@ -161,6 +161,7 @@ IRAM 优化
- 设置 :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL` 为禁用 HAL 组件的断言,可以节省 IRAM 空间,对于经常调用 ``HAL_ASSERT`` 且位于 IRAM 中的 HAL 代码尤为如此。 - 设置 :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL` 为禁用 HAL 组件的断言,可以节省 IRAM 空间,对于经常调用 ``HAL_ASSERT`` 且位于 IRAM 中的 HAL 代码尤为如此。
- 要禁用不需要的 flash 驱动程序,节省 IRAM 空间,请参阅 sdkconfig 菜单中的 ``Auto-detect Flash chips`` 选项。 - 要禁用不需要的 flash 驱动程序,节省 IRAM 空间,请参阅 sdkconfig 菜单中的 ``Auto-detect Flash chips`` 选项。
- 启用 :ref:`CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH`。只要未启用 :ref:`CONFIG_SPI_MASTER_ISR_IN_IRAM` 选项,且没有从 ISR 中错误地调用堆函数,就可以在所有配置中安全启用此选项。 - 启用 :ref:`CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH`。只要未启用 :ref:`CONFIG_SPI_MASTER_ISR_IN_IRAM` 选项,且没有从 ISR 中错误地调用堆函数,就可以在所有配置中安全启用此选项。
:esp32c2: - 启用 :ref:`CONFIG_BT_RELEASE_IRAM`。 蓝牙所使用的 databss 和 text 段已经被分配在连续的RAM区间。当调用 ``esp_bt_mem_release`` 时,这些段都会被添加到 Heap 中。 这将节省约 22 KB 的 RAM。但要再次使用蓝牙功能需要重启程序。
.. only:: esp32 .. only:: esp32