# USB 主机维护者注意事项（DWC_OTG 控制器）

[English]

ESP32-S3 使用 DesignWare USB 2.0 On-the-Go 控制器（后文简称为 DWC_OTG）作为其底层硬件控制器。启用分散/聚集式 DMA 功能后，DWC_OTG 将以主机模式运行。

备注

本节高度概括了 DWC_OTG 在主机模式下的操作。有关 DWC_OTG 的详细信息，请参阅 DWC_OTG 技术规格书和编程指南。

## 主机模式操作模型

下图展示了 DWC_OTG 在主机模式下的简化操作模型。该图包含了 DWC_OTG 主机模式下的一些关键概念及术语。

备注

详情请参阅技术规格书第 2.1.4 节（主机架构）。

### 主机端口

主机端口指的是 DWC_OTG 提供的单个 USB 端口（在 USB 术语中，也被视为总线根集线器的单个 USB 端口）。主机端口通常只能连接一个设备，但可以通过集线器连接更多设备。

主机端口具有以下功能：

- 检测直连设备的连接/断开情况。

- 检测直连设备的速度。

- 发送各种总线信号（如挂起、恢复、复位）。

### 主机通道

在主机模式下，DWC_OTG 使用通道与设备端点通信，每个通道会映射到特定的端点（在 USB 术语中，通道是管道的硬件表示）。例如，有个通道将映射到 EP 1 OUT。每个通道都有一组控制和状态寄存器 (CSR)，可以进行独立配置和控制，主要用于：

- 指定通道目标端点的详细信息（例如，设备地址、端点编号、传输类型、通道方向）。

- 启动通道传输（如设置 DMA 描述符）。

使用分散/聚集式 DMA 功能时，主机通道上的传输完全由事件驱动，用户只需填写恰当的 DMA 描述符，填充通道的 CSR，然后启用通道即可。传输完成后，通道将生成中断。

### 数据 FIFO

主机模式下，DWC_OTG 使用多个 FIFO 作为 USB 传输数据负载的暂存区。使用 DMA 时，DMA 引擎将在 TX/RX FIFO 和 ESP32-S3 的内部存储器之间复制数据：

- 对于 OUT 传输，数据负载将由 DMA 从主内存复制到某个 TX FIFO 中。MAC 层将按照 USB 数据包格式传输该数据负载。

- 对于 IN 传输，MAC 层会解析接收到的 USB 数据包，并将接收的数据负载存储在 RX FIFO 中。之后，由 DMA 将数据复制到主内存中。

目标 FIFO 由通道的方向和传输类型决定：

- 所有 IN 通道数据进入 RX FIFO。

- 所有非周期性（即控制和批量）OUT 通道数据进入非周期性 TX (NPTX) FIFO。

- 所有周期性（即中断和同步）OUT 通道数据进入周期性 TX (PTX) FIFO。

备注

非周期性和周期性 OUT 通道数据应分别进入 NPTX 和 PTX FIFO，因为中断和同步端点具有周期性特性（由端点的 `bInterval` 值指定）。DWC_OTG 会自动调度周期性传输，因此 PTX FIFO 能单独暂存这些周期性传输。

### DMA 引擎

DMA 引擎负责在 FIFO 和主内存之间复制数据。启用主机模式分散/聚集式 DMA 功能，无需软件干预，特定通道即可自动执行多个传输。下图展示了 DWC_OTG 主机模式分散/聚集式 DMA 内存结构。

- USB 传输由队列传输描述符 (QTD) 描述。每个 QTD 包含：

  - 一个 32 位的 buffer 状态四元组，用来指定有关传输的详细信息，且会在传输完成后报告传输状态。buffer 状态四元组可以指定 QTD 在传输完成后生成中断或是停止通道，也指定上述两种情况同时发生。

  - 一个 32 位指针，指向一个包含 OUT 传输数据负载的 buffer，或是指向一个空的 buffer，这个空 buffer 将用来存储 IN 传输的数据负载。

- 每个 QTD 的数据负载可以大于其目标端点的最大数据包大小 (MPS)。DWC_OTG 能够自动拆分传输。

- 多个 QTD 可以放入一个 QTD 列表中。通道将自动执行列表中的每个 QTD，并可设置是否要循环执行。

- 在通道开始传输数据之前，会为其配置 QTD 列表（以及 QTD 列表长度）。一旦启用通道，DWC_OTG 将自动开始 USB 传输。

- 在特定 QTD 或整个 QTD 列表结束任务后，通道将生成中断（可配置）。

备注

详情请参阅编程指南第 6.2.1 节（描述符内存结构）。

## 硬件配置

DWC_OTG IP 是可配置的。有关 ESP32-S3 的 DWC_OTG 的重要主机配置，请参阅下表：

ESP32-S3 的 DWC_OTG 配置
描述 | 配置
--- | ---
支持 OTG 的主机和设备模式 | `OTG_MODE = 0`
支持全速 (FS) 和低速 (LS) | `OTG_FSPHY_INTERFACE = 1`、`OTG_HSPHY_INTERFACE = 0`
支持分散/聚集式 DMA 功能的内部 DMA 控制器 | `OTG_ARCHITECTURE = 2`、 `OTG_EN_DESC_DMA = 1`
8 个主机模式通道 | `OTG_NUM_HOST_CHAN = 8`
支持包括 ISOC 和 INTR OUT 传输在内的所有传输类型 | `OTG_EN_PERIO_HOST = 1`
动态大小的 1024 字节（256 行）数据 FIFO | `OTG_DFIFO_DYNAMIC = 1`, `OTG_DFIFO_DEPTH = 256`

## 分散/聚集式 DMA 传输

主机通道传输的基本操作步骤如下：

1. 准备好数据 buffer、QTD 及 QTD 列表，确保有 QTD 能在完成任务后停止通道并生成中断。

2. 通过 CSR 设置通道和端点的特性（如 EP 地址、传输类型、EP MPS 等）。

3. 设置有关通道 QTD 列表的 CSR（如 QTD 列表指针和 QTD 列表长度）及通道中断 CSR。

4. 启用通道。硬件将使用 DMA 自动处理传输。

5. 在发生通道事件（如 QTD 完成任务或通道报错）时，通道将生成中断。

6. 解析通道中断，确定通道事件类型。

7. 解析 QTD，确定每个单独传输的结果。

若传输类型不同，在通道操作和 QTD 列表使用上也会有一些细微差别。

### 批量传输

批量传输最为简单。每个 QTD 代表特定方向的批量传输，DWC_OTG 会自动将特定 QTD 拆分为多个 MPS 大小的传输。因此，可以用多次批量传输填充一个 QTD 列表，并自动执行整个列表（即，只在最后一个 QTD 完成任务时发送中断）。

### 控制传输

控制传输是双向的，因而较为复杂（即，每个控制传输阶段可以有不同的方向）。每个阶段需要一个单独的 QTD，并且每个 QTD 必须在完成任务后停止传输通道，从而确保能通过重新配置通道的 CSR 来改变通道的方向。通常来说，控制传输需要 3 个 QTD（每个阶段一个）。

### 中断传输

根据 USB 2.0 规范，中断传输在端点指定的服务周期（即 `bInterval`）执行传输事务。特定中断端点在一个服务周期内不得执行多次中断传输。服务周期由微帧或帧的数量指定，因此特定中断端点通常每隔 N 个微帧或帧执行一次传输，直至完成传输。特定中断通道的服务周期（即 `bInterval`）由主机帧列表指定（详见编程指南第 6.5 节）。

备注

HS USB 允许一个中断端点在一个微帧内执行三次中断传输。详情请参阅 USB 2.0 规范第 5.7.3 节（中断传输数据包大小限制）。

总的来说，主机模式分散/聚集式 DMA 中的中断传输具有以下特点：

- 如果 QTD 数据负载大于端点的 MPS，通道会自动将传输拆分为多个 MPS 大小的传输事务（类似于批量传输）。但每次传输将在端点指定的服务周期内执行（即每个 `bInterval` 时间段内执行一次传输），直至完成传输。

- 对于中断 IN 传输，若收到短包（即传输的数据负载小于 MPS），则表明端点已无需要发送的数据，此时：

  - 即便 QTD 未设置 IOC（完成时中断）位，通道也会生成额外的通道中断。

  - 即使生成了额外的通道中断，通道也不会停止。

  - 软件必须使用这个额外的中断手动停止中断通道，从而取消 QTD 列表中剩余的 QTD。

备注

基于上述中断传输的特点，对于软件来说，为每次传输分配一个 QTD 可能比为整个传输分配一个 QTD 更加容易。

### 同步传输

根据 USB 2.0 规范，同步传输在端点指定的服务周期（即 `bInterval`）执行传输事务，以实现恒定的数据传输速率。特定同步端点在一个服务周期内不得执行多次中断传输。服务周期由微帧或帧的数量指定，因此特定同步端点通常每隔 N 个微帧或帧执行一次传输，直至完成传输。特定同步通道的服务周期（即 `bInterval`）由主机帧列表指定（详见编程指南第 6.5 节）。

但与中断传输不同，由于同步传输需要保持恒定的数据传输速率，即便传输失败（或收到 NAK），同步传输也不会重试，

备注

HS USB 允许一个同步端点在一个微帧内执行三次同步传输。详情请参阅 USB 2.0 规范第 5.6.3 节（同步传输数据包大小限制）。

总的来说，主机模式分散/聚集式 DMA 中的同步传输具有以下特点：

- 必须为每微帧或帧分配一个 QTD，但非服务周期的 QTD 应保持空白（即，如果通道的服务周期是每 N 个微帧或帧，则只需填充每第 N 个 QTD）。

- 每个已填充的 QTD 只能代表一次传输事务，而非整个传输过程。

- 同步传输不会在失败时重试，因此必须检查每个完成任务的 QTD 的状态。

## 补充说明

某些 DWC_OTG 行为在技术规格书或编程指南中均未提及。本节解释了一些与主机协议栈的实现相关的行为。

### 端口错误不会触发通道中断

一个或多个通道运行时，若发生端口错误（例如突然断连或端口过流），则：

- 通道仍可运行（即，保持设置 `HCCHAR.ChEna`）且不会生成通道中断。

- 理论上可以通过设置 `HCCHAR.ChDis` 来禁用通道，但这对同步通道无效，因为通道禁用中断未能生成。

因此，发生端口错误时，应使用控制器软复位以确保禁用所有通道。

### 端口复位中断

- DWC_OTG 在其端口上发出复位信号，如果设备在此期间断开连接，则断连中断（即 `HPRT.PrtConnDet`）不会在取消复位前生成。

- 在复位已经启用的端口（即 `HPRT.PrtEna`）时，如枚举期间的二次复位或是设备运行期间的复位，无论是在复位信号生效还是失效时，都会生成端口启用/禁用更改中断（即 `HPRT.PrtEnChng`）。

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。