1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 22:43:50 +01:00

cpu/esp32: add BLE support for the ESP32-H2

This commit is contained in:
Gunar Schorcht 2025-04-19 09:36:24 +02:00
parent 62fd4805d9
commit e528d3488d
6 changed files with 113 additions and 15 deletions

View File

@ -27,6 +27,9 @@ ifneq (,$(filter esp_ble,$(USEMODULE)))
ifeq (esp32,$(CPU_FAM))
FEATURES_REQUIRED += esp_ble_esp32
USEPKG += esp32_sdk_lib_bt_esp32
else ifeq (esp32h2,$(CPU_FAM))
FEATURES_REQUIRED += esp_ble_esp32h2
USEPKG += esp32_sdk_lib_bt_esp32h2
else ifneq (,$(filter esp32c3 esp32s3,$(CPU_FAM)))
FEATURES_REQUIRED += esp_ble_esp32c3
USEPKG += esp32_sdk_lib_bt_esp32c3
@ -161,9 +164,15 @@ endif
ifneq (,$(filter nimble,$(USEPKG)))
USEMODULE += esp_ble
USEMODULE += esp_ble_nimble
USEMODULE += esp_idf_nvs_flash
USEMODULE += nimble_host
USEMODULE += nimble_transport_hci_h4
USEMODULE += ztimer_msec
ifeq (esp32h2,$(CPU_FAM))
# TODO for the moment, we use tinycrypt for encryption
# USEPKG += esp32_sdk_mbedtls
USEPKG += esp32_sdk_lib_coexist
endif
endif
ifneq (,$(filter periph_adc,$(USEMODULE)))

View File

@ -45,17 +45,19 @@ ifneq (esp32h2,$(CPU_FAM))
FEATURES_PROVIDED += esp_wifi_enterprise
endif
ifeq (esp32,$(CPU_FAM))
ifneq (,$(filter esp32 esp32c3 esp32h2 esp32s3,$(CPU_FAM)))
FEATURES_PROVIDED += ble_nimble
FEATURES_PROVIDED += ble_nimble_netif
FEATURES_PROVIDED += esp_ble
endif
ifeq (esp32,$(CPU_FAM))
FEATURES_PROVIDED += esp_ble_esp32
else ifeq (esp32h2,$(CPU_FAM))
FEATURES_PROVIDED += esp_ble_esp32h2
else ifneq (,$(filter esp32c3 esp32s3,$(CPU_FAM)))
FEATURES_PROVIDED += ble_adv_ext
FEATURES_PROVIDED += ble_nimble
FEATURES_PROVIDED += ble_nimble_netif
FEATURES_PROVIDED += ble_phy_2mbit
FEATURES_PROVIDED += esp_ble
FEATURES_PROVIDED += esp_ble_esp32c3
endif

View File

@ -184,6 +184,9 @@ ifneq (,$(filter esp_ble,$(USEMODULE)))
INCLUDES += -I$(ESP32_SDK_DIR)/components/bt/include/esp32c3/include
endif
ifeq (esp32h2,$(CPU_FAM))
CFLAGS += -Ddefault_RNG_defined=0
CFLAGS += -DNIMBLE_OS_MSYS_INIT_IN_CONTROLLER=1
CFLAGS += -DNIMBLE_G_MSYS_POOL_LIST_IN_CONTROLLER=1
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/port/$(CPU_FAM)/private_include
endif
endif
@ -211,6 +214,7 @@ endif
ifneq (,$(filter esp_idf_nvs_flash,$(USEMODULE)))
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_partition/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/nvs_flash/include
CFLAGS += -DMBEDTLS_CIPHER_MODE_XTS
endif
@ -401,12 +405,18 @@ endif
# Libraries needed when using esp_ble
ifneq (,$(filter esp_ble,$(USEMODULE)))
LINKFLAGS += -L$(ESP32_SDK_LIB_PHY_DIR)/$(CPU_FAM)
LINKFLAGS += -L$(ESP32_SDK_LIB_BT_DIR)/$(CPU_FAM)
ARCHIVES += -lbtdm_app
ARCHIVES += -lphy -lstdc++
ifneq (,$(filter esp32 esp32c3 esp32s3,$(CPU_FAM)))
LINKFLAGS += -L$(ESP32_SDK_LIB_BT_DIR)/$(CPU_FAM)
ARCHIVES += -lbtdm_app
else ifeq (esp32h2,$(CPU_FAM))
LINKFLAGS += -L$(ESP32_SDK_LIB_COEXIST_DIR)/$(CPU_FAM)
LINKFLAGS += -L$(ESP32_SDK_LIB_BT_DIR)
ARCHIVES += -lble_app -lcoexist
endif
ifeq (esp32,$(CPU_FAM))
ARCHIVES += -lrtc
else ifneq (,$(filter esp32c3 esp32s3,$(CPU_FAM)))
else ifneq (,$(filter esp32c3 esp32h2 esp32s3,$(CPU_FAM)))
ARCHIVES += -lbtbb
endif
endif

View File

@ -22,14 +22,16 @@
#include "log.h"
#include "esp_bt.h"
#include "mutex.h"
#include "nimble_riot.h"
#include "od.h"
#include "host/ble_hs.h"
#include "nimble/hci_common.h"
#include "nimble/nimble_port.h"
#include "nimble/transport/hci_h4.h"
#include "sysinit/sysinit.h"
#include "nvs_flash.h"
#define ENABLE_DEBUG 0
#include "debug.h"
@ -45,6 +47,23 @@
#define BLE_VHCI_TIMEOUT_MS 2000
#if CPU_FAM_ESP32 || CPU_FAM_ESP32S3 || CPU_FAM_ESP32C3
/* On ESP32, ESP32-S3 and ESP32-C3, the BT Controller calls the
* notify_host_send_available callback function when it becomes ready to
* receive commands from the host. It can be used to unlock a mutex that
* is used to synchronize the access to the BT Controller by different
* threads. */
# define BT_CTRL_SUPPORTS_READY_CB 1
#elif CPU_FAM_ESP32C2 || CPU_FAM_ESP32C6 || CPU_FAM_ESP32H2
/* On other ESP32x variants like ESP32-C2, ESP32-C6 and ESP32-H2,
* this callback function is not used and we have to use another mechanism. */
# define BT_CTRL_SUPPORTS_READY_CB 0
# define BT_CTRL_WAIT_READY_CYCLES 10
# define BT_CTRL_WAIT_READY_INTERVALL_MS 10
#else
# error "Platform implementation is missing"
#endif
/* Definition of UART H4 packet types */
enum {
BLE_HCI_UART_H4_NONE = 0x00,
@ -56,19 +75,30 @@ enum {
static const char *LOG_TAG = "esp_nimble";
#if BT_CTRL_SUPPORTS_READY_CB
static mutex_t _esp_vhci_semaphore = MUTEX_INIT;
#endif
static struct hci_h4_sm _esp_h4sm;
static void _ble_vhci_controller_ready_cb(void)
{
DEBUG("%s\n", __func__);
#if BT_CTRL_SUPPORTS_READY_CB
mutex_unlock(&_esp_vhci_semaphore);
#endif
}
static int _ble_vhci_packet_received_cb(uint8_t *data, uint16_t len)
{
DEBUG("%s: data=%p len=%u\n", __func__, data, len);
/* process the HCI H4 formatted packet and call ble_transport_to_hs_* */
len = hci_h4_sm_rx(&_esp_h4sm, data, len);
if (nimble_port_initialized) {
len = hci_h4_sm_rx(&_esp_h4sm, data, len);
}
return 0;
}
@ -81,6 +111,9 @@ static inline int _ble_transport_to_ll(uint8_t *packet, uint16_t len)
{
uint8_t rc = 0;
DEBUG("%s: controller status=%d\n", __func__, esp_bt_controller_get_status());
#if BT_CTRL_SUPPORTS_READY_CB
/* check whether the controller is ready to accept packets */
if (!esp_vhci_host_check_send_available()) {
LOG_TAG_DEBUG(LOG_TAG, "Controller not ready to accept packets");
@ -94,6 +127,23 @@ static inline int _ble_transport_to_ll(uint8_t *packet, uint16_t len)
else {
rc = BLE_HS_ETIMEOUT_HCI;
}
#else
unsigned i = 0;
for (; i < BT_CTRL_WAIT_READY_CYCLES; i++) {
if (esp_vhci_host_check_send_available()) {
break;
}
ztimer_sleep(ZTIMER_MSEC, BT_CTRL_WAIT_READY_INTERVALL_MS);
}
if (i < BT_CTRL_WAIT_READY_CYCLES) {
esp_vhci_host_send_packet(packet, len);
}
else {
LOG_TAG_DEBUG(LOG_TAG, "Controller not ready to accept packets");
rc = BLE_HS_ETIMEOUT_HCI;
}
#endif
return rc;
}
@ -113,8 +163,8 @@ int ble_transport_to_ll_cmd_impl(void *buf)
packet[0] = BLE_HCI_UART_H4_CMD; /* first byte is the packet indicator */
memcpy(packet + 1, cmd, len - 1);
DEBUG("%s: CMD host to ctrl\n", __func__);
if (ENABLE_DEBUG && IS_USED(MODULE_OD)) {
printf("CMD host to ctrl:\n");
od_hex_dump(packet + 1, len - 1, OD_WIDTH_DEFAULT);
}
@ -147,8 +197,8 @@ int ble_transport_to_ll_acl_impl(struct os_mbuf *om)
packet[0] = BLE_HCI_UART_H4_ACL;
len++;
DEBUG("%s: ACL host to ctrl\n", __func__);
if (ENABLE_DEBUG && IS_USED(MODULE_OD)) {
printf("ACL host to ctrl:\n");
od_hex_dump(packet + 1,
(om->om_len < 32) ? om->om_len : 32, OD_WIDTH_DEFAULT);
}
@ -169,17 +219,19 @@ static int _esp_hci_h4_frame_cb(uint8_t pkt_type, void *data)
{
int rc = 0;
DEBUG("%s: pkt_type=%d data=%p\n", __func__, pkt_type, data);
switch (pkt_type) {
case HCI_H4_ACL:
DEBUG("%s: ACL ctrl to host\n", __func__);
if (ENABLE_DEBUG && IS_USED(MODULE_OD)) {
printf("ACL ctrl to host:\n");
od_hex_dump((uint8_t *)data, 4, OD_WIDTH_DEFAULT);
}
rc = ble_transport_to_hs_acl(data);
break;
case HCI_H4_EVT:
DEBUG("%s: EVT ctrl to host\n", __func__);
if (ENABLE_DEBUG && IS_USED(MODULE_OD)) {
printf("EVT ctrl to host:\n");
od_hex_dump((uint8_t *)data, ((uint8_t *)data)[1] + 2, OD_WIDTH_DEFAULT);
}
rc = ble_transport_to_hs_evt(data);
@ -197,6 +249,12 @@ void esp_ble_nimble_init(void)
esp_err_t ret;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if (IS_ACTIVE(CONFIG_ESP_WIFI_NVS_ENABLED) && !IS_USED(MODULE_ESP_WIFI_ANY)) {
if (nvs_flash_init() != ESP_OK) {
LOG_ERROR("nfs_flash_init failed\n");
}
}
/* TODO: BLE mode only used, the memory for BT Classic could be released
if ((ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);) != ESP_OK) {
LOG_TAG_ERROR(LOG_TAG,
@ -206,17 +264,23 @@ void esp_ble_nimble_init(void)
}
*/
DEBUG("%s: ctrl status=%d\n", __func__, esp_bt_controller_get_status());
/* init and enable the Bluetooth LE controller */
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
LOG_TAG_ERROR(LOG_TAG, "Bluetooth controller initialize failed: %d", ret);
assert(0);
}
DEBUG("%s: ctrl status=%d\n", __func__, esp_bt_controller_get_status());
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) {
LOG_TAG_ERROR(LOG_TAG, "Bluetooth controller enable failed: %d", ret);
assert(0);
}
DEBUG("%s: ctrl status=%d\n", __func__, esp_bt_controller_get_status());
/* register callbacks from Bluetooth LE controller */
if ((ret = esp_vhci_host_register_callback(&vhci_host_cb)) != ESP_OK) {
assert(0);

View File

@ -49,6 +49,7 @@ extern "C" {
#endif
#define CPU_INUM_GPIO 2 /**< Level interrupt with low priority 1 */
#define CPU_INUM_BLE 5 /**< Level interrupt with low priority 1 */
#define CPU_INUM_BT_MAC 8 /**< Level interrupt with low priority 1 */
#define CPU_INUM_RTT 9 /**< Level interrupt with low priority 1 */
#define CPU_INUM_SERIAL_JTAG 10 /**< Edge interrupt with low priority 1 */
#define CPU_INUM_I2C 12 /**< Level interrupt with low priority 1 */

View File

@ -45,7 +45,7 @@ typedef struct intr_handle_data_t {
uint8_t level;
} intr_handle_data_t;
/* TODO change to a clearer approach */
/* TODO change to a clearer and more dynamic approach */
static const struct intr_handle_data_t _irq_data_table[] = {
#ifndef __XTENSA__
{ ETS_FROM_CPU_INTR0_SOURCE, CPU_INUM_SOFTWARE, 1 },
@ -81,8 +81,10 @@ static const struct intr_handle_data_t _irq_data_table[] = {
#endif
#if defined(SOC_BLE_SUPPORTED)
# if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S3) || defined(CPU_FAM_ESP32C3)
{ ETS_RWBLE_INTR_SOURCE, CPU_INUM_BLE, 2 },
{ ETS_RWBLE_INTR_SOURCE, CPU_INUM_BLE, 1 },
# elif defined(CPU_FAM_ESP32H2)
{ ETS_LP_BLE_TIMER_INTR_SOURCE, CPU_INUM_BLE, 1 },
{ ETS_BT_MAC_INTR_SOURCE, CPU_INUM_BT_MAC, 1 },
# else
# error "Platform implementation is missing"
# endif
@ -193,12 +195,22 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler,
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
/* set interrupt level given by flags */
esp_cpu_intr_set_priority(_irq_data_table[i].intr, esp_intr_flags_to_level(flags));
esp_cpu_intr_set_type(_irq_data_table[i].intr,
flags & ESP_INTR_FLAG_EDGE ? ESP_CPU_INTR_TYPE_EDGE
: ESP_CPU_INTR_TYPE_LEVEL);
#endif
#if SOC_INT_PLIC_SUPPORTED
RV_CLEAR_CSR(mideleg, BIT(_irq_data_table[i].intr));
#endif
/* enable the interrupt if ESP_INTR_FLAG_INTRDISABLED is not set */
if ((flags & ESP_INTR_FLAG_INTRDISABLED) == 0) {
esp_cpu_intr_enable(BIT(_irq_data_table[i].intr));
}
else {
esp_cpu_intr_disable(BIT(_irq_data_table[i].intr));
}
if (ret_handle) {
*((intr_handle_t *)ret_handle) = (const intr_handle_t)&_irq_data_table[i];