首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

OHCI USB 主機架構:中斷處理程序深度解析

     編輯:關於C語言

在 OHCI(Open Host Controller Interface)架構下,判斷 USB 資料傳輸是否完成,必須透過中斷處理程序來實現。當 USB 主機設定好 HcControl 與 HcCommandStatus 暫存器啟動傳輸後,控制器(如 AM9200)會自動執行資料傳輸,並定期檢查 HcDoneHead 暫存器的內容,將其轉移至 HCCA 的 DoneHead,隨後產生中斷,觸發中斷服務程式(ISR)。

中斷處理核心邏輯

在中斷處理程序中,首要任務是讀取 HcInterruptStatus 暫存器,檢查 WDH(Writeback Done Head) 位元是否為 1,以確認是否有傳輸描述子(TD)處理完畢。其他中斷狀態位通常不需理會。一旦發現 TD 完成,還需進一步判斷該 TD 是否為當前傳輸命令的最後一個 TD;若是,則標記命令執行結束,通知上層程式進行後續處理。

程式碼實作範例

/**
 * OHCI 中斷處理程序
 */
void AT91F_UHP_Handler(void)
{
    unsigned int status;
    unsigned char idx;
    unsigned char cc;

    // 取得 HcInterruptStatus 暫存器內容
    status = ohciGetIntrStatus();

    // 檢查 WDH 位,判斷是否有 TD 傳輸完畢
    if ((status & OHCI_HC_INTR_WDH) != 0)
    {
        // 依據目前執行的命令類型,確定 TD 數量
        switch (usbCmdState.cmdType)
        {
            case USB_CMD_TYPE_BULK_WRITE:
            case USB_CMD_TYPE_BULK_READ:
                idx = 3;
                break;

            case USB_CMD_TYPE_CTRL_READ:
                idx = 2;
                break;

            case USB_CMD_TYPE_CTRL_WRITE:
                idx = 1;
                break;

            default:
                usbCmdState.state = USB_CMD_OVER;
                ohciClearIntrStatus();
                return;
        }

        // 取得目前完成之 TD 的 Complete Code 值
        cc = getTdCC(ohciGetHccaDoneHead());

        // 判斷目前完成的 TD 是否為命令的最後一個 TD
        if (ohciGetHccaDoneHead() == usbGetLastTdAddr(idx))
        {
            usbCmdState.cmdResult = cc;
            usbCmdState.state = USB_CMD_OVER;
        }
        else
        {
            // 目前 TD 非最後一個,但執行失敗,不會繼續處理 TD 列表
            if (cc)
            {
                usbCmdState.cmdResult = cc;
                usbCmdState.state = USB_CMD_OVER;
            }
            else
            {
                // 目前 TD 非最後一個,等待繼續處理
                usbCmdState.state++;
            }
        }
    }

    // 清除 HcInterruptStatus 暫存器,以便產生新的中斷
    ohciClearIntrStatus();
}

實作心得與替代方案探討

早期嘗試直接輪詢 ohciGetIntrStatus() 判斷傳輸完成,但實測無法正確取得 TD 處理完畢的資訊。經調試發現,因端點描述子(ED)可掛載多個 TD,AM9200 處理速度關係,可能產生一個或多個中斷。因此,在 ISR 中必須判斷「目前結束的 TD 是否為該命令的最後一個 TD」,才能確保整個 ED 佇列真正處理完畢。

誠然,這種「檢查最後一個 TD」的做法屬於權宜之計。原本期望控制器提供專門暫存器,在 ED 佇列處理完畢時主動通知,但翻閱規格書未果,只能採用此法。若讀者有更優雅的解法,歡迎交流指教。

本文出自 “rainman” 博客,請務必保留此出處:https://lancelot.blog.51cto.com/393579/261181

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved