Skip to content

Commit

Permalink
Merge branch 'feature/free_bt_memory_v5.1' into release/v5.1
Browse files Browse the repository at this point in the history
feat(bt): Frees BLE memory when no longer in use

See merge request espressif/esp-idf!26570
  • Loading branch information
jack0c committed Oct 20, 2023
2 parents 89e7a95 + ea06b04 commit 8c6114d
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 39 deletions.
13 changes: 7 additions & 6 deletions components/bt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)

Expand Down Expand Up @@ -695,13 +697,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)
Expand Down
11 changes: 11 additions & 0 deletions components/bt/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions components/bt/controller/esp32c2/Kconfig.in
Original file line number Diff line number Diff line change
Expand Up @@ -439,3 +439,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.
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
56 changes: 26 additions & 30 deletions components/bt/controller/esp32c2/bt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*********************************************************************
Expand Down Expand Up @@ -843,32 +843,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));
}
}
Expand Down
60 changes: 60 additions & 0 deletions components/bt/linker.lf.esp32c2
Original file line number Diff line number Diff line change
@@ -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)
32 changes: 31 additions & 1 deletion components/esp_system/ld/esp32c2/sections.ld.in
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,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;
Expand Down Expand Up @@ -289,6 +307,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
Expand Down
12 changes: 10 additions & 2 deletions components/esp_system/port/cpu_start.c
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -108,7 +108,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;
Expand Down Expand Up @@ -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.
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));
Expand Down
1 change: 1 addition & 0 deletions docs/en/api-guides/performance/ram-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions docs/zh_CN/api-guides/performance/ram-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 8c6114d

Please sign in to comment.