關於WinCE的中斷處理,OAL中主要是實現了ISR部分,一般IST會在裝置驅動中實現。推薦一篇WinCE的中斷架構的文章,如下:
http://msdn.microsoft.com/zh-cn/library/ms836807.aspx
建議對WinCE中斷不瞭解的朋友,可以先看看這片文章。架構
這張圖想必很多人都見過,主要這張圖太經典了,所以還是貼出來嘮叨幾句,硬體中斷產生以後,會導致核心ISR的運行,然後由OAL中的ISR來處理相應的中斷,最後導致相對應的IST運行完成真正的中斷處理。所以在WinCE中,中斷處理由ISR和IST共同完成。ISR主要完成中斷源的確定,屏蔽該中斷並返回給核心相對應的系統中斷號,ISR應該盡量短小。IST則是完成真正的中斷處理,比如資料的傳輸和解析等。當然不是所有的中斷處理都需要ISR和IST,看需要,比如WinCE的系統Timer中斷就只需要ISR完成。
在OAL中支援中斷,需要實現以下幾個中斷處理函數:
1. BOOL OEMInterruptEnable(DWORD sysIntr, VOID* pData, DWORD dataSize)
sysIntr:要被使能的系統中斷號
pData:傳入的資料指標,該資料由InterruptInitialize函數傳入
dataSize:傳入資料的大小
該函數用於使能某一個硬體中斷。在裝置驅動調用InterruptInitialize來初始化一個中斷的時候,核心就會調用該函數來使能相應的硬體中斷。
2. VOID OEMInterruptDisable(DWORD sysIntr)
sysIntr:要被屏蔽的系統中斷號
該函數用於屏蔽一個硬體中斷。如果裝置驅動調用InterruptDisable函數,則該函數會被調用。
3. VOID OEMInterruptDone(DWORD sysIntr)
sysIntr:要被重新使能的系統中斷號
該函數標誌著一個中斷處理過程的完成。當裝置驅動調用InterruptDone函數的時候,該函數會被調用,重新使能相應的硬體中斷。
4. ULONG OEMInterruptHandler(ULONG ra)
ra:指令計數,在實際應用中,沒有太大意義
當硬體中斷產生的時候,該函數就會被調用完成ISR部分的中斷處理。一般會在該函數中讀取系統的中斷標記位,確定中斷源並返回相應的系統中斷號。
5. void OEMInterruptHandlerFIQ(void)
針對於ARM處理器,該函數用於處理快速中斷。
上面5個函數完成了中斷的相關處理。這裡要提到兩個概念:IRQ和SYSINTR。IRQ是指物理中斷或者叫硬體中斷,而SYSINTR指的是系統中斷,也有的地方稱為虛擬中斷或者邏輯中斷,我個人覺得還是叫系統中斷比較好。每一個IRQ會和一個系統中斷SYSINTR相對應,當硬體中斷產生時,ISR實際上是處理IRQ中斷,然後返回相應的系統中斷SYSINTR給核心,核心會根據相應的SYSINTR觸發相應的IST來完成中斷處理。
IRQ和SYSINTR之間的對應關係稱為映射,分為靜態映射和動態映射。靜態映射是指在系統編譯時間IRQ已經和SYSINTR相對應,一般通過OALIntrStaticTranslate函數來實現。而動態映射是指WinCE系統啟動後,動態關聯IRQ與SYSINTR,一般通過KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR…)來實現。
SYSINTR的類型在nkintr.h中定義,OEMInterruptHandler函數在處理完中斷以後,會返回不同類型的SYSINTR給核心,核心會根據傳回值進行下一步操作,分為以下幾種類型:
SYSINTR_NOP:表示不需要進行任何處理
SYSINTR_RESCHED:表示要進行一次系統調度
SYSINTR_CHAIN:表示不是該中斷源產生,在中斷鏈中尋找下一個中斷
SYSINTR_RTC_ALARM:表示RTC警示產生
SYSINTR_TIMING:用於ILTiming測試
SYSINTR_PROFILE:用於系統的profile
SYSINTR_FIRMWARE:用於使用者自訂系統中斷號,所有自訂的系統中斷號都應該基於該值進行累加加1,這些自訂的系統中斷號用於和IRQ一一對應。
在以前,如果要實現OAL中的中斷部分,我們需要自己建立一個IRQ表和一個SYSINTR表,然後實現前面提到的5個函數,還要實現一個InterruptInitialize的函數,該函數用於初始化中斷,會在OEMInit中被調用,就完事了。自從WinCE5.0以後,微軟提出了PQOAL架構,中斷的實現變得“曲折”了。要實現的函數如下:
1. BOOL OALIntrInit()
該函數為中斷初始化函數,會在OEMInit中被調用,用於初始化系統的中斷,以及完成一些中斷的靜態映射。
2. BOOL OALIntrRequestIrqs(DEVICE_LOCATION *pDevLoc, UINT32 *pCount, UINT32 *pIrqs)
pDevLoc:一個DEVICE_LOCATION結構指標,包含裝置資訊
pCount:作為輸入表示最大的IRQ數,作為輸出表示實際獲得的IRQ數
pIrqs:指向一個實際獲得的IRQ數組
該函數用於通過裝置的物理地址來得到IRQ資訊,一般用於匯流排裝置。
3. BOOL OALIntrEnableIrqs(UINT32 count, const UINT32 *pIrqs)
count:要使能多少個IRQ
pIrqs:要被使能的IRQ數組
該函數用於使能IRQ中斷,該函數會被OEMInterruptEnable函數調用。
4. VOID OALIntrDisableIrqs(UINT32 count, const UINT32 *pIrqs)
count:要禁用多少個IRQ
pIrqs:要被禁用的IRQ數組
該函數用于禁用IRQ中斷,該函數會被OEMInterruptDisable函數調用。
5. VOID OALIntrDoneIrqs(UINT32 count, const UINT32 *pIrqs)
count:要重新使能多少個IRQ
pIrqs:要被重新使能的IRQ數組
該函數用於重新使能IRQ中斷,會被OEMInterruptDone函數調用。
除了上述5個函數以外,還要實現的一個重要函數就是OEMInterruptHandler了,這個函數前面介紹過,這裡不說了。實際上在WinCE5.0以後,在/Platform/Common/Src/Common/INTR/Base目錄下有個“map.c”檔案,該檔案實現了中斷的相關介面函數,實現了中斷的動態/靜態映射,還完成了SYSINTR與IRQ之間的轉換,我們只需要實現對硬體中斷的操作和初始化就可以了。
最後還有幾個函數要說一下,如下:
BSPIntrInit:被OALIntrInit函數調用
BSPIntrEnableIrq:被OALIntrEnableIrqs函數調用
BSPIntrDisableIrq:被OALIntrDisableIrqs函數調用
BSPIntrDoneIrq:被OALIntrDoneIrqs函數調用
BSPIntrRequestIrqs:被OALIntrRequestIrqs函數調用
這些函數可以被稱為板級中斷處理函數,總感覺這些函數有點多餘,一般實現了OALIntrInit,OALIntrEnableIrqs,OALIntrDisableIrqs,OALIntrDoneIrqs和OALIntrRequestIrqs就可以了,但這是基於處理器級的實現,對於基於同一處理器的不同的板子可能中斷要做一些修改,這些修改就可以在BSPIntrInit,BSPIntrEnableIrq,BSPIntrDisableIrq,BSPIntrDoneIrq和BSPIntrRequestIrqs裡面完成。
在這裡,OAL中的中斷處理函數基本都介紹了。我想最好的理解方法就是看代碼了。一般在OAL中只是做一些開關中斷和清中斷標記位的操作,真正的資料處理交給IST去做。但有的時候,有些特殊裝置的中斷會很頻繁,IST來不及響應,解決辦法就是在ISR中將資料儲存在一塊記憶體中,然後根據需要,每隔多少個硬體中斷返回一次系統中斷,從而啟用IST將資料一次性讀走,這裡涉及一個問題就是在ISR和IST中共用資料,在config.bib中預留一塊共用記憶體就可以了。
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/nanjianhui/archive/2009/03/03/3953466.aspx