# 蓝牙驱动调试指南

- X5 EVB 开发板使用 RTL8852BS 模组，支持 Wi-Fi 和 Bluetooth 功能。
  - RTL8852BS 模组的 Wi-Fi 功能调试请参考 [Wi-Fi驱动调试指南](../driver_develop_guide/33-WIFI_Driver_Debug_Guide.html#wifi)。
  - 蓝牙模块接口为UART接口，支持的协议分为 H4/Three-wire(H5)。

## 概述

- 本章主要讲述 Bluetooth 的适配和使用方法，以 RealTek（瑞昱）系列的 UART Bluetooth RTL8852BS 为例。
- 主要内容包含: 原理图确认、内核配置、DTS 配置 和 Bluetooth 使用以及常见问题。

## RealTek RTL8852BS 移植

### 原理图确认

X5 RTL8852BS 的部分原理图如下：

![image-20250116-151157.png](_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20250116-151157.png)
![image-20250124-140849.png](_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20250124-140849.png)

RTL8852BS Bluetooth 模组工作的条件，需要硬件满足以下几个条件:

- 供电：模组有两路供电，其中 `VDD_3V3` 为主电源，`VDD_1V8` 为 IO 上拉电源。<br>
- 使能：要能正常工作，需要 `BT_REG_ON` 给高电平，目前硬件上电上拉为高电平，故设备树中不需要配置。<br>
- 时钟：40MHz 的时钟输入模组可以内部生成，不需要外部单独输入该信号。<br>
- 通信：模组 Bluetooth 的通信通过 UART ，其中 `UART_TXD` `UART_RXD` 为 UART 的 2 条数据线。<br>

<div class="note">
<strong> 注意：</strong> <br>
  1.EVB为了保持接口和功能多样性，Bluetooth的 UART 接口并没有接流控，产品设计时建议接流控，不接流控可能会导致音频传输过程中出现音频卡顿、音质下降等问题。<br>
</div>

### 内核配置

进入到 BSP 的`build`目录下，执行 `./xbuild.sh boot menuconfig` 进行内核功能配置。

#### 配置命令

执行 `./xbuild.sh boot menuconfig` 会启动一个基于文本的菜单界面。使用键盘上的方向键导航菜单。按 Enter 键进入子菜单或修改配置选项。完成配置后，选择`Save`菜单项来保存你的配置。

#### 配置选项

1.配置内核选项`CONFIG_BT=m`

![image-20250212-151758.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20250212-151758.png)

2.配置内核选项`CONFIG_CRYPTO_ECDH=y`

![image-20250212-151847.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20250212-151847.png)

3.配置内核选项`CONFIG_BT_HCIUART=m`

![image-20250212-151924.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20250212-151924.png)

4.配置内核选项`CONFIG_RFKILL=m`

![image-20250212-152004.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20250212-152004.png)

5.配置内核选项`BT_HCIUART_H4=y`

![image-20250212-152045.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20250212-152045.png)

### DTS 配置

#### 确认 DTS 配置

确认 RTL8852BS Bluetooth 使用的是哪一个 UART 控制器，方法如下:

1. 根据原理图连接和设备树`pinmux-func.dtsi`可知,管脚 `LSIO_SPI4_SCLK` 对应的管脚复用配置为 `pinctrl_uart5`。
    ```dts
	pinctrl_uart5: uart5grp {
		horizon,pins = <
			LSIO_SPI4_SCLK  LSIO_PINMUX_2 BIT_OFFSET0  MUX_ALT2 &pconf_drv_pu_ds2_1v8
			LSIO_SPI4_SSN   LSIO_PINMUX_2 BIT_OFFSET2  MUX_ALT2 &pconf_drv_pu_ds2_1v8
		>;
	};
    ```

2. 进一步查看 `x5.dtsi` 文件中 `pinctrl_uart5` 节点的配置，确认其使用的控制器为 `serial@341a0000`，标签为 `uart5`。

    ```dts
    uart5: serial@341a0000 {
        compatible = "snps,dw-apb-uart";
        status = "disabled";
        reg = <0x341a0000 0x10000>;
        reg-shift = <2>;
        clocks = <&hpsclks X5_LSIO_UART5_CLK>,
                <&hpsclks X5_LSIO_UART5_PCLK>;
        clock-names = "clk","apb_pclk";
        interrupt-parent = <&gic>;
        interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
        resets = <&socrst LSIO_UART5_RESET>;
        broken-auto-flow-control;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart5>;
        dw-uart,dma-cyclic;
    };
    ```

3. 想让控制器 `serial@341a0000` 正常工作，只需将板级 DTS 配置中引用 &uart5 标签，配置status = "okay";即可。
    ```dts
    &uart5 {
        status = "okay";
    };
    ```

### 编译烧录

- 保存配置后，需要重新编译`./mk_boot.sh`编译内核镜像，`fastboot.exe flash boot boot.img`烧录 boot.img 。
- 然后使用 adb 将 `hci_uart.ko`、`bluetooth.ko`、`btrtl.ko` 和 `rfkill.ko` 上传到文件系统，adb的使用请参考 [使用 adb](../../quick_start/connect_board.html#adb)。

### 驱动加载调试

#### 1. 确认管脚复用配置
  - 进入系统后，使用 `hb_gpioinfo` 命令检查原理图管脚 `LSIO_SPI4_SCLK` 和 `LSIO_SPI4_SSN` 的复用配置是否正确。
  - 确认结果显示为 `uart5grp` 功能，配置无误。

  - 以下是 `hb_gpioinfo` 命令的部分输出示例：
  ```bash
  gpiochip4 - 32 lines: @34120000.gpio: @379-410
      [Number]                [Mode]  [Status]  [GpioName]       [PinName]          [PinNum]   [PinFunc]
      line  0:        unnamed input                             LSIO_UART7_RX         379      lsio_gpio0_0
      line  1:        unnamed input                             LSIO_UART7_TX         380      lsio_gpio0_1
      ......
      line 28:        unnamed input                             LSIO_SPI4_SCLK        407      uart5grp
      line 29:        unnamed input                             LSIO_SPI4_SSN         408      uart5grp
  ```
#### 2. 加载驱动 

  - 使用 insmod 分别加载 RTL8852BS Bluetooth 所需的驱动。
    - 使用 `insmod rfkill.ko` 加载无线设备的管理模块。
    - 使用 `insmod bluetooth.ko` 加载蓝牙核心协议栈模块。
    - 使用 `insmod btrtl.ko` 加载 Realtek 蓝牙固件加载模块，用于初始化 Realtek 蓝牙芯片的固件。
    - 使用 `insmod hci_uart.ko` 加载 HCI UART 驱动模块，支持通过串口与蓝牙硬件通信。

### 初始化程序编译和固件配置

#### 程序编译

对于使用 UART 接口的蓝牙，Realtek 提供 rtk_hciattach 工具进行蓝牙控制器的初始化。

- 1.修改 Makefile 中的工具链 CROSS_COMPILE 指定 X5使用的工具链。

  ```diff
  git diff Makefile
  diff --git a/Makefile b/Makefile
  index 207f808..d24dcf6 100755
  --- a/Makefile
  +++ b/Makefile
  @@ -1,4 +1,5 @@
  CFLAGS := -Wall -g
  +CROSS_COMPILE := /opt/arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu//bin/aarch64-none-linux-gnu-
  ```

- 2.蓝牙模块初始化过程需要加载固件文件，对于 UART 接口的可在 rtb_fwc.c 中定义固件文件所在的目录。 默认路径如下：

  ```bash
  #define FIRMWARE_DIRECTORY "/lib/firmware/rtlbt/"
  #define BT_CONFIG_DIRECTORY "/lib/firmware/rtlbt/"
  ```

- 3.执行 make 编译后生成 `rtk_hciattach` 可执行程序。
- 4.将交叉编译生成的 `rtk_hciattach` 使用 adb 将上传到板端文件系统 `/usr/bin/`。
- 5.从厂商获取的蓝牙固件和配置 `rtl8852bs_config`、`rtl8852bs_fw` 使用 adb 将上传到板端文件系统 `/lib/firmware/rtlbt/`。

<div class="note">
<strong> 注意：</strong> <br>
  1.对于 Realtek 厂商的 UART 蓝牙，应使用 Realtek 提供的 rtk_hciattach 源码进行编译生成，避免使用 BlueZ 编译的 hciattach。<br>
</div>

## FCS960K 移植

### 原理图及编译烧录

- 参考[Wi-Fi 驱动调试指南](../driver_develop_guide/33-WIFI_Driver_Debug_Guide.html) 中FCS960K移植一节，了解原理图、内核配置、DT 配置 和 编译烧录等相关内容

### 初始化程序

FCS960K 蓝牙模块通过下面的指令完成注册：
```bash
hciattach -s 1500000 /dev/ttyS5 any 1500000 noflow
```
完整的初始化流程集成在`/etc/init.d/bt_init.sh`脚本中。

## Bluetooth 使用

### 状态确认

在运行前，先查看一下当前设备上以下文件是否都存在。

需要确认的初始化程序如下：

```bash
/usr/bin/rtk_hciattach
/usr/bin/startbt8852.sh
```

需要确认的固件配置如下：

```bash
/lib/firmware/rtlbt/rtl8852bs_config
/lib/firmware/rtlbt/rtl8852bs_fw
```

需要确认的BlueZ程序如下：

```bash
/usr/bin/dbus-daemon
/usr/bin/bluetoothctl
/usr/bin/hciattach
/usr/bin/hcitool
/bin/hciconfig
/usr/bin/hcitool
```

执行`cd /lib/modules/$(uname -r)`跳转到内核模块目录，确认驱动模块如下：

```bash
kernel/drivers/bluetooth/btrtl.ko
kernel/drivers/bluetooth/hci_uart.ko
kernel/net/rfkill/rfkill.ko
kernel/net/bluetooth/bluetooth.ko
```

### 初始化

- 执行 `startbt8852.sh` 可以完成蓝牙的初始化。
- 蓝牙初始化脚本内容如下：

```bash
cat startbt8852.sh
#!/bin/bash
rtk_hciattach -n -s 115200 ttyS5 rtk_h5 &
```

### 配对连接

以下步骤介绍如何通过 `bluetoothctl` 交互界面完成蓝牙设备的配对和连接。

#### 1. 进入蓝牙配置界面

- 执行 `bluetoothctl` 进入交互模式，系统将显示蓝牙控制器的 MAC 地址及其当前状态（通常为可配对状态）。
- 执行 `show` 命令查看蓝牙详细信息，重点关注 `powered` 和 `discoverable` 状态。

  ![image-20240520-134333.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20240520-134333.png)

#### 2. 启用蓝牙功能

- 执行 `power on` 命令启用蓝牙功能。

  ![image-20240520-134343.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20240520-134343.png)

#### 3. 设置蓝牙为可发现状态

- 执行 `discoverable on` 命令，使蓝牙设备可被附近设备发现。

  ![image-20240520-134348.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20240520-134348.png)

- 此时，使用手机或电脑扫描蓝牙设备，即可发现名为 **BlueZ 5.64** 的蓝牙设备。

  ![image-20240520-135529.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20240520-135529.png)

#### 4. 扫描附近蓝牙设备

- 执行 `scan on` 命令开启主动扫描，系统将周期性显示附近蓝牙设备。
- 执行 `scan off` 命令关闭扫描，并汇总显示已发现的设备。

  ![image-20240520-134399.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20240520-134399.png)

  ![image-20240520-134358.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20240520-134358.png)

#### 5. 配对其他蓝牙设备

然后就是和其他蓝牙的配对：

- 执行 `pair [targetMAC]` 命令启动配对，根据提示输入 `yes`，并在对端设备上确认配对。

  ![image-20240520-134403.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20240520-134403.png)

- 配对成功后，可执行 `trust [targetMAC]` 命令，使设备在下次连接时自动配对。

  ![image-20240520-134408.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20240520-134408.png)

#### 6. 测试蓝牙设备连接

- 使用 `l2ping` 命令测试蓝牙设备的网络连接。

  ![image-20240520-134412.png](./_static/_images/34-Bluetooth_Driver_Debug_Guide/image-20240520-134412.png)

### 总结

通过以上步骤，您已完成蓝牙设备的扫描、配对和连接测试。如需了解更多功能，请参考 [BlueZ 官网](https://www.bluez.org) 的官方文档。

## 常见问题

### 执行 `startbt8852.sh` 进行蓝牙初始化时失败

#### 1.驱动未加载导致的蓝牙初始化失败

- **现象**：蓝牙串行协议（HCI UART）在初始化时失败。

  ```bash
  Realtek Bluetooth ERROR: Can't set line discipline 22, Invalid argument
  Realtek Bluetooth ERROR: Can't initialize devicce 22, Invalid argument
  ```

- **分析**：没有加载驱动hci_uart驱动。
- **解决方法**：使用`modprobe hci_uart`加载驱动后，然后再执行 `startbt8852.sh` 进行蓝牙初始化。

#### 2.固件使用错误导致的蓝牙初始化失败

- **现象**：蓝牙设备在进行数据传输时出现了顺序错误或数据包丢失。

  ```bash
  Realtek Bluetooth :Enable host hw flow control
  Realtek Bluetooth :h5_hci_reset: Issue hci reset cmd
  Realtek Bluetooth ERROR: Out-of-order packet arrived, got(7)expected(0)
  Realtek Bluetooth ERROR: Out-of-order packet arrived, got(7)expected(0)
  ```

- **分析**：使用了开启蓝牙硬件流控的固件，但是硬件设计上没有接流控。
- **解决方法**：向厂商获取不开启流控的固件即可，然后再执行 `startbt8852.sh` 进行蓝牙初始化。

### 蓝牙默认名字及修改方法

- ubuntu 文件系统中使用的默认名字是 `ubuntu`，buildroot 文件系统中使用的默认的名字是 `BlueZ X.YZ`，X.YZ 对 BLUEZ的版本号。
- 修改蓝牙默认名字时修改配置文件`/etc/bluetooth/main.conf`中的 [General] 对应的Name字段即可。

  ```bash
  [General]
  Name = hobot
  ```
