3、OHCI中断机制原理:中断类型(SOF、WDH、SF等)、中断使能寄存器、中断状态寄存器
OHCI(Open Host Controller Interface)规范定义了一套高效的中断机制,用于在USB主机控制器与驱动程序之间传递异步事件。理解中断类型、使能寄存器与状态寄存器的协同工作方式,是进行驱动调试与中断处理程序编写的基础。本节将深入剖析OHCI中断的核心原理。
3.1 OHCI中断类型与触发条件
OHCI主机控制器支持多种中断源,每种中断对应特定的USB总线事件或处理完成事件。驱动开发者必须能够区分这些中断类型,以便在中断服务例程(ISR)中做出正确的响应。
| 中断类型 | 缩写 | 触发条件 | 典型用途 |
|---|---|---|---|
| 帧起始 | SOF | 每1ms(全速/低速)帧起始时刻 | 时间基准同步、帧计数更新 |
| 写回完成 | WDH | ED(端点描述符)的完成码(CC)被写回HCCA | 批量/中断传输完成通知 |
| 调度溢出 | SF | 主机控制器检测到帧调度表执行超时 | 调试调度逻辑错误、带宽不足 |
| 根集线器状态改变 | RHSC | 根集线器端口状态(连接/断开/使能)发生变化 | 设备热插拔检测 |
| 不可恢复错误 | UE | 主机控制器内部发生致命错误(如总线错误) | 错误恢复、重置控制器 |
| 主控制器挂起/恢复 | OC | 过流检测或挂起/恢复事件 | 电源管理 |
调试要点:在驱动开发初期,建议先屏蔽SOF中断(仅用于时间同步场景),优先处理WDH和RHSC中断。SOF中断频率极高(1kHz),若ISR处理不当会导致系统性能严重下降。
3.2 中断使能寄存器(HcInterruptEnable)
中断使能寄存器(HcInterruptEnable)是一个32位寄存器,每一位对应一种中断类型的使能控制。只有当某位被置1时,对应的中断事件才能被主机控制器传递到CPU。该寄存器支持按位写1使能(写0不影响其他位)。
/* HcInterruptEnable 寄存器位定义 (OHCI 规范) */
#define OHCI_INTR_SO (1 << 0) /* 调度溢出 */
#define OHCI_INTR_WDH (1 << 1) /* 写回完成 */
#define OHCI_INTR_SF (1 << 2) /* 帧起始 */
#define OHCI_INTR_RD (1 << 3) /* 恢复检测 */
#define OHCI_INTR_UE (1 << 4) /* 不可恢复错误 */
#define OHCI_INTR_FNO (1 << 5) /* 帧号溢出 */
#define OHCI_INTR_RHSC (1 << 6) /* 根集线器状态改变 */
#define OHCI_INTR_OC (1 << 7) /* 过流条件 */
驱动初始化时,通常按以下顺序配置使能寄存器:
- 先清除所有中断状态(写HcInterruptStatus清除遗留事件)。
- 设置HcInterruptEnable,仅使能当前驱动需要处理的中断类型。
- 对于控制传输调试,必须使能WDH,因为控制传输的完成依赖ED写回。
典型初始化代码片段:
/* 使能WDH、RHSC、UE中断,屏蔽SOF */
volatile uint32_t *enable_reg = (uint32_t *)(base + 0x10C);
*enable_reg = OHCI_INTR_WDH | OHCI_INTR_RHSC | OHCI_INTR_UE;
3.3 中断状态寄存器(HcInterruptStatus)
中断状态寄存器(HcInterruptStatus)反映当前哪些中断事件已经发生且等待处理。该寄存器是写1清除(Write-1-to-Clear)机制:读取获得当前挂起的中断位,写入1清除对应位,写入0无效。
| 位域 | 名称 | 读值含义 | 清除方式 |
|---|---|---|---|
| Bit 0 | SO | 调度溢出已发生 | 写1清除 |
| Bit 1 | WDH | 至少一个ED完成码被写回 | 写1清除 |
| Bit 2 | SF | 帧起始事件已触发 | 写1清除 |
| Bit 3 | RD | 恢复事件被检测到 | 写1清除 |
| Bit 4 | UE | 不可恢复错误发生 | 写1清除 |
| Bit 5 | FNO | 帧号计数器溢出 | 写1清除 |
| Bit 6 | RHSC | 根集线器端口状态改变 | 写1清除 |
| Bit 7 | OC | 过流条件发生 | 写1清除 |
常见陷阱:在ISR中读取中断状态寄存器后,必须立即写回相同的值以清除已处理的中断位。如果忘记清除,主机控制器将不会产生新的中断(电平触发模式下中断线保持有效),导致系统死锁。
3.4 中断处理流程与寄存器协同
下图展示了从中断触发到驱动响应的完整流程,重点标注了使能寄存器与状态寄存器的交互位置。
3.5 中断类型与控制传输的关联
在控制传输的驱动调试中,以下中断类型最为关键:
- WDH(写回完成):控制传输的每个阶段(Setup、Data、Status)完成后,对应的ED会被主机控制器写回完成码(CC)。ISR必须遍历HCCA中的完成队列,检查每个ED的CC值,判断传输成功或失败。
- SF(调度溢出):如果控制传输的ED调度时间过长,超过帧剩余时间,主机控制器会触发SF中断。这通常表明带宽分配不合理或ED链表配置错误。
- UE(不可恢复错误):控制传输过程中如果出现总线错误(如STALL握手未正确处理),可能导致UE中断。此时需要重置主机控制器或端点。
控制传输调试中的中断处理伪代码:
void ohci_isr(void) {
uint32_t status = hc_read(HcInterruptStatus);
/* 立即清除已读取的中断位 */
hc_write(HcInterruptStatus, status);
if (status & OHCI_INTR_WDH) {
/* 遍历HCCA完成队列,处理控制传输ED */
struct ed *done_head = hcca->done_head;
while (done_head) {
if (done_head->type == CONTROL_ED) {
analyze_control_transfer(done_head);
}
done_head = done_head->next_done;
}
}
if (status & OHCI_INTR_SF) {
/* 调度溢出:检查帧调度表 */
debug_schedule_overflow();
}
if (status & OHCI_INTR_UE) {
/* 不可恢复错误:执行恢复流程 */
recover_host_controller();
}
}
3.6 中断调试技巧与常见问题
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| ISR从未被触发 | 中断使能寄存器未配置;中断线未正确连接 | 读取HcInterruptEnable确认位已置1;检查中断控制器配置 |
| WDH中断频繁触发但无实际传输 | HCCA完成队列未及时清空;ED被重复加入完成链表 | 在ISR中清空done_head后检查是否仍有遗留ED |
| SF中断持续产生 | 帧调度表执行超时;ED链表形成环路 | 打印帧调度表内容,检查ED的NextED指针 |
| 中断状态位清除后立即再次置位 | 中断源条件未消除(如WDH对应ED未从完成队列移除) | 确保ISR中处理完所有完成ED后再清除状态位 |
调试建议:在开发阶段,可以在ISR入口处打印中断状态寄存器的原始值(使用调试串口或日志缓冲区),这有助于快速定位是哪种中断类型导致的问题。同时,建议在清除状态位之前保存一份副本,用于后续分析。