中斷處理是電腦系統的核心機制,允許硬體或軟體打斷 CPU 的正常執行流程,轉而處理緊急事件。理解中斷的運作原理對於嵌入式系統開發至關重要。本文從硬體層面出發,逐步解析中斷請求如何觸發、CPU 如何儲存當前執行狀態(上下文)、如何根據中斷向量表找到對應的中斷服務例程(ISR)並執行,以及最後如何還原到原來的執行狀態。除了基本流程,還會探討中斷優先順序的處理、中斷巢狀的機制、堆積疊在儲存上下文中的角色,以及系統延遲的影響。這些知識點將幫助開發者編寫更有效率、更穩定的中斷處理程式。
中斷的處理過程
中斷是電腦系統中的一種機制,允許硬體裝置或軟體程式暫時停止目前的執行流程,並轉而執行其他任務。這個過程涉及多個步驟,包括中斷請求、儲存上下文、尋找中斷服務例程(ISR)以及還原上下文。
中斷請求(IRQ)
當硬體裝置或軟體程式需要引發中斷時,會向處理器傳送中斷請求(IRQ)。這個請求會被處理器接收並處理。中斷請求可以由多種原因引發,例如按鍵按下、網路資料傳輸或計時器超時等。
儲存上下文
當處理器接收到中斷請求後,會立即儲存目前的執行上下文。這包括儲存目前的程式計數器(PC)、暫存器值等資訊。這樣做的目的是為了在中斷服務例程(ISR)執行完成後,可以還原到原來的執行狀態。
中斷服務例程(ISR)
處理器在儲存上下文後,會根據中斷請求找到對應的中斷服務例程(ISR)。ISR是一段專門用於處理中斷的程式碼,它會執行特定的任務以回應中斷請求。例如,當按鍵按下時,ISR可能會更新按鍵狀態或觸發其他動作。
還原上下文
在ISR執行完成後,處理器會還原原來的執行上下文。這包括還原原來的程式計數器(PC)、暫存器值等資訊。這樣做的目的是為了讓系統可以繼續執行原來的任務,而不會受到中斷的影響。
中斷優先順序
在某些情況下,可能會發生多個中斷請求同時到達處理器。在這種情況下,處理器需要根據中斷優先順序來決定哪個中斷請求先被處理。中斷優先順序可以根據硬體裝置或軟體程式的需求進行設定。
中斷巢狀
有些處理器允許中斷巢狀,也就是說,在一個中斷服務例程(ISR)正在執行時,可以接收另一個中斷請求並執行另一個ISR。這個功能可以提高系統的回應速度,但也可能增加系統的複雜度。
堆積疊和堆積
堆積疊(Stack)是一種資料結構,用於儲存資訊。堆積疊可以用於儲存函式呼叫的引數、區域性變數等資訊。在中斷處理過程中,堆積疊可以用於儲存原來的執行上下文,以便在ISR執行完成後還原原來的狀態。
堆積(Heap)是一種動態記憶體組態機制,用於儲存資料。堆積可以用於儲存動態組態的記憶體區塊,以便在程式執行過程中進行記憶體管理。
系統延遲
系統延遲(System Latency)是指從中斷事件發生到ISR開始執行的時間延遲。系統延遲包括處理器的中斷延遲和最大中斷停用時間。系統延遲越小,系統的回應速度越快。
中斷處理的第三步:從向量表中取出ISR
當中斷發生並儲存上下文後,處理中斷的第三步是根據向量表(IVT)確定要呼叫的ISR。這個表格位於處理器的特定記憶體區域。當中斷發生時,處理器會查詢這個表格以呼叫與中斷相關的函式。
向量表的初始化
啟動程式碼(可能隨編譯器或處理器廠商的HAL一起提供)會為您設定向量表,通常使用暫置的中斷處理器。在除錯時,您可能希望未處理的中斷進入無窮迴圈,以便您能夠找到它們並關閉中斷或正確地處理它們。但是當產品上市時,未處理的中斷處理器進入無窮迴圈將導致系統無回應。您可能希望未處理的中斷簡單地傳回到正常執行。這樣做浪費了處理器週期,仍然是一個錯誤,但至少對客戶的影響是一個輕微的速度減慢,而不是需要重新啟動的系統。
在某些情況下,如果您將處理器函式命名為與表中相同的名稱,一些工具的魔術將使聯結器使用您在IVT中的函式。然而,在其他處理器和編譯器中,您需要在中斷的正確插槽中手動將ISR插入函式表中。
查詢ISR
向量表位於記憶體中的特定地址,由玄貓設定。由於這通常是在啟動程式碼中為您完成的,因此您通常不需要知道如何做到這一點。然而,出於好奇,讓我們深入探討STM32F103xx的啟動程式碼:
__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) = {
// Core Level - CM3
&_estack, // 初始堆積疊指標
Reset_Handler, // 這是執行的開始
NMI_Handler, // 非遮罩故障處理器
...
TIM2_IRQHandler, // 28, TIM2 全域性中斷
TIM3_IRQHandler, // 29,
TIM4_IRQHandler, // 30,
};
內容解密:
上述程式碼定義了一個向量表,該表格包含了與每個中斷相關的函式指標。當中斷發生時,處理器會查詢這個表格以呼叫相應的ISR。這個過程是由玄貓自動完成的,但瞭解其背後的原理對於開發人員來說是非常重要的。
圖表翻譯:
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title 中斷處理機制與向量表應用
package "NumPy 陣列操作" {
package "陣列建立" {
component [ndarray] as arr
component [zeros/ones] as init
component [arange/linspace] as range
}
package "陣列操作" {
component [索引切片] as slice
component [形狀變換 reshape] as reshape
component [堆疊 stack/concat] as stack
component [廣播 broadcasting] as broadcast
}
package "數學運算" {
component [元素運算] as element
component [矩陣運算] as matrix
component [統計函數] as stats
component [線性代數] as linalg
}
}
arr --> slice : 存取元素
arr --> reshape : 改變形狀
arr --> broadcast : 自動擴展
arr --> element : +, -, *, /
arr --> matrix : dot, matmul
arr --> stats : mean, std, sum
arr --> linalg : inv, eig, svd
note right of broadcast
不同形狀陣列
自動對齊運算
end note
@enduml上述流程圖展示了中斷處理的過程。當中斷發生時,處理器會查詢向量表以呼叫相應的ISR。然後,ISR會被執行,最終傳回到正常執行。
中斷處理機制
中斷(Interrupt)是一種由硬體或軟體觸發的事件,需要CPU立即處理。中斷處理機制是指CPU如何回應和處理中斷的過程。
中斷號和中斷向量表
每個中斷都有一個唯一的中斷號(Interrupt Number),用於識別中斷的來源。中斷向量表(Vector Table)是一個儲存器中的表格,包含了每個中斷號對應的中斷處理程式(ISR)的地址。
當中斷發生時,CPU會將目前的執行狀態儲存起來,然後跳轉到中斷向量表中對應的ISR地址執行。ISR負責處理中斷事件,並在完成後傳回到原來的執行狀態。
可重入函式
可重入函式(Reentrant Function)是一種可以安全地多次呼叫而不會出現問題的函式。可重入函式必須滿足以下條件:
- 不使用靜態或全域變數
- 不呼叫非可重入函式
- 不使用分享資源
中斷服務程式(ISR)
ISR是指處理中斷事件的程式。ISR應該盡可能地短小精悍,以減少系統延遲。ISR不應該呼叫非可重入函式或使用分享資源。
設定和清除位元
在某些情況下,需要設定或清除位元以控制中斷的行為。這可以透過設定和清除位元的暫存器來實作。
多個中斷源
在某些系統中,可能存在多個中斷源。這需要在ISR中進行額外的檢查,以確定哪個中斷源引發了中斷事件。
關閉中斷
可以透過關閉中斷來防止中斷事件的發生。這可以透過設定特定的旗標或暫存器來實作。
臨界區
臨界區(Critical Section)是指一段需要 atomically 執行的程式碼,以防止其他中斷事件的幹擾。可以透過關閉中斷或使用鎖機制來保護臨界區。
關閉中斷的方法
有兩種方法可以關閉中斷:
- 使用
__disable_irq()和__enable_irq()宏 - 使用鎖機制
深入剖析中斷處理的底層機制後,可以發現從中斷請求、儲存上下文、查詢向量表到執行 ISR,整個流程環環相扣,確保系統能及時回應外部事件。多維度分析顯示,中斷優先順序和巢狀機制有效提升了系統的平行處理能力,但同時也增加了系統複雜度和除錯難度。技術限制深析指出,系統延遲、ISR 的執行效率以及堆積疊溢位等問題仍是中斷處理機制面臨的挑戰,尤其在實時性要求高的嵌入式系統中更需關注。從系統穩定性角度考量,ISR 應盡可能簡短高效,避免使用分享資源和非可重入函式,並妥善處理多個中斷源的競爭問題。玄貓認為,隨著硬體效能的提升和軟體設計的最佳化,中斷處理機制將在更精細的粒度上實作更靈活、更可靠的事件回應,進一步提升系統的實時效能和資源利用率。對於追求極致效能的系統,深入理解中斷處理機制並針對特定場景進行客製化最佳化至關重要。