diff --git a/examples/bluetooth/hci/controller_hci_uart_esp32/main/controller_hci_uart_demo.c b/examples/bluetooth/hci/controller_hci_uart_esp32/main/controller_hci_uart_demo.c index 7684b7aa69..be0f9b3bb6 100644 --- a/examples/bluetooth/hci/controller_hci_uart_esp32/main/controller_hci_uart_demo.c +++ b/examples/bluetooth/hci/controller_hci_uart_esp32/main/controller_hci_uart_demo.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -8,21 +8,22 @@ #include #include "nvs_flash.h" #include "esp_bt.h" -#include "soc/uhci_periph.h" +#include "hal/uhci_ll.h" +#include "hal/uart_ll.h" #include "driver/uart.h" -#include "esp_private/periph_ctrl.h" // for enabling UHCI module, remove it after UHCI driver is released #include "esp_log.h" static const char *tag = "CONTROLLER_UART_HCI"; +#define UHCI_PORT_NUM (0) + static void uart_gpio_reset(void) { -#if CONFIG_BTDM_CTRL_HCI_UART_NO == 1 - periph_module_enable(PERIPH_UART1_MODULE); -#elif CONFIG_BTDM_CTRL_HCI_UART_NO == 2 - periph_module_enable(PERIPH_UART2_MODULE); -#endif - periph_module_enable(PERIPH_UHCI0_MODULE); + int __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused)); // To avoid build errors/warnings about __DECLARE_RCC_ATOMIC_ENV + uart_ll_enable_bus_clock(CONFIG_BTDM_CTRL_HCI_UART_NO, true); + uart_ll_reset_register(CONFIG_BTDM_CTRL_HCI_UART_NO); + uhci_ll_enable_bus_clock(UHCI_PORT_NUM, true); + uhci_ll_reset_register(UHCI_PORT_NUM); #ifdef CONFIG_BTDM_CTRL_HCI_UART_NO ESP_LOGI(tag, "HCI UART%d Pin select: TX 5, RX 18, CTS 23, RTS 19 Baudrate:%d", CONFIG_BTDM_CTRL_HCI_UART_NO, CONFIG_BTDM_CTRL_HCI_UART_BAUDRATE); diff --git a/examples/bluetooth/hci/controller_hci_uart_esp32c3_and_esp32s3/main/CMakeLists.txt b/examples/bluetooth/hci/controller_hci_uart_esp32c3_and_esp32s3/main/CMakeLists.txt index ac5aa2d71c..436f31127a 100644 --- a/examples/bluetooth/hci/controller_hci_uart_esp32c3_and_esp32s3/main/CMakeLists.txt +++ b/examples/bluetooth/hci/controller_hci_uart_esp32c3_and_esp32s3/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "main.c" - PRIV_REQUIRES bt nvs_flash esp_driver_uart esp_driver_gpio + PRIV_REQUIRES bt nvs_flash esp_driver_uart esp_ringbuf INCLUDE_DIRS "") diff --git a/examples/bluetooth/hci/controller_hci_uart_esp32c3_and_esp32s3/main/main.c b/examples/bluetooth/hci/controller_hci_uart_esp32c3_and_esp32s3/main/main.c index d554d41413..4e171bc2d8 100644 --- a/examples/bluetooth/hci/controller_hci_uart_esp32c3_and_esp32s3/main/main.c +++ b/examples/bluetooth/hci/controller_hci_uart_esp32c3_and_esp32s3/main/main.c @@ -5,12 +5,10 @@ */ #include -#include "esp_private/periph_ctrl.h" // for enabling UHCI module, remove it after UHCI driver is released -#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/ringbuf.h" #include "driver/uart.h" -#include "soc/lldesc.h" -#include "esp_private/gdma.h" -#include "hal/uhci_ll.h" +#include "driver/uhci.h" #include "nvs_flash.h" #include "esp_bt.h" #include "esp_log.h" @@ -21,6 +19,9 @@ static const char *tag = "UHCI"; #define UART_RX_THRS (120) +#define UHCI_MAX_RX_BUFFER_SIZE (512) +#define UHCI_MAX_TX_BUFFER_SIZE (512) + #define GPIO_UART_TXD_OUT (4) #define GPIO_UART_RXD_IN (5) #define GPIO_UART_RTS_OUT (6) @@ -41,19 +42,21 @@ static void hci_uart_tl_finish_transfers(void); struct uart_txrxchannel { esp_bt_hci_tl_callback_t callback; void *arg; - lldesc_t link; + uint8_t *buf; + uint32_t size; }; struct uart_env_tag { struct uart_txrxchannel tx; struct uart_txrxchannel rx; + uhci_controller_handle_t uhci_handle; + SemaphoreHandle_t rx_process_sema; + RingbufHandle_t ringbufhandle; + volatile bool rx_eof; + uint8_t rx_data_buffer[UHCI_MAX_RX_BUFFER_SIZE]; }; -struct uart_env_tag uart_env; - -static uhci_dev_t *s_uhci_hw = &UHCI0; -static gdma_channel_handle_t s_rx_channel; -static gdma_channel_handle_t s_tx_channel; +static struct uart_env_tag uart_env = {0}; static esp_bt_hci_tl_t s_hci_uart_tl_funcs = { ._magic = ESP_BT_HCI_TL_MAGIC_VALUE, @@ -82,16 +85,13 @@ static IRAM_ATTR void hci_uart_tl_recv_async(uint8_t *buf, uint32_t size, esp_bt assert(buf != NULL); assert(size != 0); assert(callback != NULL); + uart_env.rx.callback = callback; uart_env.rx.arg = arg; + uart_env.rx.size = size; + uart_env.rx.buf = buf; - memset(&uart_env.rx.link, 0, sizeof(lldesc_t)); - uart_env.rx.link.buf = buf; - uart_env.rx.link.size = size; - - s_uhci_hw->pkt_thres.thrs = size; - - gdma_start(s_rx_channel, (intptr_t)(&uart_env.rx.link)); + xSemaphoreGive(uart_env.rx_process_sema); } static IRAM_ATTR void hci_uart_tl_send_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg) @@ -102,13 +102,11 @@ static IRAM_ATTR void hci_uart_tl_send_async(uint8_t *buf, uint32_t size, esp_bt uart_env.tx.callback = callback; uart_env.tx.arg = arg; + uart_env.tx.size = size; - memset(&uart_env.tx.link, 0, sizeof(lldesc_t)); - uart_env.tx.link.length = size; - uart_env.tx.link.buf = buf; - uart_env.tx.link.eof = 1; - - gdma_start(s_tx_channel, (intptr_t)(&uart_env.tx.link)); + if (uhci_transmit(uart_env.uhci_handle, buf, size) != ESP_OK) { + assert(0); + } } static void hci_uart_tl_flow_on(void) @@ -124,36 +122,18 @@ static void hci_uart_tl_finish_transfers(void) { } -static IRAM_ATTR bool hci_uart_tl_rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) +static IRAM_ATTR bool uhci_tx_done_cb(uhci_controller_handle_t uhci_ctrl, + const uhci_tx_done_event_data_t *edata, void *user_ctx) { - assert(dma_chan == s_rx_channel); - assert(uart_env.rx.callback != NULL); - esp_bt_hci_tl_callback_t callback = uart_env.rx.callback; - void *arg = uart_env.rx.arg; - - // clear callback pointer - uart_env.rx.callback = NULL; - uart_env.rx.arg = NULL; - - // call handler - callback(arg, ESP_BT_HCI_TL_STATUS_OK); - - // send notification to Bluetooth Controller task - esp_bt_h4tl_eif_io_event_notify(1); - - return true; -} - -static IRAM_ATTR bool hci_uart_tl_tx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) -{ - assert(dma_chan == s_tx_channel); assert(uart_env.tx.callback != NULL); + assert(uart_env.tx.size == edata->sent_size); esp_bt_hci_tl_callback_t callback = uart_env.tx.callback; void *arg = uart_env.tx.arg; // clear callback pointer uart_env.tx.callback = NULL; uart_env.tx.arg = NULL; + uart_env.tx.size = 0; // call handler callback(arg, ESP_BT_HCI_TL_STATUS_OK); @@ -164,39 +144,71 @@ static IRAM_ATTR bool hci_uart_tl_tx_eof_callback(gdma_channel_handle_t dma_chan return true; } -static void uart_gpio_set(void) +static IRAM_ATTR bool uhci_rx_event_cb(uhci_controller_handle_t uhci_ctrl, const uhci_rx_event_data_t *edata, void *user_ctx) { - gpio_config_t io_output_conf = { - .intr_type = GPIO_INTR_DISABLE, //disable interrupt - .mode = GPIO_MODE_OUTPUT, // output mode - .pin_bit_mask = GPIO_OUTPUT_PIN_SEL, // bit mask of the output pins - .pull_down_en = GPIO_PULLDOWN_DISABLE, // disable pull-down mode - .pull_up_en = GPIO_PULLUP_DISABLE, // disable pull-up mode - }; - gpio_config(&io_output_conf); + BaseType_t done = xRingbufferSendFromISR(uart_env.ringbufhandle, edata->data, edata->recv_size, 0); + if (!done) { + assert(0); + } + if (edata->flags.totally_received) { + uart_env.rx_eof = true; + } - gpio_config_t io_input_conf = { - .intr_type = GPIO_INTR_DISABLE, //disable interrupt - .mode = GPIO_MODE_INPUT, // input mode - .pin_bit_mask = GPIO_INPUT_PIN_SEL, // bit mask of the input pins - .pull_down_en = GPIO_PULLDOWN_DISABLE, // disable pull-down mode - .pull_up_en = GPIO_PULLUP_DISABLE, // disable pull-down mode - }; - gpio_config(&io_input_conf); - - uart_set_pin(UART_HCI_NUM, GPIO_UART_TXD_OUT, GPIO_UART_RXD_IN, GPIO_UART_RTS_OUT, GPIO_UART_CTS_IN); + return true; } +static void uhci_rx_done_process_task(void *arg) +{ + size_t item_size = 0; + uint8_t *data = NULL; + while (1) { + xSemaphoreTake(uart_env.rx_process_sema, portMAX_DELAY); + data = xRingbufferReceiveUpTo(uart_env.ringbufhandle, &item_size, portMAX_DELAY, uart_env.rx.size); + if (item_size != uart_env.rx.size) { + assert(0); + } + memcpy(uart_env.rx.buf, data, item_size); + vRingbufferReturnItem(uart_env.ringbufhandle, data); + + if (uart_env.rx_eof) { + uhci_receive(uart_env.uhci_handle, uart_env.rx_data_buffer, UHCI_MAX_RX_BUFFER_SIZE); + uart_env.rx_eof = false; + } + + assert(uart_env.rx.callback != NULL); + esp_bt_hci_tl_callback_t callback = uart_env.rx.callback; + void *arg = uart_env.rx.arg; + + // clear callback pointer + uart_env.rx.callback = NULL; + uart_env.rx.arg = NULL; + uart_env.rx.size = 0; + + // call handler + callback(arg, ESP_BT_HCI_TL_STATUS_OK); + + // send notification to Bluetooth Controller task + esp_bt_h4tl_eif_io_event_notify(1); + } +} + +static void uhci_rx_prepare(void) +{ + uhci_receive(uart_env.uhci_handle, uart_env.rx_data_buffer, UHCI_MAX_RX_BUFFER_SIZE); + + uart_env.ringbufhandle = xRingbufferCreate(UHCI_MAX_RX_BUFFER_SIZE * 4, RINGBUF_TYPE_BYTEBUF); + if (uart_env.ringbufhandle == NULL) { + ESP_LOGE(tag, "Ringbuffer create failed"); + return; + } + + uart_env.rx_process_sema = xSemaphoreCreateBinary(); + xTaskCreate(uhci_rx_done_process_task, "trigger controller task", 4096, NULL, 5, NULL); +} + + void uhci_uart_install(void) { - periph_module_enable(PERIPH_UHCI0_MODULE); - periph_module_reset(PERIPH_UHCI0_MODULE); - - periph_module_enable(PERIPH_UART1_MODULE); - periph_module_reset(PERIPH_UART1_MODULE); - - uart_gpio_set(); - // configure UART1 uart_config_t uart_config = { .baud_rate = CONFIG_EXAMPLE_HCI_UART_BAUDRATE, @@ -212,45 +224,27 @@ void uhci_uart_install(void) .source_clk = UART_SCLK_DEFAULT, }; ESP_ERROR_CHECK(uart_param_config(UART_HCI_NUM, &uart_config)); + ESP_ERROR_CHECK(uart_set_pin(UART_HCI_NUM, GPIO_UART_TXD_OUT, GPIO_UART_RXD_IN, GPIO_UART_RTS_OUT, GPIO_UART_CTS_IN)); - // install DMA driver - gdma_channel_alloc_config_t tx_channel_config = { - .flags.reserve_sibling = 1, - .direction = GDMA_CHANNEL_DIRECTION_TX, + uhci_controller_config_t uhci_cfg = { + .uart_port = UART_HCI_NUM, + .tx_trans_queue_depth = 1, + .max_receive_internal_mem = UHCI_MAX_RX_BUFFER_SIZE, + .max_transmit_size = UHCI_MAX_TX_BUFFER_SIZE, + .dma_burst_size = 32, + .rx_eof_flags.idle_eof = 1, }; - ESP_ERROR_CHECK(gdma_new_ahb_channel(&tx_channel_config, &s_tx_channel)); - gdma_channel_alloc_config_t rx_channel_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = s_tx_channel, + + ESP_ERROR_CHECK(uhci_new_controller(&uhci_cfg, &uart_env.uhci_handle)); + + uhci_event_callbacks_t uhci_cbs = { + .on_rx_trans_event = uhci_rx_event_cb, + .on_tx_trans_done = uhci_tx_done_cb, }; - ESP_ERROR_CHECK(gdma_new_ahb_channel(&rx_channel_config, &s_rx_channel)); - gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0)); - gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0)); + ESP_ERROR_CHECK(uhci_register_event_callbacks(uart_env.uhci_handle, &uhci_cbs, NULL)); - gdma_strategy_config_t strategy_config = { - .auto_update_desc = false, - .owner_check = false - }; - gdma_apply_strategy(s_tx_channel, &strategy_config); - gdma_apply_strategy(s_rx_channel, &strategy_config); - - gdma_rx_event_callbacks_t rx_cbs = { - .on_recv_eof = hci_uart_tl_rx_eof_callback - }; - gdma_register_rx_event_callbacks(s_rx_channel, &rx_cbs, NULL); - - gdma_tx_event_callbacks_t tx_cbs = { - .on_trans_eof = hci_uart_tl_tx_eof_callback - }; - gdma_register_tx_event_callbacks(s_tx_channel, &tx_cbs, NULL); - - // configure UHCI - uhci_ll_init(s_uhci_hw); - uhci_ll_rx_set_eof_mode(s_uhci_hw, UHCI_RX_LEN_EOF); - // disable software flow control - s_uhci_hw->escape_conf.val = 0; - uhci_ll_attach_uart_port(s_uhci_hw, 1); + uhci_rx_prepare(); }