diff --git a/boards/xtensa/esp32/Kconfig.defconfig b/boards/xtensa/esp32/Kconfig.defconfig index 12f2179cf9a..1765615d7b5 100644 --- a/boards/xtensa/esp32/Kconfig.defconfig +++ b/boards/xtensa/esp32/Kconfig.defconfig @@ -16,3 +16,20 @@ config LOG_DETECT_MISSED_STRDUP default n endif + +if BT + +config HEAP_MEM_POOL_SIZE + default 16384 + +config ENTROPY_GENERATOR + default y + +config DYNAMIC_INTERRUPTS + default y + +choice BT_HCI_BUS_TYPE + default BT_ESP32 +endchoice + +endif # BT diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index e8ac3e6558e..ea87556d796 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -7,3 +7,4 @@ zephyr_sources_ifdef(CONFIG_BT_RPMSG rpmsg.c) zephyr_sources_ifdef(CONFIG_BT_RPMSG_NRF53 rpmsg_nrf53.c) zephyr_sources_ifdef(CONFIG_BT_STM32_IPM ipm_stm32wb.c) zephyr_sources_ifdef(CONFIG_BT_USERCHAN userchan.c) +zephyr_sources_ifdef(CONFIG_BT_ESP32 hci_esp32.c) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 2e7ec5e9781..9ad2c301842 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -63,6 +63,11 @@ config BT_USERCHAN The Bluetooth adapter must be powered off in order for Zephyr to be able to use it. +config BT_ESP32 + bool "ESP32 HCI driver" + help + Espressif HCI bluetooth interface + config BT_NO_DRIVER bool "No default HCI driver" help @@ -128,7 +133,7 @@ endif # BT_RPMSG_NRF53 config BT_DRIVER_QUIRK_NO_AUTO_DLE bool "Host auto-initiated Data Length Update quirk" depends on BT_AUTO_DATA_LEN_UPDATE - default y if BT_RPMSG_NRF53 + default y if BT_RPMSG_NRF53 || BT_ESP32 help Enable the quirk wherein BT Host stack will auto-initiate Data Length Update procedure for new connections for controllers that do not diff --git a/drivers/bluetooth/hci/hci_esp32.c b/drivers/bluetooth/hci/hci_esp32.c new file mode 100644 index 00000000000..ca5f8b46b0d --- /dev/null +++ b/drivers/bluetooth/hci/hci_esp32.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_MODULE_NAME bt_hci_driver_esp32 +#include "common/log.h" + +#include +#include + +#include + +#include + +#define HCI_CMD 0x01 +#define HCI_ACL 0x02 +#define HCI_SCO 0x03 +#define HCI_EVT 0x04 +#define HCI_ISO 0x05 + +#define HCI_BT_ESP32_TIMEOUT K_MSEC(2000) + +static K_SEM_DEFINE(hci_send_sem, 1, 1); + +static bool is_hci_event_discardable(const uint8_t *evt_data) +{ + uint8_t evt_type = evt_data[0]; + + switch (evt_type) { +#if defined(CONFIG_BT_BREDR) + case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI: + case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT: + return true; +#endif + case BT_HCI_EVT_LE_META_EVENT: { + uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)]; + + switch (subevt_type) { + case BT_HCI_EVT_LE_ADVERTISING_REPORT: + return true; + case BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT: + return true; + default: + return false; + } + } + default: + return false; + } +} + +static struct net_buf *bt_esp_evt_recv(uint8_t *data, size_t remaining) +{ + bool discardable = false; + struct bt_hci_evt_hdr hdr; + struct net_buf *buf; + + if (remaining < sizeof(hdr)) { + BT_ERR("Not enough data for event header"); + return NULL; + } + + discardable = is_hci_event_discardable(data); + + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + remaining -= sizeof(hdr); + + if (remaining != hdr.len) { + BT_ERR("Event payload length is not correct"); + return NULL; + } + BT_DBG("len %u", hdr.len); + + buf = bt_buf_get_evt(hdr.evt, discardable, K_NO_WAIT); + if (!buf) { + if (discardable) { + BT_DBG("Discardable buffer pool full, ignoring event"); + } else { + BT_ERR("No available event buffers!"); + } + return buf; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static struct net_buf *bt_esp_acl_recv(uint8_t *data, size_t remaining) +{ + struct bt_hci_acl_hdr hdr; + struct net_buf *buf; + + if (remaining < sizeof(hdr)) { + BT_ERR("Not enough data for ACL header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + remaining -= sizeof(hdr); + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + } else { + BT_ERR("No available ACL buffers!"); + return NULL; + } + + if (remaining != sys_le16_to_cpu(hdr.len)) { + BT_ERR("ACL payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + BT_DBG("len %u", remaining); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static struct net_buf *bt_esp_iso_recv(uint8_t *data, size_t remaining) +{ + struct bt_hci_iso_hdr hdr; + struct net_buf *buf; + + if (remaining < sizeof(hdr)) { + BT_ERR("Not enough data for ISO header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + remaining -= sizeof(hdr); + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + } else { + BT_ERR("No available ISO buffers!"); + return NULL; + } + + if (remaining != sys_le16_to_cpu(hdr.len)) { + BT_ERR("ISO payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + BT_DBG("len %zu", remaining); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static int hci_esp_host_rcv_pkt(uint8_t *data, uint16_t len) +{ + uint8_t pkt_indicator; + struct net_buf *buf = NULL; + size_t remaining = len; + + BT_HEXDUMP_DBG(data, len, "host packet data:"); + + pkt_indicator = *data++; + remaining -= sizeof(pkt_indicator); + + switch (pkt_indicator) { + case HCI_EVT: + buf = bt_esp_evt_recv(data, remaining); + break; + + case HCI_ACL: + buf = bt_esp_acl_recv(data, remaining); + break; + + case HCI_SCO: + buf = bt_esp_iso_recv(data, remaining); + break; + + default: + BT_ERR("Unknown HCI type %u", pkt_indicator); + return -1; + } + + if (buf) { + BT_DBG("Calling bt_recv(%p)", buf); + + bt_recv(buf); + } + + return 0; +} + +static void hci_esp_controller_rcv_pkt_ready(void) +{ + k_sem_give(&hci_send_sem); +} + +static esp_vhci_host_callback_t vhci_host_cb = { + hci_esp_controller_rcv_pkt_ready, + hci_esp_host_rcv_pkt +}; + +static int bt_esp32_send(struct net_buf *buf) +{ + int err = 0; + uint8_t pkt_indicator; + + BT_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + pkt_indicator = HCI_ACL; + break; + case BT_BUF_CMD: + pkt_indicator = HCI_CMD; + break; + case BT_BUF_ISO_OUT: + pkt_indicator = HCI_ISO; + break; + default: + BT_ERR("Unknown type %u", bt_buf_get_type(buf)); + goto done; + } + net_buf_push_u8(buf, pkt_indicator); + + BT_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:"); + + if (!esp_vhci_host_check_send_available()) { + BT_WARN("Controller not ready to receive packets"); + } + + if (k_sem_take(&hci_send_sem, HCI_BT_ESP32_TIMEOUT) == 0) { + esp_vhci_host_send_packet(buf->data, buf->len); + } else { + BT_ERR("Send packet timeout error"); + err = -ETIMEDOUT; + } + +done: + net_buf_unref(buf); + k_sem_give(&hci_send_sem); + + return err; +} + +static int bt_esp32_ble_init(void) +{ + int ret; + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + +#ifdef CONFIG_BT_BREDR + esp_bt_mode_t mode = ESP_BT_MODE_BTDM; +#else + esp_bt_mode_t mode = ESP_BT_MODE_BLE; +#endif + + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + BT_ERR("Bluetooth controller init failed %d", ret); + return ret; + } + + ret = esp_bt_controller_enable(mode); + if (ret) { + BT_ERR("Bluetooth controller enable failed: %d", ret); + return ret; + } + + esp_vhci_host_register_callback(&vhci_host_cb); + + return 0; +} + +static int bt_esp32_open(void) +{ + int err; + + err = bt_esp32_ble_init(); + if (err) { + return err; + } + + BT_DBG("ESP32 BT started"); + + return 0; +} + +static const struct bt_hci_driver drv = { + .name = "BT ESP32", + .open = bt_esp32_open, + .send = bt_esp32_send, + .bus = BT_HCI_DRIVER_BUS_IPM, +#if defined(CONFIG_BT_DRIVER_QUIRK_NO_AUTO_DLE) + .quirks = BT_QUIRK_NO_AUTO_DLE, +#endif +}; + +static int bt_esp32_init(const struct device *unused) +{ + ARG_UNUSED(unused); + + bt_hci_driver_register(&drv); + + return 0; +} + +SYS_INIT(bt_esp32_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/soc/xtensa/esp32/Kconfig.soc b/soc/xtensa/esp32/Kconfig.soc index 41c13a9e63b..743ffc17dfd 100644 --- a/soc/xtensa/esp32/Kconfig.soc +++ b/soc/xtensa/esp32/Kconfig.soc @@ -7,12 +7,19 @@ config SOC_ESP32 select CLOCK_CONTROL select CLOCK_CONTROL_ESP32 +if SOC_ESP32 + config IDF_TARGET_ESP32 bool "ESP32 as target board" default y - depends on SOC_ESP32 config ESPTOOLPY_FLASHFREQ_80M bool default y - depends on SOC_ESP32 + +config ESP32_BT_RESERVE_DRAM + hex "Bluetooth controller reserved RAM region" + default 0xdb5c if BT + default 0 + +endif # SOC_ESP32 diff --git a/soc/xtensa/esp32/linker.ld b/soc/xtensa/esp32/linker.ld index 4cb39b5de43..723a3b36ea4 100644 --- a/soc/xtensa/esp32/linker.ld +++ b/soc/xtensa/esp32/linker.ld @@ -39,9 +39,8 @@ MEMORY * * FIXME: * - Utilize available memory regions to full capacity - * - Reserve memory region for BT controller library from ROM */ - dram0_0_seg(RW): org = 0x3FFB0000, len = 0x30000 + dram0_0_seg(RW): org = 0x3FFB0000 + CONFIG_ESP32_BT_RESERVE_DRAM, len = 0x2c200 - CONFIG_ESP32_BT_RESERVE_DRAM dram0_1_seg(RW): org = 0x3FFE4350, len = 0x1BCB0 drom0_0_seg(R): org = 0x3F400020, len = 0x400000-0x20 rtc_iram_seg(RWX): org = 0x400C0000, len = 0x2000 @@ -206,6 +205,12 @@ _net_buf_pool_list = _esp_net_buf_pool_list; .dram0.data : { _data_start = ABSOLUTE(.); + + _btdm_data_start = ABSOLUTE(.); + *libbtdm_app.a:(.data .data.*) + . = ALIGN (4); + _btdm_data_end = ABSOLUTE(.); + *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -260,6 +265,26 @@ _net_buf_pool_list = _esp_net_buf_pool_list; . = ALIGN(4); #endif +#if defined(CONFIG_BT_BREDR) + . = ALIGN(4); + Z_LINK_ITERABLE(bt_l2cap_br_fixed_chan); + . = ALIGN(4); +#endif + +#if defined(CONFIG_BT_MESH) + Z_LINK_ITERABLE(bt_mesh_subnet_cb); + Z_LINK_ITERABLE(bt_mesh_app_key_cb); + Z_LINK_ITERABLE(bt_mesh_hb_cb); +#endif + + . = ALIGN(4); + Z_LINK_ITERABLE(bt_gatt_service_static); + . = ALIGN(4); + + . = ALIGN(4); + Z_LINK_ITERABLE(bt_l2cap_fixed_chan); + . = ALIGN(4); + . = ALIGN(4); Z_LINK_ITERABLE(shell); . = ALIGN(4); @@ -363,6 +388,8 @@ __shell_root_cmds_end = __esp_shell_root_cmds_end; #endif _iram_text_end = ABSOLUTE(.); + . = ALIGN(4); + _iram_end = ABSOLUTE(.); } GROUP_LINK_IN(IRAM_REGION) .flash.text : @@ -396,6 +423,12 @@ __shell_root_cmds_end = __esp_shell_root_cmds_end; { . = ALIGN (8); _bss_start = ABSOLUTE(.); + + _btdm_bss_start = ABSOLUTE(.); + *libbtdm_app.a:(.bss .bss.* COMMON) + . = ALIGN (4); + _btdm_bss_end = ABSOLUTE(.); + *(.dynsbss) *(.sbss) *(.sbss.*) @@ -414,6 +447,9 @@ __shell_root_cmds_end = __esp_shell_root_cmds_end; _bss_end = ABSOLUTE(.); } GROUP_LINK_IN(RAMABLE_REGION) + ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), + "DRAM segment data does not fit.") + SECTION_DATA_PROLOGUE(_NOINIT_SECTION_NAME, (NOLOAD),) { . = ALIGN (8); @@ -435,3 +471,6 @@ __shell_root_cmds_end = __esp_shell_root_cmds_end; } } + +ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), + "IRAM0 segment data does not fit.") diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index a8caf984238..a934e323e99 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -190,7 +190,7 @@ if BT_CONN config BT_HCI_ACL_FLOW_CONTROL bool "Controller to Host ACL flow control support" # Enable if building a Host-only build - default y if !BT_CTLR && !BT_STM32_IPM + default y if !BT_CTLR && !BT_STM32_IPM && !BT_ESP32 # Enable if building a Controller-only build default y if BT_HCI_RAW select POLL diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 2c7057ef009..b5ea0628d51 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -119,6 +119,7 @@ config BT_HCI_RESERVE default 1 if BT_SPI default 1 if BT_STM32_IPM default 1 if BT_USERCHAN + default 1 if BT_ESP32 # Even if no driver is selected the following default is still # needed e.g. for unit tests. default 0