Skip to content

Commit aa674c4

Browse files
committed
feat(bt): Added API to get/set low power clock source
1 parent a509144 commit aa674c4

File tree

2 files changed

+164
-78
lines changed
  • components/bt

2 files changed

+164
-78
lines changed

components/bt/controller/esp32/bt.c

Lines changed: 130 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,11 @@ static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0; // number of fractional bit f
450450

451451
#if CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG
452452
// used low power clock
453-
static DRAM_ATTR uint8_t btdm_lpclk_sel;
453+
#if CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL
454+
static DRAM_ATTR uint8_t btdm_lpclk_sel = ESP_BT_SLEEP_CLOCK_EXT_32K_XTAL;
455+
#else
456+
static DRAM_ATTR uint8_t btdm_lpclk_sel = ESP_BT_SLEEP_CLOCK_MAIN_XTAL;
457+
#endif /* CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL */
454458
#endif /* #ifdef CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG */
455459

456460
static DRAM_ATTR QueueHandle_t s_wakeup_req_sem = NULL;
@@ -1492,6 +1496,117 @@ static void hli_queue_setup_pinned_to_core(int core_id)
14921496
}
14931497
#endif /* CONFIG_BTDM_CTRL_HLI */
14941498

1499+
// init low-power control resources
1500+
static esp_err_t btdm_low_power_mode_init(void)
1501+
{
1502+
esp_err_t err = ESP_OK;
1503+
1504+
#ifdef CONFIG_PM_ENABLE
1505+
s_btdm_allow_light_sleep = false;
1506+
#endif
1507+
1508+
// set default sleep clock cycle and its fractional bits
1509+
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
1510+
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
1511+
1512+
#if CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG
1513+
if (btdm_lpclk_sel == ESP_BT_SLEEP_CLOCK_EXT_32K_XTAL) {
1514+
// check whether or not EXT_CRYS is working
1515+
if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
1516+
#ifdef CONFIG_PM_ENABLE
1517+
s_btdm_allow_light_sleep = true;
1518+
#endif
1519+
} else {
1520+
ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n"
1521+
"light sleep mode will not be able to apply when bluetooth is enabled");
1522+
btdm_lpclk_sel = ESP_BT_SLEEP_CLOCK_MAIN_XTAL; // set default value
1523+
}
1524+
} else if (btdm_lpclk_sel != ESP_BT_SLEEP_CLOCK_MAIN_XTAL) {
1525+
assert(0);
1526+
}
1527+
1528+
bool select_src_ret __attribute__((unused));
1529+
bool set_div_ret __attribute__((unused));
1530+
if (btdm_lpclk_sel == ESP_BT_SLEEP_CLOCK_MAIN_XTAL) {
1531+
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL);
1532+
set_div_ret = btdm_lpclk_set_div(esp_clk_xtal_freq() * 2 / MHZ - 1);
1533+
assert(select_src_ret && set_div_ret);
1534+
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
1535+
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
1536+
} else { // btdm_lpclk_sel == BTDM_LPCLK_SEL_XTAL32K
1537+
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL32K);
1538+
set_div_ret = btdm_lpclk_set_div(0);
1539+
assert(select_src_ret && set_div_ret);
1540+
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
1541+
btdm_lpcycle_us = (RTC_CLK_CAL_FRACT > 15) ? (1000000 << (RTC_CLK_CAL_FRACT - 15)) :
1542+
(1000000 >> (15 - RTC_CLK_CAL_FRACT));
1543+
assert(btdm_lpcycle_us != 0);
1544+
}
1545+
btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_ORIG);
1546+
1547+
#elif CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_EVED
1548+
btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_EVED);
1549+
#else
1550+
btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_NONE);
1551+
#endif
1552+
1553+
#ifdef CONFIG_PM_ENABLE
1554+
if (!s_btdm_allow_light_sleep) {
1555+
if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) {
1556+
return err;
1557+
}
1558+
}
1559+
if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) {
1560+
return err;
1561+
}
1562+
esp_timer_create_args_t create_args = {
1563+
.callback = btdm_slp_tmr_callback,
1564+
.arg = NULL,
1565+
.name = "btSlp"
1566+
};
1567+
if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) {
1568+
return err;
1569+
}
1570+
1571+
s_pm_lock_acquired = true;
1572+
#endif
1573+
1574+
return err;
1575+
}
1576+
1577+
esp_bt_sleep_clock_t esp_bt_get_lpclk_src(void)
1578+
{
1579+
#if CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG
1580+
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED &&
1581+
btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
1582+
return ESP_BT_SLEEP_CLOCK_NONE;
1583+
}
1584+
return btdm_lpclk_sel;
1585+
#else
1586+
return ESP_BT_SLEEP_CLOCK_NONE;
1587+
#endif
1588+
}
1589+
1590+
esp_err_t esp_bt_set_lpclk_src(esp_bt_sleep_clock_t lpclk)
1591+
{
1592+
#if CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG
1593+
if (lpclk < ESP_BT_SLEEP_CLOCK_MAIN_XTAL || lpclk > ESP_BT_SLEEP_CLOCK_EXT_32K_XTAL) {
1594+
return ESP_ERR_INVALID_ARG;
1595+
}
1596+
1597+
if (btdm_controller_status == ESP_BT_CONTROLLER_STATUS_INITED ||
1598+
btdm_controller_status == ESP_BT_CONTROLLER_STATUS_ENABLED) {
1599+
ESP_LOGW(BTDM_LOG_TAG, "Please set the Bluetooth sleep clock source before Bluetooth initialization");
1600+
return ESP_ERR_INVALID_STATE;
1601+
}
1602+
1603+
btdm_lpclk_sel = lpclk;
1604+
return ESP_OK;
1605+
#else
1606+
return ESP_ERR_NOT_SUPPORTED;
1607+
#endif
1608+
}
1609+
14951610
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
14961611
{
14971612
esp_err_t err;
@@ -1556,85 +1671,17 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
15561671
periph_module_enable(PERIPH_BT_MODULE);
15571672
periph_module_reset(PERIPH_BT_MODULE);
15581673

1559-
#ifdef CONFIG_PM_ENABLE
1560-
s_btdm_allow_light_sleep = false;
1561-
#endif
1562-
1563-
// set default sleep clock cycle and its fractional bits
1564-
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
1565-
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
1566-
1567-
#if CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG
1568-
1569-
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
1570-
#if CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL
1571-
// check whether or not EXT_CRYS is working
1572-
if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
1573-
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32kHz XTAL
1574-
#ifdef CONFIG_PM_ENABLE
1575-
s_btdm_allow_light_sleep = true;
1576-
#endif
1577-
} else {
1578-
ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n"
1579-
"light sleep mode will not be able to apply when bluetooth is enabled");
1580-
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
1581-
}
1582-
#else
1583-
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
1584-
#endif
1585-
1586-
bool select_src_ret __attribute__((unused));
1587-
bool set_div_ret __attribute__((unused));
1588-
if (btdm_lpclk_sel == BTDM_LPCLK_SEL_XTAL) {
1589-
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL);
1590-
set_div_ret = btdm_lpclk_set_div(esp_clk_xtal_freq() * 2 / MHZ - 1);
1591-
assert(select_src_ret && set_div_ret);
1592-
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
1593-
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
1594-
} else { // btdm_lpclk_sel == BTDM_LPCLK_SEL_XTAL32K
1595-
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL32K);
1596-
set_div_ret = btdm_lpclk_set_div(0);
1597-
assert(select_src_ret && set_div_ret);
1598-
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
1599-
btdm_lpcycle_us = (RTC_CLK_CAL_FRACT > 15) ? (1000000 << (RTC_CLK_CAL_FRACT - 15)) :
1600-
(1000000 >> (15 - RTC_CLK_CAL_FRACT));
1601-
assert(btdm_lpcycle_us != 0);
1602-
}
1603-
btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_ORIG);
1604-
1605-
#elif CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_EVED
1606-
btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_EVED);
1607-
#else
1608-
btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_NONE);
1609-
#endif
1610-
16111674
#if CONFIG_BTDM_CTRL_HCI_UART_FLOW_CTRL_EN
16121675
sdk_config_set_uart_flow_ctrl_enable(true);
16131676
#else
16141677
sdk_config_set_uart_flow_ctrl_enable(false);
16151678
#endif
16161679

1617-
#ifdef CONFIG_PM_ENABLE
1618-
if (!s_btdm_allow_light_sleep) {
1619-
if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) {
1620-
goto error;
1621-
}
1622-
}
1623-
if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) {
1624-
goto error;
1625-
}
1626-
esp_timer_create_args_t create_args = {
1627-
.callback = btdm_slp_tmr_callback,
1628-
.arg = NULL,
1629-
.name = "btSlp"
1630-
};
1631-
if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) {
1680+
if ((err = btdm_low_power_mode_init()) != ESP_OK) {
1681+
ESP_LOGE(BTDM_LOG_TAG, "Low power module initialization failed");
16321682
goto error;
16331683
}
16341684

1635-
s_pm_lock_acquired = true;
1636-
#endif
1637-
16381685
#if CONFIG_SW_COEXIST_ENABLE
16391686
coex_init();
16401687
#endif
@@ -1673,10 +1720,9 @@ esp_err_t esp_bt_controller_deinit(void)
16731720
return ESP_OK;
16741721
}
16751722

1676-
static void bt_controller_deinit_internal(void)
1723+
// deinit low power control resources
1724+
static void btdm_low_power_mode_deinit(void)
16771725
{
1678-
periph_module_disable(PERIPH_BT_MODULE);
1679-
16801726
#ifdef CONFIG_PM_ENABLE
16811727
if (!s_btdm_allow_light_sleep) {
16821728
esp_pm_lock_delete(s_light_sleep_pm_lock);
@@ -1697,6 +1743,16 @@ static void bt_controller_deinit_internal(void)
16971743
s_pm_lock_acquired = false;
16981744
#endif
16991745

1746+
btdm_lpcycle_us = 0;
1747+
btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_NONE);
1748+
}
1749+
1750+
static void bt_controller_deinit_internal(void)
1751+
{
1752+
periph_module_disable(PERIPH_BT_MODULE);
1753+
1754+
btdm_low_power_mode_deinit();
1755+
17001756
if (s_wakeup_req_sem) {
17011757
semphr_delete_wrapper(s_wakeup_req_sem);
17021758
s_wakeup_req_sem = NULL;
@@ -1709,9 +1765,6 @@ static void bt_controller_deinit_internal(void)
17091765

17101766
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
17111767

1712-
btdm_lpcycle_us = 0;
1713-
btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_NONE);
1714-
17151768
esp_bt_power_domain_off();
17161769

17171770
esp_phy_modem_deinit();

components/bt/include/esp32/include/esp_bt.h

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -393,6 +393,15 @@ typedef enum {
393393
ESP_SCO_DATA_PATH_PCM = 1, /*!< data over PCM interface */
394394
} esp_sco_data_path_t;
395395

396+
/**
397+
* @brief Bluetooth sleep clock
398+
*/
399+
typedef enum {
400+
ESP_BT_SLEEP_CLOCK_NONE = 0, /*!< Sleep clock not configured */
401+
ESP_BT_SLEEP_CLOCK_MAIN_XTAL = 1, /*!< SoC main crystal */
402+
ESP_BT_SLEEP_CLOCK_EXT_32K_XTAL = 2, /*!< External 32.768kHz crystal/oscillator */
403+
} esp_bt_sleep_clock_t;
404+
396405
/**
397406
* @brief Initialize the Bluetooth Controller to allocate tasks and other resources
398407
*
@@ -690,6 +699,30 @@ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len);
690699
* - ESP_FAIL: Failure
691700
*/
692701
esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback);
702+
703+
/**
704+
* @brief Get the Bluetooth module sleep clock source.
705+
*
706+
* @note This function should be called after `esp_bt_controller_init()`
707+
*
708+
* @return
709+
* - Clock source used in Bluetooth low power mode
710+
*/
711+
esp_bt_sleep_clock_t esp_bt_get_lpclk_src(void);
712+
713+
/**
714+
* @brief Set the Bluetooth module sleep clock source.
715+
*
716+
* @note This function should be called before `esp_bt_controller_init()`
717+
*
718+
* @param[in] lpclk Bluetooth sleep clock source
719+
*
720+
* @return
721+
* - ESP_OK: Success
722+
* - ESP_ERR_INVALID_ARG: Invalid argument
723+
*/
724+
esp_err_t esp_bt_set_lpclk_src(esp_bt_sleep_clock_t lpclk);
725+
693726
#ifdef __cplusplus
694727
}
695728
#endif

0 commit comments

Comments
 (0)