Skip to content

Commit

Permalink
component/bt : support bluetooth controller DRAM release dynamically
Browse files Browse the repository at this point in the history
1. remove CONFIG_BT_DRAM_RELEASE from Kconfig
2. add API to release bluetooth controller DRAM to heap
  • Loading branch information
tianhaoesp committed Sep 21, 2017
1 parent b54719d commit 3e2ee24
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 65 deletions.
9 changes: 0 additions & 9 deletions components/bt/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
153 changes: 114 additions & 39 deletions components/bt/bt.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@
#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 */
Expand All @@ -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_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{\
Expand All @@ -81,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);
Expand Down Expand Up @@ -309,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
Expand All @@ -321,22 +349,74 @@ static uint32_t btdm_config_mask_load(void)
return mask;
}

static void btdm_controller_release_mem(void)
static void btdm_controller_mem_init(void)
{
uint32_t bt_mem_start, bt_mem_end;
#if CONFIG_BT_DRAM_RELEASE
bt_mem_start = 0x3ffb0000; bt_mem_end = 0x3ffb3000; //Reserve BT data region
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
ESP_ERROR_CHECK( heap_caps_add_region((intptr_t)bt_mem_start, (intptr_t)bt_mem_end));
bt_mem_start = 0x3ffbdb28; bt_mem_end = 0x3ffc0000; //Reserve BT data region
ESP_ERROR_CHECK( heap_caps_add_region((intptr_t)bt_mem_start, (intptr_t)bt_mem_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_ERROR_CHECK( heap_caps_add_region((intptr_t)bt_mem_start, (intptr_t)bt_mem_end));
/* 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)
Expand All @@ -348,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;
}
Expand All @@ -359,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);
Expand All @@ -380,8 +467,6 @@ esp_err_t esp_bt_controller_deinit(void)
return ESP_ERR_NO_MEM;
}

btdm_controller_release_mem();

btdm_controller_status = ESP_BT_CONTROLLER_STATUS_SHUTDOWN;
return ESP_OK;
}
Expand All @@ -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) {
return ESP_ERR_INVALID_STATE;
}
#if CONFIG_BT_DRAM_RELEASE
if (mode != ESP_BT_MODE_BLE) {
#else
if (mode != ESP_BT_MODE_BLE
&& mode != ESP_BT_MODE_CLASSIC_BT
&& mode != ESP_BT_MODE_BTDM) {
#endif

//check the mode is available mode
if (mode & ~btdm_dram_available_region[0].mode) {
return ESP_ERR_INVALID_ARG;
}

Expand All @@ -420,21 +501,15 @@ 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;

if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}

if (mode != 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);
ret = btdm_controller_disable(btdm_controller_get_mode());
if (ret < 0) {
return ESP_ERR_INVALID_STATE;
}
Expand Down
43 changes: 34 additions & 9 deletions components/bt/include/bt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 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
*/
esp_err_t esp_bt_controller_deinit(void);

/**
* @brief Enable BT controller.
* By a knowned issue, if the function already set mode, it can not set another mode dynamically.
* If want to change mode type, should call esp_bt_controller_disable, then call esp_bt_controller_enable.
* 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.
* If CONFIG_BT_DRAM_RELEASE=y, the param mode should only be ESP_BT_MODE_BLE.
* @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.
* 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
*/
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
Expand Down Expand Up @@ -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);

/** @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
Expand Down
2 changes: 1 addition & 1 deletion components/bt/lib
Submodule lib updated from a3aee1 to f75b0b
8 changes: 1 addition & 7 deletions components/soc/esp32/soc_memory_layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 19 additions & 0 deletions examples/bluetooth/ble_adv/main/app_bt.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,12 @@ 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;
Expand All @@ -237,6 +243,19 @@ void app_main()
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);
}

0 comments on commit 3e2ee24

Please sign in to comment.