component/bt : support bluetooth controller DRAM release dynamically

1. remove CONFIG_BT_DRAM_RELEASE from Kconfig
2. add API to release bluetooth controller DRAM to heap
This commit is contained in:
Tian Hao 2017-09-19 20:10:35 +08:00
parent b54719d00f
commit 3e2ee24e4f
6 changed files with 169 additions and 65 deletions

View file

@ -31,15 +31,6 @@ config CLASSIC_BT_ENABLED
help help
For now this option needs "SMP_ENABLE" to be set to yes 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 config GATTS_ENABLE
bool "Include GATT server module(GATTS)" bool "Include GATT server module(GATTS)"
depends on BLUEDROID_ENABLED depends on BLUEDROID_ENABLED

View file

@ -41,10 +41,9 @@
#define BTDM_INIT_PERIOD (5000) /* ms */ #define BTDM_INIT_PERIOD (5000) /* ms */
/* Bluetooth system and controller config */ /* Bluetooth system and controller config */
#define BTDM_CFG_BT_EM_RELEASE (1<<0) #define BTDM_CFG_BT_DATA_RELEASE (1<<0)
#define BTDM_CFG_BT_DATA_RELEASE (1<<1) #define BTDM_CFG_HCI_UART (1<<1)
#define BTDM_CFG_HCI_UART (1<<2) #define BTDM_CFG_CONTROLLER_RUN_APP_CPU (1<<2)
#define BTDM_CFG_CONTROLLER_RUN_APP_CPU (1<<3)
/* Other reserved for future */ /* Other reserved for future */
/* not for user call, so don't put to include file */ /* not for user call, so don't put to include file */
@ -69,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_set(int power_type, int power_level);
extern int ble_txpwr_get(int power_type); 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_DEBUG(...)
#define BT_API_CALL_CHECK(info, api_call, ret) \ #define BT_API_CALL_CHECK(info, api_call, ret) \
do{\ do{\
@ -81,6 +87,27 @@ do{\
#define OSI_FUNCS_TIME_BLOCKING 0xffffffff #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 { struct osi_funcs_t {
xt_handler (*_set_isr)(int n, xt_handler f, void *arg); xt_handler (*_set_isr)(int n, xt_handler f, void *arg);
void (*_ints_on)(unsigned int mask); void (*_ints_on)(unsigned int mask);
@ -309,9 +336,10 @@ static uint32_t btdm_config_mask_load(void)
{ {
uint32_t mask = 0x0; uint32_t mask = 0x0;
#ifdef CONFIG_BT_DRAM_RELEASE if (btdm_dram_available_region[0].mode == ESP_BT_MODE_BLE) {
mask |= (BTDM_CFG_BT_EM_RELEASE | BTDM_CFG_BT_DATA_RELEASE); mask |= BTDM_CFG_BT_DATA_RELEASE;
#endif }
#ifdef CONFIG_BT_HCI_UART #ifdef CONFIG_BT_HCI_UART
mask |= BTDM_CFG_HCI_UART; mask |= BTDM_CFG_HCI_UART;
#endif #endif
@ -321,22 +349,74 @@ static uint32_t btdm_config_mask_load(void)
return mask; return mask;
} }
static void btdm_controller_release_mem(void) static void btdm_controller_mem_init(void)
{ {
uint32_t bt_mem_start, bt_mem_end; /* initialise .bss, .data and .etc section */
#if CONFIG_BT_DRAM_RELEASE memcpy(&_data_start_btdm, (void *)_data_start_btdm_rom, &_data_end_btdm - &_data_start_btdm);
bt_mem_start = 0x3ffb0000; bt_mem_end = 0x3ffb3000; //Reserve BT data region ESP_LOGD(BTDM_LOG_TAG, ".data initialise [0x%08x] <== [0x%08x]\n", (uint32_t)&_data_start_btdm, _data_start_btdm_rom);
ESP_ERROR_CHECK( heap_caps_add_region((intptr_t)bt_mem_start, (intptr_t)bt_mem_end));
bt_mem_start = 0x3ffb8000; bt_mem_end = 0x3ffbbb28; //Reserve BT data region for (int i = 1; i < sizeof(btdm_dram_available_region)/sizeof(btdm_dram_available_region_t); i++) {
ESP_ERROR_CHECK( heap_caps_add_region((intptr_t)bt_mem_start, (intptr_t)bt_mem_end)); if (btdm_dram_available_region[i].mode != ESP_BT_MODE_IDLE) {
bt_mem_start = 0x3ffbdb28; bt_mem_end = 0x3ffc0000; //Reserve BT data region memset((void *)btdm_dram_available_region[i].start, 0x0, btdm_dram_available_region[i].end - btdm_dram_available_region[i].start);
ESP_ERROR_CHECK( heap_caps_add_region((intptr_t)bt_mem_start, (intptr_t)bt_mem_end)); ESP_LOGD(BTDM_LOG_TAG, ".bss initialise [0x%08x] - [0x%08x]\n", btdm_dram_available_region[i].start, btdm_dram_available_region[i].end);
#else }
bt_mem_start = 0x3ffb0000; bt_mem_end = 0x3ffc0000; //Reserve BT hardware shared memory & BT data region }
ESP_ERROR_CHECK( heap_caps_add_region((intptr_t)bt_mem_start, (intptr_t)bt_mem_end)); }
#endif
bt_mem_start = 0x3ffae2a0; bt_mem_end = 0x3ffaff10; //Reserve ROM data region esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode)
ESP_ERROR_CHECK( heap_caps_add_region((intptr_t)bt_mem_start, (intptr_t)bt_mem_end)); {
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) esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
@ -348,6 +428,11 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
return ESP_ERR_INVALID_STATE; 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) { if (cfg == NULL) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
@ -359,6 +444,8 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
btdm_osi_funcs_register(&osi_funcs); btdm_osi_funcs_register(&osi_funcs);
btdm_controller_mem_init();
btdm_cfg_mask = btdm_config_mask_load(); btdm_cfg_mask = btdm_config_mask_load();
ret = btdm_controller_init(btdm_cfg_mask, cfg); ret = btdm_controller_init(btdm_cfg_mask, cfg);
@ -380,8 +467,6 @@ esp_err_t esp_bt_controller_deinit(void)
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
btdm_controller_release_mem();
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_SHUTDOWN; btdm_controller_status = ESP_BT_CONTROLLER_STATUS_SHUTDOWN;
return ESP_OK; return ESP_OK;
} }
@ -393,13 +478,9 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
#if CONFIG_BT_DRAM_RELEASE
if (mode != ESP_BT_MODE_BLE) { //check the mode is available mode
#else if (mode & ~btdm_dram_available_region[0].mode) {
if (mode != ESP_BT_MODE_BLE
&& mode != ESP_BT_MODE_CLASSIC_BT
&& mode != ESP_BT_MODE_BTDM) {
#endif
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
@ -420,7 +501,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
return ESP_OK; 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; int ret;
@ -428,13 +509,7 @@ esp_err_t esp_bt_controller_disable(esp_bt_mode_t mode)
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
if (mode != btdm_controller_get_mode()) { ret = btdm_controller_disable(btdm_controller_get_mode());
ESP_LOGW(BTDM_LOG_TAG, "The input mode should be equal %d, but ignore error, use %d instead of %d\n",
btdm_controller_get_mode(), btdm_controller_get_mode(), mode);
mode = btdm_controller_get_mode();
}
ret = btdm_controller_disable(mode);
if (ret < 0) { if (ret < 0) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }

View file

@ -154,30 +154,25 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg);
* *
* This function should be called only once, after any other BT functions are called. * This function should be called only once, after any other BT functions are called.
* This function is not whole completed, esp_bt_controller_init cannot called after this function. * This function is not whole completed, esp_bt_controller_init cannot called after this function.
* After call this function, it will release all the .bss/.data and .etc memory to heap dynamically.
* The release memory about 64K bytes (if CONFIG_BT_DRAM_RELEASE=y, it's about 36K bytes)
* @return ESP_OK - success, other - failed * @return ESP_OK - success, other - failed
*/ */
esp_err_t esp_bt_controller_deinit(void); esp_err_t esp_bt_controller_deinit(void);
/** /**
* @brief Enable BT controller. * @brief Enable BT controller.
* By a knowned issue, if the function already set mode, it can not set another mode dynamically. * Due to a known issue, you cannot call esp_bt_controller_enable() a second time
* If want to change mode type, should call esp_bt_controller_disable, then call esp_bt_controller_enable. * 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. * @param mode : the mode(BLE/BT/BTDM) to enable.
* If CONFIG_BT_DRAM_RELEASE=y, the param mode should only be ESP_BT_MODE_BLE.
* @return ESP_OK - success, other - failed * @return ESP_OK - success, other - failed
*/ */
esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode); esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode);
/** /**
* @brief Disable BT controller * @brief Disable BT controller
* @param mode : the mode(BLE/BT/BTDM) to disable.
* the mode should be equal to which esp_bt_controller_enable set.
* If not, the function will give warning, then use the correct mode to do disable.
* @return ESP_OK - success, other - failed * @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 * @brief Get BT controller is initialised/de-initialised/enabled/disabled
@ -213,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); 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 #ifdef __cplusplus
} }
#endif #endif

@ -1 +1 @@
Subproject commit a3aee13381c21c10590cf8b5a6be3010abf3d4a6 Subproject commit f75b0b9ed881640b79ea2034719ba569d51162f8

View file

@ -150,16 +150,10 @@ const soc_reserved_region_t soc_reserved_regions[] = {
{ 0x3ffe4000, 0x3ffe4350 }, //Reserve ROM APP data region { 0x3ffe4000, 0x3ffe4350 }, //Reserve ROM APP data region
#if CONFIG_BT_ENABLED #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 { 0x3ffb0000, 0x3ffc0000 }, //Reserve BT hardware shared memory & BT data region
#endif
{ 0x3ffae000, 0x3ffaff10 }, //Reserve ROM data region, inc region needed for BT ROM routines { 0x3ffae000, 0x3ffaff10 }, //Reserve ROM data region, inc region needed for BT ROM routines
#else #else
{ 0x3ffae000, 0x3ffae2a0 }, //Reserve ROM data region { 0x3ffae000, 0x3ffae6e0 }, //Reserve ROM data region
#endif #endif
#if CONFIG_MEMMAP_TRACEMEM #if CONFIG_MEMMAP_TRACEMEM

View file

@ -227,6 +227,12 @@ void app_main()
ESP_ERROR_CHECK( ret ); ESP_ERROR_CHECK( ret );
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); 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) { if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
ESP_LOGI(tag, "Bluetooth controller initialize failed"); ESP_LOGI(tag, "Bluetooth controller initialize failed");
return; return;
@ -237,6 +243,19 @@ void app_main()
return; 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); xTaskCreatePinnedToCore(&bleAdvtTask, "bleAdvtTask", 2048, NULL, 5, NULL, 0);
} }