3. 初始化阶段总览:UHCI初始化流程、关键寄存器配置、DMA准备步骤
UHCI 控制器的初始化是 USB 子系统正常工作的前提,也是后续 DMA 传输能够正确执行的基石。本节从整体流程出发,梳理初始化阶段的关键步骤、寄存器配置要点以及 DMA 引擎的准备条件,帮助你在实战中建立清晰的初始化全景图。
3.1 UHCI 初始化完整流程
UHCI 初始化遵循“主机控制器 → 根集线器 → 帧列表 → 传输描述符”的递进顺序。以下流程图展示了从系统上电到 DMA 就绪的完整路径:
3.2 关键寄存器配置详解
UHCI 初始化阶段涉及的核心寄存器集中在 I/O 空间基址偏移处。下表列出必须配置的寄存器及其功能:
| 偏移地址 | 寄存器名称 | 位宽 | 初始化值 | 关键位说明 |
|---|---|---|---|---|
| 0x00 | USBCMD | 16-bit | 0x0000 | Bit0=1 运行/停止;Bit1=1 全局复位;Bit2=1 全局挂起 |
| 0x02 | USBSTS | 16-bit | 0x0020 | Bit5 HCHalted 只读,指示控制器是否停止 |
| 0x04 | USBINTR | 16-bit | 0x0000 | 中断使能位,初始化阶段通常全部清零 |
| 0x06 | FRNUM | 16-bit | 0x0000 | 当前帧号,由硬件自动递增 |
| 0x08 | FLBASEADD | 32-bit | 对齐到 4KB | 帧列表基址,必须指向 4KB 对齐的物理内存 |
| 0x0C | SOFMOD | 8-bit | 0x40 | SOF 帧长度调整,典型值 0x40(64 个 bit time) |
| 0x10 | PORTSC1/2 | 16-bit | 0x0080 | Bit7 端口使能;Bit0 端口连接状态检测 |
初始化顺序要点:
- 先通过 USBCMD 的 Bit1 发起全局复位,等待 USBSTS 的 Bit5 变为 1(HCHalted)。
- 清除复位位后,设置 FLBASEADD 为帧列表的物理基址。
- 配置 SOFMOD 为 0x40,设定 1ms 帧周期。
- 最后设置 USBCMD 的 Bit0 为 1,启动控制器运行。
3.3 DMA 准备步骤
DMA 传输的准备工作在 UHCI 控制器进入运行状态后进行。核心任务包括帧列表初始化、传输描述符(TD)队列构建以及链表指针的正确链接。
3.3.1 帧列表初始化
帧列表是 1024 个 32 位指针的数组,每个指针指向一个 TD 或 QH。初始化时将所有帧列表项指向一个空的同步 TD(SKIP 位=1),表示该帧无传输任务。
// 帧列表初始化示例(C 伪代码)
#define FRAME_LIST_SIZE 1024
uint32_t *frame_list = (uint32_t *)FRAME_LIST_BASE;
for (int i = 0; i < FRAME_LIST_SIZE; i++) {
// 设置 Terminate 位(Bit0=1),表示链表结束
frame_list[i] = 0x00000001;
}
3.3.2 传输描述符(TD)结构准备
每个 TD 占用 32 字节,包含链接指针、控制状态、令牌和缓冲区指针。DMA 引擎通过 TD 链表遍历传输任务。以下表格列出 TD 各字段的偏移和用途:
| 偏移 | 字段 | 位宽 | 描述 |
|---|---|---|---|
| 0x00 | Link Pointer | 32-bit | 指向下一个 TD/QH,Bit0=0 表示 TD,Bit0=1 表示 QH |
| 0x04 | Control/Status | 32-bit | 包含完成状态、错误计数、SPD、IOC 等控制位 |
| 0x08 | Token | 32-bit | 包含端点号、设备地址、PID(IN/OUT/SETUP)和数据长度 |
| 0x0C | Buffer Pointer | 32-bit | 数据缓冲区物理地址,必须 4 字节对齐 |
3.3.3 链表构建与 DMA 启动
DMA 传输依赖链表结构。帧列表项指向第一个 TD,TD 的 Link Pointer 指向下一个 TD,形成单向链表。最后一个 TD 的 Link Pointer 必须设置 Terminate 位(Bit0=1)。
实战建议:在初始化阶段,建议预先分配 3~5 个 TD 作为测试链表,验证 DMA 引擎能否正确遍历。使用逻辑分析仪抓取 PCI 总线上的内存读取事务,确认帧列表和 TD 的物理地址是否正确。
3.4 初始化阶段常见问题与避坑
- 帧列表未 4KB 对齐:FLBASEADD 的低 12 位必须为 0,否则 DMA 引擎会读取错误的帧列表项。
- TD 缓冲区未对齐:Buffer Pointer 必须 4 字节对齐,否则 UHCI 会忽略低 2 位,导致数据错位。
- 遗漏 Terminate 位:链表末尾的 TD 必须设置 Bit0=1,否则 DMA 引擎会无限遍历非法内存地址。
- 未等待 HCHalted 确认:复位后立即配置寄存器可能导致写入无效,必须轮询 USBSTS 的 Bit5 确认控制器已停止。
关键警告:不要在 UHCI 运行状态下修改 FLBASEADD 或帧列表内容。必须先通过 USBCMD 停止控制器(Bit0=0),等待 HCHalted 置位后再修改,否则会导致 DMA 引擎读取不一致的帧列表,引发系统崩溃。
3.5 初始化状态检查清单
以下清单可用于初始化完成后的快速验证:
| 检查项 | 预期值 | 验证方法 |
|---|---|---|
| USBCMD 运行位 | Bit0=1 | 读取 USBCMD 寄存器 |
| USBSTS HCHalted | Bit5=0 | 读取 USBSTS 寄存器 |
| FLBASEADD 对齐 | 低 12 位为 0 | 检查物理地址 |
| 帧列表项 Terminate | Bit0=1 | 读取帧列表内存 |
| TD 链表完整性 | 末尾 Terminate | 遍历 TD 链表 |
| 端口使能状态 | PORTSC Bit7=1 | 读取 PORTSC 寄存器 |