本文介紹 GPIO 中斷,包括中斷示例及其各種功能。這是上一篇文章的延續,該文章解釋了微控制器的并發和中斷的概念。
GPIO 外設有什么作用?
GPIO 外設能夠檢測(或“知道”)四件事:引腳上的值是 1 還是 0,以及該值是從 0 變為 1 還是從 1 變為 0。
這些對于檢測許多事件很有用。例如,如果我將簧片開關連接到門上,那么我在微控制器上的程序可以根據簧片開關所連接的引腳上的值變化來判斷門是剛剛打開還是剛剛關閉,如圖 1 所示。
圖 1.使用 GPIO 和簧片開關檢測門的狀態(打開或關閉)和狀態變化。
我將首先解釋假設一切都已正確配置,中斷是如何工作的,然后我們將查看需要正確配置以使中斷工作的各個部分。
外設中斷標志
讓我們假設與我們之前的示例類似,我們試圖檢測的事件是引腳值從 1 變為 0 時。在 GPIO 外設內部,將有一個硬件檢測到這種變化并指示這種變化已經發生將該引腳的所謂中斷標志設置為 1。
如圖 2 所示。
圖 2.檢測到應該產生中斷的事件后設置 GPIO 引腳中斷標志。
中斷控制器和中斷控制器標志
微控制器中有許多外圍設備,每個外圍設備都有自己的一組中斷。大多數微控制器都有一個硬件,通常稱為中斷控制器,它管理來自外設的所有中斷,決定運行哪個中斷,并中斷 CPU 以使其執行正確的 ISR。
通常,中斷控制器有一個可能的中斷列表以及它們相應的優先級。我們的 GPIO 外設在中斷控制器保留的列表中可能有一個或多個中斷。
例如,對于 CC2544,有一組 8 個引腳是 GPIO 的一部分,稱為 PORT0。每個引腳標記為 P0_0、P0_1,依此類推,直到 P0_7。雖然每個引腳都有自己的中斷標志,但中斷控制器對整個端口只有一個中斷,P0INT。每當設置GPIO 外設中的任何引腳標志時,也會設置整個端口的中斷控制器中的標志。
注意這里有兩個標志,一個是特定引腳的標志,它是 GPIO 外設的一部分,另一個是整個端口的中斷標志,它是中斷控制器的一部分。如圖 3 所示。
圖 3.檢測到應該產生中斷的事件后,在中斷控制器中設置 GPIO 引腳中斷標志和中斷標志。
向量表
許多微控制器使用所謂的中斷向量方法。在這種方法中,內存中有一個向量表,它為每個中斷列出了 CPU 必須為該特定中斷執行的 ISR 所在的地址。該地址通常稱為中斷向量。
例如,對于使用 8501 微控制器架構的 CC2544,PORT0 的中斷向量是內存地址 0x6B。當中斷控制器告訴 CPU 有來自特定向量的中斷時,CPU 會做一些記錄,然后開始從該中斷向量執行 ISR。這如圖 4 所示。
圖 4.在檢測到應該產生中斷的事件后,在設置 GPIO 引腳中斷標志和中斷控制器中的 GPIO 中斷標志后執行 GPIO 中斷向量的 ISR。
配置中斷行為
像 GPIO 這樣的外設通常讓您可以選擇配置哪些類型的事件會導致外設產生中斷。對于 GPIO,典型的選項是當值從 0 變為 1 時,當值從 1 變為 0 時,值的任何變化(即,0 到 1 或 1 到 0 但無所謂),或者當值保持為 1 或 0。
根據微控制器的不同,這可以針對每個引腳或端口上的所有引腳完成。ATmega328P 有兩個引腳,您可以在其中單獨更改。默認情況下,其他 GPIO 引腳會檢測引腳上的任何變化(0 到 1 或 1 到 0)。回想一下,在上一篇文章中,我們說明了中斷是如何工作的,我們假設引腳配置為僅檢測從 1 到 0 的變化。
此外,一些微控制器要求將感興趣的引腳配置為輸入,以便在事件發生時設置中斷標志(例如,CC2544)。其他人(例如,ATmega328P)將設置標志,無論引腳配置為輸出還是輸入。
中斷屏蔽
用于描述啟用和禁用中斷的常用術語是“屏蔽”。通常,可以在多個級別禁用中斷。CPU 可以啟用或禁用所有中斷,但通常有一些至關重要的中斷稱為不可屏蔽中斷,它們永遠不會被禁用。
禁用 CPU 中的所有中斷實際上會停止中斷控制器和 CPU 之間的通信。這意味著 GPIO 外設中的 pin 標志及其在控制器中的相應中斷標志將被設置;但是,CPU 不會得到中斷請求。這如圖 5 所示。
圖 5.在 CPU 級別全局禁用中斷。
可以屏蔽中斷的另一個級別是中斷控制器級別。在這里,我們可以啟用或禁用控制器內部的特定中斷。
中斷示例:CC2544
一個具體的例子會有所幫助。假設我們正在使用 CC2544,并且禁用了 PORT0。假設引腳 P0_3 更改了其值,以便在 GPIO 外設中設置其標志。PORT0 中斷標志也會在中斷控制器中設置,但中斷控制器會忽略該標志。
這與 CPU 禁用所有中斷不同,因為中斷控制器仍在與 CPU 通信。因此,例如,如果 PORT1 已啟用其中斷,并且引腳 P1_2 更改了其值,因此其標志在 GPIO 外設中設置,并且 PORT1 中斷標志也已設置,則中斷控制器將中斷 CPU 以處理該中斷。
中斷控制器忽略中斷向量標志的情況如圖 6 所示。
圖 6.中斷控制器級別的中斷屏蔽。
大多數微控制器還允許在外設級別屏蔽中斷。在這里,我們可以啟用或禁用 GPIO 外設中特定引腳的中斷。
在我遇到的所有微控制器中,當我們要查找的事件發生在 GPIO 外設中時,總是設置中斷標志,無論該引腳的中斷是啟用還是禁用。例如,如果引腳 P0_3 以我們正在尋找的方式更改其值,則其標志將在 GPIO 外設中設置。但是,GPIO 外設不會向中斷控制器發出警報,因此不會設置中斷控制器中的 PORT0 中斷標志,并且由于我們需要設置該標志才能中斷 CPU,因此不會發生中斷。這如圖 7 所示。
圖 7. GPIO 外設級別的中斷屏蔽
當一個中斷被屏蔽時,它仍然會被檢測到。CPU只是不響應它。如果中斷標志沒有被清除并且中斷被完全取消屏蔽,那么如果它滿足所有其他條件(除了屏蔽),CPU 就會響應它以執行它。已檢測到并等待 CPU 執行其 ISR 的中斷通常稱為待處理中斷。
圖 8 說明了中斷處于未決狀態,隨后又被取消屏蔽的情況。
圖 8. GPIO 級別的中斷屏蔽和取消屏蔽,假設中斷在中斷控制器和 CPU 級別取消屏蔽。
回顧一下,完全取消屏蔽中斷,以便在滿足中斷的所有其他條件時 CPU 可以響應它:
必須在外設中啟用中斷(如果適用)。
它在中斷控制器中的相應中斷也必須使能。
所有中斷必須由 CPU 啟用(即 CPU 和中斷控制器之間的通信必須啟用可屏蔽中斷)。
中斷優先級
有時會同時發生兩個或多個導致中斷的事件。發生這種情況時,中斷控制器需要一種機制來知道應該先執行哪個中斷等等,因為 CPU 一次只能處理一個中斷。中斷控制器通常提供一種稱為優先級的配置,允許用戶通過他們的代碼來指定哪些中斷是較高優先級,哪些是較低優先級。大多數還為每個中斷提供默認設置。
每當多個事件同時發生并導致多個中斷在中斷控制器處掛起時,中斷控制器就會選擇最高優先級的中斷供 CPU 處理。中斷可以中斷(或搶占)已經運行的中斷,因此如果 CPU 正在處理較低優先級的中斷,并且發生與較高優先級中斷相關的事件,控制器將中斷 CPU 以處理較高優先級的中斷,并且 CPU 將恢復處理完成后被搶占的低優先級中斷。圖 9 說明了中斷的優先級和搶占是如何工作的。
圖 9.假設只有兩個中斷的優先級中斷處理。
高優先級和低優先級中斷標志同時設置。CPU 在低優先級中斷之前執行高優先級中斷(因為當高優先級中斷完成時,它的標志仍處于掛起狀態)
在 CPU 開始處理低優先級中斷后,高優先級中斷標志被設置。高優先級中斷搶占低優先級中斷,CPU 執行高優先級中斷的 ISR 直到完成,然后恢復執行低優先級中斷的 ISR。請注意,CPU 會繼續執行低優先級中斷的 ISR,即使在執行高優先級中斷的 ISR 時它的標志仍未設置。這是因為在執行 ISR 之后,除非代碼干擾正常的中斷過程,否則 CPU 總是會恢復到它開始執行 ISR 之前的任何狀態。它返回的這個狀態可能是另一個 ISR。
較低優先級的中斷標志設置在較高優先級的中斷標志之后。由于較低優先級的中斷不能搶占較高優先級的中斷,CPU 在響應較低優先級的中斷之前執行較高優先級的中斷 ISR 直到完成。
檢查和清除中斷標志
前面我們看到,對于像 CC2544 這樣的一些微控制器,當 ISR 代碼開始執行時,我們只知道哪個端口導致了中斷,而不知道具體的引腳。例如,如果 P0_3 改變它的值,它的標志將在 GPIO 外設內部設置,但 CPU 只執行 ISR 以響應來自中斷控制器的 PORT0 中斷標志。檢查 ISR 中的 GPIO 外設中斷標志可以告訴我們哪個特定引腳產生了中斷,以便我們做出相應的響應。
由于中斷標志表明我們要查找的事件已經發生,所以只要設置了中斷標志,CPU每次有機會都會響應中斷。例如,假設 P0_3 只改變了一次狀態并導致其中斷標志被設置。如果我們不設置標志位,那么在 CPU 運行了與 PORT0 相關的 ISR 之后,它仍然會認為有一個新的中斷,所以它會再次運行 ISR。
為了避免這種情況,我們需要清除中斷標志。有時中斷標志在 CPU 開始運行 ISR 時會自動清除;其他時候你必須自己清除標志。微控制器的技術文檔會讓您知道是哪種情況。例如,CC2544 不會自動清除引腳中斷標志,但 ATmega328P 會。如果您必須自己清除中斷,這通常是您在 ISR 代碼中做的第一件事,通常是在確定哪個引腳中斷導致 ISR 被執行之后。
回顧:讓 GPIO 中斷工作
要將以上所有內容放在一起,為了使 GPIO 中斷與您的代碼一起工作,您必須:
編寫一個 ISR,在其中你
確保清除任何需要清除的標志
用所需的動作響應中斷
將 ISR 與正確的中斷向量相關聯
配置要觸發中斷的 GPIO 事件。可能的選項可能并非全部適用于您的特定微控制器,僅從 0 更改為 1、僅從 1 更改為 0、任何更改(0 到 1 或 1 到 0)、穩定為 1 或穩定為 0 。
為 GPIO 內的引腳啟用中斷。通常建議在啟用引腳中斷之前清除引腳的標志。
啟用中斷控制器內部的中斷。
確保 CPU 已啟用所有中斷。
-
微控制器
+關注
關注
48文章
7904瀏覽量
153688 -
中斷
+關注
關注
5文章
904瀏覽量
42517 -
GPIO
+關注
關注
16文章
1271瀏覽量
53562
發布評論請先 登錄
STM32 GPIO的外部中斷設計

嵌入式Linux的GPIO中斷

評論