diff --git a/components/bt/Kconfig b/components/bt/Kconfig index fd805bd7f..174b2deef 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -31,15 +31,6 @@ config CLASSIC_BT_ENABLED help For now this option needs "SMP_ENABLE" to be set to yes -config BT_DRAM_RELEASE - bool "Release DRAM from Classic BT controller" - depends on BT_ENABLED && (!BLUEDROID_ENABLED || (BLUEDROID_ENABLED && !CLASSIC_BT_ENABLED)) - default n - help - This option should only be used when BLE only. - Enabling this option will release about 30K DRAM from Classic BT. - The released DRAM will be used as system heap memory. - config GATTS_ENABLE bool "Include GATT server module(GATTS)" depends on BLUEDROID_ENABLED diff --git a/components/bt/bt.c b/components/bt/bt.c index 61e8792da..12e1d4407 100644 --- a/components/bt/bt.c +++ b/components/bt/bt.c @@ -17,6 +17,7 @@ #include #include +#include "esp_heap_caps_init.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" @@ -30,16 +31,19 @@ #include "esp_attr.h" #include "esp_phy_init.h" #include "bt.h" +#include "esp_err.h" +#include "esp_log.h" #if CONFIG_BT_ENABLED +#define BTDM_LOG_TAG "BTDM_INIT" + #define BTDM_INIT_PERIOD (5000) /* ms */ /* Bluetooth system and controller config */ -#define BTDM_CFG_BT_EM_RELEASE (1<<0) -#define BTDM_CFG_BT_DATA_RELEASE (1<<1) -#define BTDM_CFG_HCI_UART (1<<2) -#define BTDM_CFG_CONTROLLER_RUN_APP_CPU (1<<3) +#define BTDM_CFG_BT_DATA_RELEASE (1<<0) +#define BTDM_CFG_HCI_UART (1<<1) +#define BTDM_CFG_CONTROLLER_RUN_APP_CPU (1<<2) /* Other reserved for future */ /* not for user call, so don't put to include file */ @@ -48,6 +52,7 @@ extern int btdm_controller_init(uint32_t config_mask, esp_bt_controller_config_t extern int btdm_controller_deinit(void); extern int btdm_controller_enable(esp_bt_mode_t mode); extern int btdm_controller_disable(esp_bt_mode_t mode); +extern uint8_t btdm_controller_get_mode(void); extern void btdm_rf_bb_init(void); /* VHCI function interface */ @@ -63,6 +68,13 @@ extern void API_vhci_host_register_callback(const vhci_host_callback_t *callback extern int ble_txpwr_set(int power_type, int power_level); extern int ble_txpwr_get(int power_type); +extern char _bss_start_btdm; +extern char _bss_end_btdm; +extern char _data_start_btdm; +extern char _data_end_btdm; +extern uint32_t _data_start_btdm_rom; +extern uint32_t _data_end_btdm_rom; + #define BT_DEBUG(...) #define BT_API_CALL_CHECK(info, api_call, ret) \ do{\ @@ -75,6 +87,27 @@ do{\ #define OSI_FUNCS_TIME_BLOCKING 0xffffffff +typedef struct { + esp_bt_mode_t mode; + intptr_t start; + intptr_t end; +} btdm_dram_available_region_t; + +/* the mode column will be modifid by release function to indicate the available region */ +static btdm_dram_available_region_t btdm_dram_available_region[] = { + //following is .data + {ESP_BT_MODE_BTDM, 0x3ffae6e0, 0x3ffaff10}, + //following is memory which HW will use + {ESP_BT_MODE_BTDM, 0x3ffb0000, 0x3ffb09a8}, + {ESP_BT_MODE_BLE, 0x3ffb09a8, 0x3ffb1ddc}, + {ESP_BT_MODE_BTDM, 0x3ffb1ddc, 0x3ffb2730}, + {ESP_BT_MODE_CLASSIC_BT, 0x3ffb2730, 0x3ffb8000}, + //following is .bss + {ESP_BT_MODE_BTDM, 0x3ffb8000, 0x3ffbbb28}, + {ESP_BT_MODE_CLASSIC_BT, 0x3ffbbb28, 0x3ffbdb28}, + {ESP_BT_MODE_BTDM, 0x3ffbdb28, 0x3ffc0000}, +}; + struct osi_funcs_t { xt_handler (*_set_isr)(int n, xt_handler f, void *arg); void (*_ints_on)(unsigned int mask); @@ -303,9 +336,10 @@ static uint32_t btdm_config_mask_load(void) { uint32_t mask = 0x0; -#ifdef CONFIG_BT_DRAM_RELEASE - mask |= (BTDM_CFG_BT_EM_RELEASE | BTDM_CFG_BT_DATA_RELEASE); -#endif + if (btdm_dram_available_region[0].mode == ESP_BT_MODE_BLE) { + mask |= BTDM_CFG_BT_DATA_RELEASE; + } + #ifdef CONFIG_BT_HCI_UART mask |= BTDM_CFG_HCI_UART; #endif @@ -315,6 +349,76 @@ static uint32_t btdm_config_mask_load(void) return mask; } +static void btdm_controller_mem_init(void) +{ + /* initialise .bss, .data and .etc section */ + memcpy(&_data_start_btdm, (void *)_data_start_btdm_rom, &_data_end_btdm - &_data_start_btdm); + ESP_LOGD(BTDM_LOG_TAG, ".data initialise [0x%08x] <== [0x%08x]\n", (uint32_t)&_data_start_btdm, _data_start_btdm_rom); + + for (int i = 1; i < sizeof(btdm_dram_available_region)/sizeof(btdm_dram_available_region_t); i++) { + if (btdm_dram_available_region[i].mode != ESP_BT_MODE_IDLE) { + memset((void *)btdm_dram_available_region[i].start, 0x0, btdm_dram_available_region[i].end - btdm_dram_available_region[i].start); + ESP_LOGD(BTDM_LOG_TAG, ".bss initialise [0x%08x] - [0x%08x]\n", btdm_dram_available_region[i].start, btdm_dram_available_region[i].end); + } + } +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + bool update = true; + intptr_t mem_start, mem_end; + + //get the mode which can be released, skip the mode which is running + mode &= ~btdm_controller_get_mode(); + if (mode == 0x0) { + return ESP_ERR_INVALID_ARG; + } + + //already relesed + if (!(mode & btdm_dram_available_region[0].mode)) { + return ESP_ERR_INVALID_STATE; + } + + for (int i = 0; i < sizeof(btdm_dram_available_region)/sizeof(btdm_dram_available_region_t); i++) { + //skip the share mode, idle mode and other mode + if (btdm_dram_available_region[i].mode == ESP_BT_MODE_IDLE + || (mode & btdm_dram_available_region[i].mode) != btdm_dram_available_region[i].mode) { + //clear the bit of the mode which will be released + btdm_dram_available_region[i].mode &= ~mode; + continue; + } else { + //clear the bit of the mode which will be released + btdm_dram_available_region[i].mode &= ~mode; + } + + if (update) { + mem_start = btdm_dram_available_region[i].start; + mem_end = btdm_dram_available_region[i].end; + update = false; + } + + if (i < sizeof(btdm_dram_available_region)/sizeof(btdm_dram_available_region_t) - 1) { + mem_end = btdm_dram_available_region[i].end; + if (btdm_dram_available_region[i+1].mode != ESP_BT_MODE_IDLE + && (mode & btdm_dram_available_region[i+1].mode) == btdm_dram_available_region[i+1].mode + && mem_end == btdm_dram_available_region[i+1].start) { + continue; + } else { + ESP_LOGD(BTDM_LOG_TAG, "Release DRAM [0x%08x] - [0x%08x]\n", mem_start, mem_end); + ESP_ERROR_CHECK( heap_caps_add_region(mem_start, mem_end)); + update = true; + } + } else { + mem_end = btdm_dram_available_region[i].end; + ESP_LOGD(BTDM_LOG_TAG, "Release DRAM [0x%08x] - [0x%08x]\n", mem_start, mem_end); + ESP_ERROR_CHECK( heap_caps_add_region(mem_start, mem_end)); + update = true; + } + } + + return ESP_OK; +} + esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) { BaseType_t ret; @@ -324,6 +428,11 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) return ESP_ERR_INVALID_STATE; } + //if all the bt available memory was already released, cannot initialize bluetooth controller + if (btdm_dram_available_region[0].mode == ESP_BT_MODE_IDLE) { + return ESP_ERR_INVALID_STATE; + } + if (cfg == NULL) { return ESP_ERR_INVALID_ARG; } @@ -335,6 +444,8 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) btdm_osi_funcs_register(&osi_funcs); + btdm_controller_mem_init(); + btdm_cfg_mask = btdm_config_mask_load(); ret = btdm_controller_init(btdm_cfg_mask, cfg); @@ -356,7 +467,7 @@ esp_err_t esp_bt_controller_deinit(void) return ESP_ERR_NO_MEM; } - btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_SHUTDOWN; return ESP_OK; } @@ -368,7 +479,8 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) return ESP_ERR_INVALID_STATE; } - if (mode != ESP_BT_MODE_BTDM) { + //check the mode is available mode + if (mode & ~btdm_dram_available_region[0].mode) { return ESP_ERR_INVALID_ARG; } @@ -389,7 +501,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) return ESP_OK; } -esp_err_t esp_bt_controller_disable(esp_bt_mode_t mode) +esp_err_t esp_bt_controller_disable(void) { int ret; @@ -397,11 +509,7 @@ esp_err_t esp_bt_controller_disable(esp_bt_mode_t mode) return ESP_ERR_INVALID_STATE; } - if (mode != ESP_BT_MODE_BTDM) { - return ESP_ERR_INVALID_ARG; - } - - ret = btdm_controller_disable(mode); + ret = btdm_controller_disable(btdm_controller_get_mode()); if (ret < 0) { return ESP_ERR_INVALID_STATE; } @@ -435,5 +543,4 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) return (esp_power_level_t)ble_txpwr_get(power_type); } - -#endif +#endif /* CONFIG_BT_ENABLED */ diff --git a/components/bt/include/bt.h b/components/bt/include/bt.h index a11cd3eec..997696044 100644 --- a/components/bt/include/bt.h +++ b/components/bt/include/bt.h @@ -78,6 +78,7 @@ typedef enum { ESP_BT_CONTROLLER_STATUS_IDLE = 0, ESP_BT_CONTROLLER_STATUS_INITED, ESP_BT_CONTROLLER_STATUS_ENABLED, + ESP_BT_CONTROLLER_STATUS_SHUTDOWN, ESP_BT_CONTROLLER_STATUS_NUM, } esp_bt_controller_status_t; @@ -158,20 +159,20 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg); esp_err_t esp_bt_controller_deinit(void); /** - * @brief Enable BT controller + * @brief Enable BT controller. + * Due to a known issue, you cannot call esp_bt_controller_enable() a second time + * to change the controller mode dynamically. To change controller mode, call + * esp_bt_controller_disable() and then call esp_bt_controller_enable() with the new mode. * @param mode : the mode(BLE/BT/BTDM) to enable. - * Now only support BTDM. * @return ESP_OK - success, other - failed */ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode); /** * @brief Disable BT controller - * @param mode : the mode(BLE/BT/BTDM) to disable. - * Now only support BTDM. * @return ESP_OK - success, other - failed */ -esp_err_t esp_bt_controller_disable(esp_bt_mode_t mode); +esp_err_t esp_bt_controller_disable(void); /** * @brief Get BT controller is initialised/de-initialised/enabled/disabled @@ -207,6 +208,36 @@ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len); */ void esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback); +/** @brief esp_bt_controller_mem_release + * release the memory by mode, if never use the bluetooth mode + * it can release the .bbs, .data and other section to heap. + * The total size is about 70k bytes. + * + * If esp_bt_controller_enable(mode) has already been called, calling + * esp_bt_controller_mem_release(ESP_BT_MODE_BTDM) will automatically + * release all memory which is not needed for the currently enabled + * Bluetooth controller mode. + * + * For example, calling esp_bt_controller_enable(ESP_BT_MODE_BLE) then + * esp_bt_controller_mem_release(ESP_BT_MODE_BTDM) will enable BLE modes + * and release memory only used by BT Classic. Also, call esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT) + * is the same. + * + * Note that once BT controller memory is released, the process cannot be reversed. + * If your firmware will later upgrade the Bluetooth controller mode (BLE -> BT Classic or disabled -> enabled) + * then do not call this function. + * + * If user never use bluetooth controller, could call esp_bt_controller_mem_release(ESP_BT_MODE_BTDM) + * before esp_bt_controller_init or after esp_bt_controller_deinit. + * + * For example, user only use bluetooth to config SSID and PASSWORD of WIFI, after config, will never use bluetooth. + * Then, could call esp_bt_controller_mem_release(ESP_BT_MODE_BTDM) after esp_bt_controller_deinit. + * + * @param mode : the mode want to release memory + * @return ESP_OK - success, other - failed + */ +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); + #ifdef __cplusplus } #endif diff --git a/components/bt/lib b/components/bt/lib index d41e35129..f75b0b9ed 160000 --- a/components/bt/lib +++ b/components/bt/lib @@ -1 +1 @@ -Subproject commit d41e3512971612a4903e1ea1189968408811a1ae +Subproject commit f75b0b9ed881640b79ea2034719ba569d51162f8 diff --git a/components/heap/heap_caps_init.c b/components/heap/heap_caps_init.c index 9f88c87d5..0c8405ec1 100644 --- a/components/heap/heap_caps_init.c +++ b/components/heap/heap_caps_init.c @@ -213,7 +213,8 @@ esp_err_t heap_caps_add_region(intptr_t start, intptr_t end) for (int i = 0; i < soc_memory_region_count; i++) { const soc_memory_region_t *region = &soc_memory_regions[i]; - if (region->start <= start && (region->start + region->size) > end) { + // Test requested start only as 'end' may be in a different region entry, assume 'end' has same caps + if (region->start <= start && (region->start + region->size) > start) { const uint32_t *caps = soc_memory_types[region->type].caps; return heap_caps_add_region_with_caps(caps, start, end); } diff --git a/components/soc/esp32/soc_memory_layout.c b/components/soc/esp32/soc_memory_layout.c index dce4ff8b4..02bced263 100644 --- a/components/soc/esp32/soc_memory_layout.c +++ b/components/soc/esp32/soc_memory_layout.c @@ -150,16 +150,10 @@ const soc_reserved_region_t soc_reserved_regions[] = { { 0x3ffe4000, 0x3ffe4350 }, //Reserve ROM APP data region #if CONFIG_BT_ENABLED -#if CONFIG_BT_DRAM_RELEASE - { 0x3ffb0000, 0x3ffb3000 }, //Reserve BT data region - { 0x3ffb8000, 0x3ffbbb28 }, //Reserve BT data region - { 0x3ffbdb28, 0x3ffc0000 }, //Reserve BT data region -#else { 0x3ffb0000, 0x3ffc0000 }, //Reserve BT hardware shared memory & BT data region -#endif { 0x3ffae000, 0x3ffaff10 }, //Reserve ROM data region, inc region needed for BT ROM routines #else - { 0x3ffae000, 0x3ffae2a0 }, //Reserve ROM data region + { 0x3ffae000, 0x3ffae6e0 }, //Reserve ROM data region #endif #if CONFIG_MEMMAP_TRACEMEM diff --git a/examples/bluetooth/a2dp_sink/main/main.c b/examples/bluetooth/a2dp_sink/main/main.c index 3e97b4f3e..e8d579c8b 100644 --- a/examples/bluetooth/a2dp_sink/main/main.c +++ b/examples/bluetooth/a2dp_sink/main/main.c @@ -58,7 +58,7 @@ void app_main() return; } - if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) { + if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) { ESP_LOGE(BT_AV_TAG, "%s enable controller failed\n", __func__); return; } diff --git a/examples/bluetooth/ble_adv/main/app_bt.c b/examples/bluetooth/ble_adv/main/app_bt.c index 6d0ef2459..f6c01a2db 100644 --- a/examples/bluetooth/ble_adv/main/app_bt.c +++ b/examples/bluetooth/ble_adv/main/app_bt.c @@ -227,16 +227,35 @@ void app_main() ESP_ERROR_CHECK( ret ); esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); + if (ret) { + ESP_LOGI(tag, "Bluetooth controller release classic bt memory failed"); + return; + } + if (esp_bt_controller_init(&bt_cfg) != ESP_OK) { ESP_LOGI(tag, "Bluetooth controller initialize failed"); return; } - if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) { + if (esp_bt_controller_enable(ESP_BT_MODE_BLE) != ESP_OK) { ESP_LOGI(tag, "Bluetooth controller enable failed"); return; } + /* + * If call mem release here, also work. Input ESP_BT_MODE_CLASSIC_BT, the function will + * release the memory of classic bt mdoe. + * esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); + * + */ + + /* + * If call mem release here, also work. Input ESP_BT_MODE_BTDM, the function will calculate + * that the BLE mode is already used, so it will release of only classic bt mode. + * esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); + */ + xTaskCreatePinnedToCore(&bleAdvtTask, "bleAdvtTask", 2048, NULL, 5, NULL, 0); }