| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-S3 | ESP32-S31 |
|---|
ESP-IDF UART HCI Controller
This example demonstrates how to run the Bluetooth controller with HCI over UART (H4), so the chip can be used as an external BLE/BTDM controller for a host on another device (PC or MCU).
HCI UART transport is initialized automatically in esp_bt_controller_init(). On ESP32 and ESP32-C3 / ESP32-S3, this is requested by the example through CONFIG_BTDM_CTRL_HCI_UART_INIT_BY_CONTROLLER and CONFIG_BT_CTRL_HCI_UART_INIT_BY_CONTROLLER in sdkconfig.defaults.<target>, since those targets also allow the application to own the HCI UART.
Example Default Configuration
Per-target defaults are in sdkconfig.defaults and sdkconfig.defaults.<target>:
| Target group | HCI UART TX pin | HCI UART RX pin | HCI UART RTS / CTS | HCI UART baud rate | HW flow control |
|---|---|---|---|---|---|
| ESP32 | 5 | 18 | 19 / 23 | 921600 | enabled |
| ESP32-C3 / ESP32-S3 | 4 | 5 | 6 / 7 | 115200 | enabled |
| ESP32-C2 / C5 / C6 / C61 / H2 / H21 | 8 | 9 | — | 115200 | disabled |
| ESP32-S31 / ESP32-H4 | 8 | 9 | — | 115200 | disabled |
UART0 is used for log output (IDF monitor). A second UART carries HCI traffic.
When using Bluetooth HCI UART with a third-party host stack, ensure Espressif Vendor-specific HCI commands are not enabled (disabled by default). See components/bt/include/$IDF_TARGET/include/esp_bt_vs.h.
How to Use the Example
Hardware Required
Connect the HCI UART to a USB-UART adapter or ESP-Test board on the host PC. Cross-connect data lines: device TX → host RX, device RX → host TX. On ESP32 / ESP32-C3 / ESP32-S3, also connect RTS/CTS when hardware flow control is enabled (default).
Configure the Project
idf.py set-target <target>
idf.py menuconfig
Build and Flash
idf.py -p PORT flash monitor
(To exit the serial monitor, type Ctrl-].)
Example Output
ESP32:
I (442) BTDM_INIT: HCI UART1 Pin select: TX 5, RX 18, CTS 23, RTS 19 Baudrate:921600
I (442) BTDM_INIT: BT controller compile version [...]
I (452) system_api: read default base MAC address from EFUSE
ESP32-C3 / ESP32-S3:
I (336) BT_HCI_UART: HCI messages can be communicated over UART1:
--PINs: TxD 4, RxD 5, RTS 6, CTS 7
--Baudrate: 115200
I (336) BLE_INIT: BT controller compile version [...]
I (406) system_api: read default base MAC address from EFUSE
ESP32-C2 / C5 / C6 / C61 / H2 / H21:
I (...) hci_driver_uart: set uart pin tx:8, rx:9.
I (...) hci_driver_uart: set baud_rate:115200.
I (...) hci_driver_uart: set flow_ctrl:0.
I (346) system_api: read default base MAC address from EFUSE
ESP32-S31 / H4:
I (537) hci_uart_config: set uart pin tx:8, rx:9.
I (537) hci_uart_config: set rts:-1, cts:-1.
I (537) hci_uart_config: set baud_rate:115200.
I (547) hci_uart_config: set flow_ctrl:0.
I (547) uart: ALREADY NULL
I (547) uart: queue free spaces: 1
I (557) hci_uart: hci transport task create successfully, prio:23, stack size: 1024
I (557) BTDM_INIT: BTDM controller init OK
After startup, HCI messages can be exchanged over the configured HCI UART.
Console Commands
The console REPL on the log UART is optional (CONFIG_ENABLE_HCI_CONSOLE, default off). The Bluetooth controller still runs without it. Extra command groups can be enabled separately.
| Group | Commands | Enabled by |
|---|---|---|
| Common (BLE and BR/EDR) | reconfig_hci_uart_pin -t <tx> -r <rx> |
CONFIG_ENABLE_HCI_CONSOLE |
| BLE DTM | set_ble_tx_power -i <index>, get_ble_tx_power, get_ble_rx_rssi |
CONFIG_ENABLE_BLE_DTM_CONFIGURATION_COMMAND |
The common group is available on every target whose HCI UART pins can be changed at runtime. The BLE DTM group targets direct test mode: on ESP32-C3/S3 enabling it also configures the HCI UART without hardware flow control, so only TX/RX have to be wired.
Troubleshooting
- Match UART baud rate on the host to the controller configuration (921600 for ESP32, 115200 for other targets in this example).
- On ESP32 / ESP32-C3 / ESP32-S3, connect RTS/CTS when hardware flow control is enabled.
- Do not enable Espressif VS HCI commands when using a third-party host stack.