4. HCI 接口调试:UART HCI、USB HCI、SDIO HCI、SPI HCI 的硬件连接与初始化
HCI(Host Controller Interface)是蓝牙主机与蓝牙控制器之间的标准通信接口。在实际嵌入式系统中,HCI 的物理层实现方式多种多样,常见的有 UART、USB、SDIO 和 SPI。不同的接口在硬件连接、初始化流程、调试手段上存在显著差异,理解这些差异是进行蓝牙驱动兼容性调试的基础。
4.1 四种 HCI 物理接口对比
| 接口类型 | 典型速率 | 引脚数 | 适用场景 | 调试难度 |
|---|---|---|---|---|
| UART HCI | 115200 bps ~ 4 Mbps | 4 (TX, RX, CTS, RTS) | 低功耗嵌入式、MCU 直连 | 中等(需检查波特率、流控) |
| USB HCI | 12 Mbps (Full Speed) / 480 Mbps (High Speed) | 4 (D+, D-, VBUS, GND) | PC、Linux 主机、高性能网关 | 低(标准 USB 枚举流程) |
| SDIO HCI | 25 MHz ~ 200 MHz 时钟 | 6~9 (CLK, CMD, DAT0~DAT3) | Wi-Fi/BT 组合芯片、移动平台 | 高(需配置 SDIO 时钟、中断) |
| SPI HCI | 1 MHz ~ 48 MHz | 4~6 (SCLK, MOSI, MISO, CS, IRQ) | 资源受限的 IoT 设备 | 高(需处理 SPI 片选与中断同步) |
4.2 硬件连接与初始化流程
4.2.1 UART HCI
UART HCI 是最常见的蓝牙 HCI 接口,广泛用于 CSR、TI CC256x、Realtek 等芯片。硬件连接通常采用 4 线制(TX、RX、CTS、RTS)硬件流控,部分低功耗场景可使用 2 线制(无流控)。
// UART HCI 初始化示例(Linux 内核驱动片段)
static int hci_uart_setup(struct hci_uart *hu)
{
struct uart_port *port = hu->serdev->uart_port;
int baudrate = 3000000; // 3 Mbps
// 1. 设置波特率
uart_update_timeout(port, port->state->port.uartclk / 16, baudrate);
// 2. 启用硬件流控
port->flags |= UPF_HARD_FLOW;
// 3. 发送 HCI 复位命令
hci_uart_send_cmd(hu, HCI_OP_RESET, NULL, 0);
// 4. 等待 HCI 命令完成事件
wait_for_completion(&hu->cmd_completion);
return 0;
}
4.2.2 USB HCI
USB HCI 通常用于 USB 蓝牙适配器。蓝牙芯片作为 USB 设备,通过标准 USB 枚举过程被主机识别。蓝牙类代码(bInterfaceClass = 0xE0)和协议(bInterfaceProtocol = 0x01)是识别关键。
// USB HCI 设备描述符示例(通过 lsusb -v 获取)
Bus 001 Device 003: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle
bDeviceClass 224 (Wireless)
bDeviceSubClass 1
bDeviceProtocol 1
bNumConfigurations 1
Interface Descriptor:
bInterfaceClass 224 (Wireless)
bInterfaceSubClass 1
bInterfaceProtocol 1 // Bluetooth Primary Controller
USB HCI 初始化由 USB 核心自动完成,驱动只需注册 usb_driver 并绑定到蓝牙接口。调试时重点关注 USB 枚举是否成功、端点描述符是否正确。
4.2.3 SDIO HCI
SDIO HCI 常见于博通(Broadcom)、联发科(MediaTek)等 Wi-Fi/BT 组合芯片。SDIO 接口需要配置时钟频率、总线宽度(1-bit 或 4-bit)以及功能号(Function 1 通常用于蓝牙)。
// SDIO HCI 初始化流程
1. 使能 SDIO 功能(sdio_claim_host / sdio_enable_func)
2. 设置块大小(sdio_set_block_size, 通常为 512 字节)
3. 配置时钟(默认 25 MHz,部分芯片需降频)
4. 读取芯片版本寄存器(确认通信正常)
5. 发送 HCI 厂商特定命令(如设置 BD_ADDR)
6. 注册中断处理函数(sdio_claim_irq)
mmc-utils 工具可以查看 SDIO 总线状态。
4.2.4 SPI HCI
SPI HCI 主要用于 Nordic nRF52、Dialog DA14531 等低功耗蓝牙 SoC。SPI 接口需要额外的 IRQ 引脚用于蓝牙芯片通知主机有数据可读。
// SPI HCI 数据包收发流程(伪代码)
// 主机发送 HCI 命令
spi_write(cmd_buffer, len);
// 等待 IRQ 引脚拉低(表示蓝牙芯片已处理)
while (gpio_get_value(irq_pin) == 1);
// 读取 HCI 事件
spi_read(event_buffer, expected_len);
4.3 HCI 命令/事件/数据包格式分析
HCI 数据包分为四种类型:命令(Command)、事件(Event)、异步数据(ACL Data)和同步数据(SCO Data)。每种类型都有固定的头部格式。
| 包类型 | 头部长度 | 关键字段 | 方向 |
|---|---|---|---|
| HCI Command | 3 字节 | OpCode (2B) + Parameter Total Length (1B) | Host → Controller |
| HCI Event | 2 字节 | Event Code (1B) + Parameter Total Length (1B) | Controller → Host |
| ACL Data | 4 字节 | Handle (2B) + Data Total Length (2B) | 双向 |
| SCO Data | 3 字节 | Handle (2B) + Data Total Length (1B) | 双向 |
// HCI 命令包示例:HCI_Reset (OpCode = 0x0C03)
// 原始字节流
0x01 0x03 0x0C 0x00
// 解析:
// 0x01 - HCI Command 包指示符
// 0x03 0x0C - OpCode (OGF=0x03, OCF=0x0C03 & 0x03FF = 0x0003)
// 0x00 - 参数长度(Reset 命令无参数)
// HCI 事件包示例:Command Complete Event (Event Code = 0x0E)
// 原始字节流
0x04 0x0E 0x04 0x01 0x03 0x0C 0x00
// 解析:
// 0x04 - HCI Event 包指示符
// 0x0E - Event Code (Command Complete)
// 0x04 - 参数长度
// 0x01 - Num HCI Command Packets(允许发送的命令数)
// 0x03 0x0C - Command OpCode (对应 HCI_Reset)
// 0x00 - Return Parameters (Status = Success)
4.4 HCI 调试工具实战
4.4.1 hcitool
hcitool 是 Linux 下最基础的蓝牙调试工具,用于发送 HCI 命令和查看控制器信息。
# 查看可用蓝牙接口
hcitool dev
# 发送 HCI 命令(例如读取本地版本信息)
hcitool cmd 0x04 0x0001
# 扫描周围蓝牙设备
hcitool scan
# 查看连接状态
hcitool con
4.4.2 btmon
btmon 是 Linux 蓝牙协议栈的监控工具,可以实时捕获并解析 HCI 数据包。
# 启动 btmon 监控所有 HCI 流量
btmon
# 输出示例(HCI 命令和事件逐行显示)
< HCI Command: LE Set Scan Parameters (0x08|0x000B) plen 7
Type: Passive (0x00)
Interval: 60.000 msec (0x0060)
Window: 30.000 msec (0x0030)
Own address type: Public (0x00)
Filter policy: Accept all (0x00)
> HCI Event: Command Complete (0x0E) plen 4
LE Set Scan Parameters (0x08|0x000B) ncmd 1
Status: Success (0x00)
4.4.3 Wireshark
Wireshark 配合 btmon 或 bt snoop 日志可以图形化分析 HCI 数据包。
# 生成 bt snoop 日志(适用于 Wireshark 导入)
btmon -w /tmp/bt_snoop.log
# 在 Wireshark 中打开日志文件
# 选择 "File" → "Open" → 选择 bt_snoop.log
# Wireshark 会自动识别蓝牙 HCI 协议并解析
1. 使用
hcitool dev 确认蓝牙接口已注册。2. 使用
btmon 实时观察 HCI 命令/事件交互,检查是否有命令超时或错误状态返回。3. 如果 btmon 无输出,说明 HCI 传输层可能存在问题,需检查物理接口(UART 波特率、USB 枚举、SDIO 时钟等)。
4. 使用 Wireshark 分析复杂场景下的 HCI 数据包时序,例如 LE 连接建立过程。