# ESP-Hosted Wi-Fi 协处理器使用指南

ESP-Hosted 驱动可以把 ESP32 系列芯片作为 K230/K230D 的 Wi-Fi 协处理器使用。K230 通过 SPI 与运行 ESP-Hosted-MCU 从机固件的 ESP 芯片通信，驱动向 RT-Thread WLAN 和 lwIP 注册 STA、SoftAP 两个网络接口。

当前移植基于 ESP-Hosted-MCU 2.12.x，支持 SPI Full-Duplex 和 SPI Half-Duplex 传输。Half-Duplex 使用硬件 Dual/Quad SPI，支持 2 或 4 条数据线，不支持 1 条数据线模式。已验证的全双工从机固件版本为 2.12.11。K230 侧不依赖 ESP-IDF，仅需要在 ESP 芯片侧编译和烧录 ESP-Hosted-MCU 从机固件。

## 功能范围

当前 RT-Smart 移植支持以下功能：

- STA 和 SoftAP 模式，以及 STA 与 SoftAP 并发
- 阻塞式 Wi-Fi 扫描
- STA 连接、断开和状态查询
- SoftAP 启动、停止和已连接终端查询
- SoftAP 主动断开指定终端
- RSSI、信道、MAC 地址和 Wi-Fi 省电配置
- RT-Thread 国家枚举与 ESP 两字符国家码转换
- 通过 lwIP 收发以太网帧
- Bluetooth H:4 控制器接口；CanMV 可使用 NimBLE 提供 BLE Central、Peripheral、GAP、GATT、L2CAP 和 SMP

当前不支持以下 ESP-Hosted 功能：

- SDIO 和 UART 传输
- Wi-Fi 混杂模式

RT-Smart 不重新实现 BLE 协议栈。内核只提供可复用的 H:4 HCI 设备层，ESP-Hosted、后续 USB Bluetooth 或其他控制器驱动均可注册到该层；GAP、GATT、ATT、L2CAP 和 SMP 使用经过验证的 NimBLE host stack。

## 硬件连接

SPI Full-Duplex 使用 D0/MOSI 和 D1/MISO，并额外使用 HS、DR 两个控制信号：

主机和 ESP 从机之间需要连接以下信号，并确保两块板共地、电平兼容：

| K230 主机信号 | ESP 从机信号 | 方向 |
| --- | --- | --- |
| SPI CLK | SPI CLK | K230 到 ESP |
| SPI D0/MOSI | SPI MOSI | K230 到 ESP |
| SPI D1/MISO | SPI MISO | ESP 到 K230 |
| CS | SPI CS | K230 到 ESP |
| HS | Handshake | ESP 到 K230 |
| DR | Data Ready | ESP 到 K230 |
| RESET | ESP EN 或从机复位 GPIO | K230 到 ESP |

SPI Half-Duplex 不使用 HS。D0、D1 在 Dual SPI 中双向传输；Quad SPI 还需要 D2、D3：

| K230 主机信号 | ESP 从机信号 | 方向 |
| --- | --- | --- |
| SPI CLK | SPI-HD CLK | K230 到 ESP |
| SPI D0-D1 | SPI-HD D0-D1 | 双向 |
| SPI D2-D3 | SPI-HD D2-D3 | 双向，仅 Quad SPI |
| CS | SPI-HD CS | K230 到 ESP |
| DR | Data Ready | ESP 到 K230 |
| RESET | ESP EN 或从机复位 GPIO | K230 到 ESP |

当前验证使用下面的 ESP32-C6 接线。RT-Smart 中除 RESET 外的引脚与 Kconfig 默认值一致；RESET 由默认的 `-1` 改为 GPIO 10，以便主机复位 ESP 从机并同步传输状态。实际引脚必须与 ESP-Hosted-MCU 从机工程的配置保持一致。

| RT-Smart 配置项 | K230 GPIO | ESP32-C6 GPIO | 信号 |
| --- | ---: | ---: | --- |
| `ESP_HOSTED_SPI_CS_PIN` | 14 | 18 | CS |
| `ESP_HOSTED_SPI_CLK_PIN` | 15 | 20 | CLK |
| `ESP_HOSTED_SPI_D0_PIN` | 16 | 14 | MOSI |
| `ESP_HOSTED_SPI_D1_PIN` | 17 | 15 | MISO |
| `ESP_HOSTED_HANDSHAKE_PIN` | 18 | 19 | HS |
| `ESP_HOSTED_DATA_READY_PIN` | 19 | 8 | DR |
| `ESP_HOSTED_RESET_PIN` | 10 | 9 | RESET |

```{warning}
K230 GPIO 编号不是开发板排针编号。接线前需要查阅所用开发板的原理图或引脚图，同时确认该 GPIO 支持所选 SPI 控制器的 FPIOA 功能。
```

## 配置 RT-Smart

先选择目标开发板的 defconfig，然后进入 RT-Smart menuconfig。例如：

```bash
make <board>_defconfig
make rtsmart-menuconfig
```

进入以下菜单：

```text
Drivers Configuration
    -> Ext Driver
        -> Enable ESP-Hosted Wi-Fi coprocessor
```

该选项依赖 RT-Thread SPI、K230 QSPI 驱动和 RT-Thread Wi-Fi 框架。ESP-Hosted 与 RW007、CYW43XX 和 Realtek Wi-Fi 驱动互斥，因为这些驱动会使用相同的 `sta` 和 `ap` 设备名。

### SPI 配置

先通过 `Transport` choice 选择传输协议：

| 菜单选项 | 用途 |
| --- | --- |
| `SPI full-duplex` | 标准 MOSI/MISO 全双工协议，使用 HS 和 DR |
| `SPI half-duplex` | ESP SPI-HD 协议，使用 2/4 条双向数据线和 DR |

SPI 总线通过 choice 菜单选择，控制器对应关系如下：

| 菜单选项 | RT-Thread 总线 | K230 控制器 |
| --- | --- | --- |
| `spi0 (OSPI controller)` | `spi0` | OSPI |
| `spi1 (QSPI0)` | `spi1` | QSPI0 |
| `spi2 (QSPI1)` | `spi2` | QSPI1 |

需要重点确认以下配置：

| 配置项 | 默认值 | 说明 |
| --- | ---: | --- |
| `ESP_HOSTED_SPI_DEVICE_NAME` | `esp-hosted` | SPI 设备名 |
| `ESP_HOSTED_SPI_MAX_HZ` | 5000000 | SPI 时钟，范围 1 MHz 到 40 MHz |
| `ESP_HOSTED_SPI_MODE` | Full-Duplex 为 3，Half-Duplex 为 0 | 必须与所选 ESP 从机传输配置一致 |
| `ESP_HOSTED_SPI_CS_PIN` | 14 | CS GPIO，`-1` 表示使用硬件 CS |
| `ESP_HOSTED_SPI_CLK_PIN` | 15 | CLK GPIO |
| `ESP_HOSTED_SPI_D0_PIN` | 16 | Full-Duplex MOSI 或 Half-Duplex D0 |
| `ESP_HOSTED_SPI_D1_PIN` | 17 | Full-Duplex MISO 或 Half-Duplex D1 |
| `ESP_HOSTED_CHECKSUM` | 开启 | 必须与从机校验和配置一致 |

建议先使用默认的 5 MHz 验证通信，再逐步提高频率。ESP32 的 SPI 频率上限为 10 MHz，其他受支持芯片通常可配置到 40 MHz，但最终稳定频率还取决于接线长度、信号质量和板级设计。

Half-Duplex 还需要选择最大总线宽度：

| 配置项 | 说明 |
| --- | --- |
| `ESP_HOSTED_SPI_HD_WIDTH_2` | 使用 D0、D1，启动和后续传输均为 Dual SPI |
| `ESP_HOSTED_SPI_HD_WIDTH_4` | 启动时先使用 D0、D1，能力协商成功后切换到 D0-D3 |
| `ESP_HOSTED_SPI_D2_PIN` | Quad SPI D2 GPIO，仅 4 线模式可见 |
| `ESP_HOSTED_SPI_D3_PIN` | Quad SPI D3 GPIO，仅 4 线模式可见 |
| `ESP_HOSTED_SPI_HD_POLL_INTERVAL_MS` | DR 为 `-1` 时读取从机状态的轮询间隔 |

选择 4 线模式时必须配置 D2、D3，并确认它们未与 DR、RESET 或其他外设冲突。K230 与从机都配置 4 线时，能力包之前的初始化仍按协议使用 2 线，之后才切换到 4 线。

### 控制信号配置

| 配置项 | 默认值 | 说明 |
| --- | ---: | --- |
| `ESP_HOSTED_HANDSHAKE_PIN` | 18 | Full-Duplex 必需的握手信号；Half-Duplex 不使用 |
| `ESP_HOSTED_HANDSHAKE_ACTIVE_LOW` | 关闭 | Full-Duplex HS 有效电平，默认高有效 |
| `ESP_HOSTED_DATA_READY_PIN` | 19 | 从机有数据待发送的通知信号；Full-Duplex 必需 |
| `ESP_HOSTED_DATA_READY_ACTIVE_LOW` | 关闭 | DR 有效电平，默认高有效 |
| `ESP_HOSTED_RESET_PIN` | -1 | ESP EN 或从机复位 GPIO |
| `ESP_HOSTED_RESET_ACTIVE_LOW` | 开启 | RESET 默认低有效 |

支持 `-1` 的引脚配置含义如下：

- CLK、D0、D1、D2 和 D3 为 `-1`：驱动保留开发板已有的 FPIOA 配置。
- CS 为 `-1`：使用 SPI 控制器硬件 CS；否则由 ESP-Hosted 驱动使用 GPIO 控制 CS。
- Half-Duplex 的 DR 为 `-1`：使用轮询方式检查从机状态寄存器。Full-Duplex 的 HS 和 DR 均不可禁用。
- RESET 为 `-1`：K230 不控制 ESP 复位。

SPI 传输协议要求主机与从机的计数器和传输状态在启动时同步。RESET 为 `-1` 时，应由外部硬件同时复位 K230 和 ESP；如果只重启其中一端，传输状态可能无法恢复。量产硬件建议连接 RESET 信号。

### 其他配置

通常可以保留以下默认值：

| 配置项 | 默认值 | 说明 |
| --- | ---: | --- |
| `ESP_HOSTED_RPC_TIMEOUT_MS` | 10000 | 控制命令超时时间，单位为毫秒 |
| `ESP_HOSTED_MAX_SCAN_RESULTS` | 20 | 单次扫描最多返回的 AP 数量 |
| `ESP_HOSTED_BLE` | 关闭 | 注册 ESP Bluetooth 控制器，并自动选择通用 `RT_USING_BT_HCI` 设备层 |
| `ESP_HOSTED_BT_HCI_DEVICE_NAME` | `hci0` | H:4 字符设备名，对应 `/dev/hci0` |
| `ESP_HOSTED_BT_HCI_RX_BUFFER_SIZE` | 8192 | 完整 HCI 事件和 ACL 数据包的接收缓存 |
| `ESP_HOSTED_THREAD_PRIORITY` | 8 | SPI 传输线程优先级 |
| `ESP_HOSTED_THREAD_STACK_SIZE` | 8192 | SPI 传输线程栈大小 |
| `ESP_HOSTED_EVENT_THREAD_STACK_SIZE` | 8192 | WLAN 事件线程栈大小 |

## 配置 ESP-Hosted-MCU 从机工程

在完整的 ESP-Hosted-MCU 工程配置步骤补充前，从机工程至少需要满足以下兼容要求：

1. 使用 ESP-Hosted-MCU 2.12.x 的 `slave` 示例。
1. 传输方式必须与 RT-Smart 的 `Transport` choice 一致。
1. Full-Duplex 的 SPI mode 与 `ESP_HOSTED_SPI_MODE` 一致，推荐先使用 mode 3。
1. Half-Duplex 的 mode 和数据线数量与 RT-Smart 一致，只选择 2 或 4 条数据线。
1. CLK、数据线、CS、控制信号和 RESET 引脚与 K230 接线一致。
1. HS、DR 和 RESET 的有效电平与 RT-Smart 配置一致。
1. 主从两端同时开启或同时关闭 SPI checksum。
1. 使用 BLE 时，从机启用 Bluetooth controller，并选择通过当前 SPI/SPI-HD transport 传输 HCI，而不是 HCI UART。

> 建议使能 RESET 引脚，使通信稳定。

ESP 从机启动日志应能显示实际使用的 SPI 模式和引脚，例如：

```text
SPI Ctrl:1 mode: 3, Freq:ConfigAtHost
GPIOs: CLK:20 MOSI:14 MISO:15 CS:18 HS:19 DR:8
Using GPIO [9] as slave reset pin
```

应以该日志中的实际值核对 K230 接线和 RT-Smart Kconfig，不能只参考 ESP 工程中的历史配置文件。

## 启动检查

驱动启动时会打印总线参数和完整引脚配置：

```text
[I/esp.hosted] SPI: bus=spi0 mode=3 freq=5000000 Hz full-duplex
[I/esp.hosted] GPIOs: CLK:15 MOSI:16 MISO:17 CS:14 HS:18 DR:19 RESET:10
[I/esp.hosted] waiting for transport handshake
```

通信成功后会出现类似日志：

```text
[I/esp.hosted] transport ready: SPI full-duplex, chip=0x0d firmware=2.12.11
```

Half-Duplex 启动时会先显示 2 线数据通路，在处理从机能力包后显示最终协商宽度：

```text
[I/esp.spi.hd] SPI-HD data path open: width=2 TX=1600 RX=1600
[I/esp.spi.hd] SPI-HD negotiated 4 data lines
[I/esp.hosted] transport ready: SPI half-duplex, chip=0x0d firmware=2.12.11
```

启用 `ESP_HOSTED_BLE` 且从机能力匹配时，还会出现：

```text
[I/esp.hci] Bluetooth HCI registered as hci0
[I/esp.hosted] BLE controller transport available (BLE-only)
```

此时 `ls /dev` 应包含 `hci0`。如果只出现 HCI 注册日志，却提示从机未发布 Bluetooth 能力，应检查 ESP-Hosted-MCU 的 Bluetooth 和 HCI transport 配置。

随后驱动向 RT-Thread WLAN 框架注册 STA 和 SoftAP 设备。执行 `ifconfig` 时应能看到：

- `w0`：STA 网络接口
- `w1`：SoftAP 网络接口

如果没有出现 `transport ready`，不要继续排查 lwIP 或 Wi-Fi 命令，应先检查 SPI 和控制信号。

## 功能验证

### STA 扫描和联网

执行扫描：

```shell
wifi scan
```

连接 AP：

```shell
wifi join <SSID> <password>
```

连接成功并通过 DHCP 获取地址后，检查状态和网络接口：

```shell
wifi status
ifconfig
ping <gateway_ip>
```

建议先 ping 局域网网关或同一局域网中的主机，避免把路由器无法访问公网误判为 ESP-Hosted 数据通路故障。

断开 STA：

```shell
wifi disc
```

### SoftAP

启动 SoftAP：

```shell
wifi ap <SSID> <password>
```

使用手机或电脑连接后查询已连接终端：

```shell
wifi list_sta
ifconfig
```

CanMV 可以使用 `status("stations")` 获取终端 MAC，再调用 SoftAP 接口的 `disconnect()` 主动断开指定终端：

```python
stations = ap.status("stations")
if stations:
    ap.disconnect(tuple(stations[0]))
```

主动断开后，终端应从 `wifi list_sta` 的结果中消失。

停止 SoftAP：

```shell
wifi ap_stop
```

### STA 与 SoftAP 并发

先使用 `wifi join` 连接上游 AP，再使用 `wifi ap` 启动 SoftAP。执行 `ifconfig`，确认 `w0` 和 `w1` 都处于 `LINK_UP` 状态。

STA 与 SoftAP 同时工作只表示两个 Wi-Fi 接口都已建立，不代表系统会自动在两个接口之间启用 NAT 或路由转发。

### BLE

内核侧启用 `ESP_HOSTED_BLE` 后，可由任意 H:4 host stack 打开 `/dev/hci0`。CanMV 已接入 MicroPython 自带的 NimBLE，实现完整 BLE host 功能；在 SDK 顶层 menuconfig 中启用：

```text
CanMV Micropython Components Configurations
    -> Enable Bluetooth module (NimBLE over RT-Smart HCI)
```

`BLUETOOTH_HCI_DEVICE_PATH` 默认是 `/dev/hci0`，必须与 RT-Smart 的 `ESP_HOSTED_BT_HCI_DEVICE_NAME` 一致。NimBLE 是 MicroPython 的 git submodule，首次构建前需初始化：

```bash
git -C src/canmv/micropython submodule update --init lib/mynewt-nimble
```

打开 `/dev/hci0` 时，内核通过 ESP-Hosted `FeatureControl` RPC 初始化并使能 ESP 端 Bluetooth controller；关闭设备时先关闭再反初始化 controller，但不释放其内存，因此之后可以再次打开。ESP-Hosted-MCU 2.5.2 及以后版本默认不会自动启动 Bluetooth controller，这两个 RPC 步骤不能省略。

先验证控制器初始化和扫描：

```python
import bluetooth
import time

_IRQ_SCAN_RESULT = 5
_IRQ_SCAN_DONE = 6

def irq(event, data):
    if event == _IRQ_SCAN_RESULT:
        addr_type, addr, adv_type, rssi, adv_data = data
        print("scan", bytes(addr).hex(), rssi, bytes(adv_data))
    elif event == _IRQ_SCAN_DONE:
        print("scan done")

ble = bluetooth.BLE()
ble.active(True)
ble.irq(irq)
ble.gap_scan(5000, 30000, 30000)
time.sleep_ms(6000)
```

再验证 Peripheral 广播：

```python
payload = b"\x02\x01\x06\x0b\x09CanMV-K230"
ble.gap_advertise(500000, adv_data=payload)
```

手机 BLE 扫描工具应能发现 `CanMV-K230`。扫描验证 Observer/Central 数据通路，广播验证 Broadcaster/Peripheral 数据通路；之后可使用 MicroPython `examples/bluetooth` 中的 temperature peripheral/central 示例测试 GATT service discovery、读写和 notification。

Wi-Fi 和 HCI 共用 ESP transport，但使用独立优先级队列。RPC/control 优先级最高，HCI 次之，WLAN data 最后；WLAN flow-control 不会停止 HCI 命令和 ACL 数据。

### 吞吐量测试

如需使用 iperf，需要在 SDK 配置中启用：

```text
CONFIG_PKG_USING_NETUTILS=y
CONFIG_PKG_NETUTILS_IPERF=y
```

可使用局域网内的 PC 作为对端进行 TCP 或 UDP 测试：

```shell
iperf -c <PC_IP>
iperf -s
iperf -u -c <PC_IP>
iperf -u -s
```

## 常见问题

### 启动时长时间等待

Full-Duplex 先检查 HS、DR 和 RESET；Half-Duplex 先检查 DR、RESET、SPI mode 和数据线数量。未连接 ESP 从机时，驱动会在后台退避等待，不应阻塞系统启动；连接从机后必须出现 `transport ready` 才表示协议初始化完成。

### SPI 接收一直为 `0xff`

日志可能包含：

```text
SPI RX stuck at 0xff; check spi0 D1/MISO wiring and coprocessor power
```

这通常表示 MISO 悬空、接错、从机未上电，或者 ESP 从机没有驱动 MISO。重点检查 D1/MISO，不要把 K230 的 D0 和 D1 与 ESP 的 MOSI、MISO 反接。

### SPI 接收一直为 `0x00`

依次检查以下项目：

1. ESP 从机是否已运行 SPI Full-Duplex 固件。
1. SPI mode 是否与从机一致。
1. CS 是否接到从机配置的 CS GPIO，并在整个 1600 字节帧期间保持有效。
1. MISO 和共地是否连接可靠。
1. HS、DR 是否接反或有效电平配置错误。
1. 先把 SPI 频率降到 1 MHz 或 5 MHz，再排除信号质量问题。

### 可以扫描但不能连接

先重新执行 `wifi scan`，确认目标 SSID 仍在当前扫描结果中，再执行 `wifi join`。同时检查密码和 AP 的安全类型。驱动的扫描结果数量受 `ESP_HOSTED_MAX_SCAN_RESULTS` 限制，目标 AP 较弱时可适当提高该值。

### 已连接并获取 IP，但无法访问网络

先执行 `ping <gateway_ip>` 验证局域网数据通路。如果网关可达而域名不可用，再检查 DHCP 下发的 DNS；如果公网 IP 也不可达，应检查上游路由器的互联网连接，不要仅根据域名 ping 结果判断驱动故障。

### 主机单独重启后通信失败

这是 RESET 配置为 `-1` 时最常见的问题。SPI 传输状态不会因为 K230 单独重启而自动同步。连接 K230 GPIO 到 ESP EN/RESET，或者确保外部复位电路同时复位主机和从机。

## 代码位置

RT-Smart 端实现位于：

```text
src/rtsmart/rtsmart/kernel/bsp/maix3/drivers/extdrv/esp_hosted/
```

协议帧、收发队列和上层回调位于 transport 公共层，SPI Full-Duplex 与 SPI Half-Duplex 分别由独立后端实现。后续增加 SDIO 时应实现新的 transport 后端，不应把 SDIO 状态加入 WLAN/RPC 层。驱动目录中的 `README.md` 记录移植范围和实现约束；Kconfig 是 menuconfig 选项的最终依据。
