3、OHCI中断机制原理:中断类型(SOF、WDH、SF等)、中断使能寄存器、中断状态寄存器

OHCI(Open Host Controller Interface)规范定义了一套高效的中断机制,用于在USB主机控制器与驱动程序之间传递异步事件。理解中断类型、使能寄存器与状态寄存器的协同工作方式,是进行驱动调试与中断处理程序编写的基础。本节将深入剖析OHCI中断的核心原理。

3.1 OHCI中断类型与触发条件

OHCI主机控制器支持多种中断源,每种中断对应特定的USB总线事件或处理完成事件。驱动开发者必须能够区分这些中断类型,以便在中断服务例程(ISR)中做出正确的响应。

中断类型缩写触发条件典型用途
帧起始SOF每1ms(全速/低速)帧起始时刻时间基准同步、帧计数更新
写回完成WDHED(端点描述符)的完成码(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)   /* 过流条件 */

驱动初始化时,通常按以下顺序配置使能寄存器:

  1. 先清除所有中断状态(写HcInterruptStatus清除遗留事件)。
  2. 设置HcInterruptEnable,仅使能当前驱动需要处理的中断类型。
  3. 对于控制传输调试,必须使能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 0SO调度溢出已发生写1清除
Bit 1WDH至少一个ED完成码被写回写1清除
Bit 2SF帧起始事件已触发写1清除
Bit 3RD恢复事件被检测到写1清除
Bit 4UE不可恢复错误发生写1清除
Bit 5FNO帧号计数器溢出写1清除
Bit 6RHSC根集线器端口状态改变写1清除
Bit 7OC过流条件发生写1清除
常见陷阱:在ISR中读取中断状态寄存器后,必须立即写回相同的值以清除已处理的中断位。如果忘记清除,主机控制器将不会产生新的中断(电平触发模式下中断线保持有效),导致系统死锁。

3.4 中断处理流程与寄存器协同

下图展示了从中断触发到驱动响应的完整流程,重点标注了使能寄存器与状态寄存器的交互位置。

OHCI中断处理流程:使能寄存器与状态寄存器协同 USB事件发生 HcInterruptEnable 对应位=1? 是 HcInterruptStatus 对应位置1 CPU进入中断服务例程(ISR) 读取HcInterruptStatus,识别中断类型 写1清除状态位 → 处理对应事件(如WDH遍历HCCA) 关键规则 使能位=0时,状态位 不会置位,中断被屏蔽 状态位必须写1清除

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入口处打印中断状态寄存器的原始值(使用调试串口或日志缓冲区),这有助于快速定位是哪种中断类型导致的问题。同时,建议在清除状态位之前保存一份副本,用于后续分析。