您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關如何進行RT-Thread中斷管理,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
下面是關于RT-Thread中斷管理的學習總結,包括簡單地介紹了什么是中斷,裸機中斷與RT-Thread中斷有什么區別,RT-Thread是如何處理中斷的,RT-Thread內核提供哪些中斷相關的接口,等等。
從以下幾個方面總結一下RT-Thread中斷管理的學習過程
中斷相關的概念描述
什么是中斷?中斷,顧名思義就是一項正在進行的工作,突然間被其他事情打斷,導致原來正在進行的工作不能繼續正常進行,而需要去把其他事情處理完,才能回來繼續進行原來的工作。
如何通俗地理解中斷?想象一下這樣的場景,周末你正在家里愉快地寫著代碼,突然間你的手機鈴聲響了,你必須停下手里的工作,記錄代碼寫到哪個階段,然后就去接這個電話了。“寫代碼”就是正在進行的工作,“電話響起”就是中斷事件。
這個電話是媳婦打過來的,她讓你去菜市場買點韭菜和豬肉,晚上包餃子吃,媳婦的話哪敢不聽,于是你覺得菜市場買東西比較重要,掛掉電話后就去買東西了,買完東西回來后,再接著寫剛剛還沒完成的代碼。“菜市場買東西”就是中斷服務程序,這就是一個典型的中斷處理過程。
關于中斷的操作模式和特權級別,Cortex-M的處理器有三種狀態劃分,分別是:特權級處理模式,特權級線程模式,用戶級線程模式。這三種狀態的關系,如下圖所示。
從上圖可以看出,中斷或異常的服務程序,總是處于特權級處理模式的。而RT-Thread系統內核復位上電時啟動的主線程(main線程),是運行在特權級線程模式的。其他用戶創建的線程,是運行在用戶級線程模式的。
為什么處理器要區分特權級和用戶級?特權,顧名思義就是處理器如果工作在這個級別下,權限就會比較高,就可以訪問一些特殊的寄存器,以防止用戶級的代碼訪問這些特殊寄存器,對數據進行破壞。中斷由于其特殊性,所以,中斷函數是工作在特權級別下的。
裸機中斷與操作系統中斷兩者有什么區別呢?我們在裸機代碼中處理硬件中斷的時候,一般只要編寫中斷處理函數就可以了,這種方式處理中斷,簡單且直接。
然而,有了操作系統之后,所有的東西都變了,要考慮的問題就多了很多。因為操作里面運行了很多線程,中斷來了之后,就要告知操作系統,把當前運行線程的信息保存到棧里面,再去處理中斷服務程序,處理完中斷要再回去處理線程,此時又可能涉及到線程切換調度,而線程切換本身又需要PendSV中斷參與。
所以,在裸機處理中斷和在操作系統中處理中斷,簡直就是天壤之別。
RT-Thread 中斷處理機制
了解過Cortex-M系列單片機的工程師,一般都知道在芯片的匯編啟動文件startup_xxx.s里面,有一個中斷向量表,所有的中斷都是通過這個中斷向量表來進行處理的。
當一個中斷異常觸發的時候,處理器將會判斷是哪個中斷源,然后跳轉到固定位置進行處理,每個中斷服務程序的地址入口必須是放到統一的地址上,也就是需要設置到NVIC的中斷向量偏移寄存器里面。
其實,不管有沒有操作系統的參與,一旦硬件發送中斷和異常之后,中斷的入口都是在這個中斷向量表的。區別無非就是在裸機環境下,直接處理中斷服務程序,而在有操作系統的情況下,需要先保留線程的運行情況,然后再處理中斷,處理完中斷后,再恢復線程的運行環境。
硬件中斷的優先級是最高的,任何線程的優先級都要低于硬件中斷,因此,只要發生了硬件中斷事件,系統就必須要進行相應的處理。
RT-Thread在處理中斷的時候,一般都會有三個階段:中斷前導程序,中斷服務程序,中斷后續程序,這三個階段,如下圖所示。
中斷前導程序的主要工作是,當中斷事件發生的時候,處理器的硬件會把當前CPU相關的寄存器參數自動壓入中斷棧里面。程序需要調用rt_interrupt_enter()函數,把全局變量rt_interrupt_nest進行加1操作,這個全局變量是用來記錄中斷的嵌套層數的。
用戶中斷服務程序的主要工作分兩種情況,一種是不進行線程切換,另一種是進行線程切換。不進行線程切換的話,中斷服務程序和中斷后續程序運行完成后,將返回被中斷的線程。
而如果要進行線程切換,則會調用rt_hw_context_switch_interrupt() 函數進行上下文切換,這個函數主要是設置變量rt_interrupt_to_thread,然后觸發PendSV中斷。
在這里要注意一下:由于PendSV中斷的優先級最低,不能進行中斷搶占,因此即使觸發了該中斷,但由于此時還在用戶中斷處理函數里面,所以PendSV中斷還處于等待階段,只有退出了中斷后續程序,才會進行PendSV中斷處理,才會進行線程的上下文切換。所以,線程的上下文切換是不會在用戶中斷里面進行的,是在中斷結束后進行的。
中斷后續程序的主要工作是,通知系統內核離開中斷狀態,通過調用rt_interrupt_leave()函數,將全局變量rt_interrupt_nest進行減1操作,然后從中斷棧里面恢復恢復CPU相關的寄存器參數。
這里恢復CPU寄存器參數的時候需要注意,如果在用戶中斷里面涉及到線程切換,那么這個時候就需要恢復到新的線程CPU寄存器參數,而不是恢復到被中斷打斷的線程CPU寄存器參數。
RT-Thread操作系統在處理中斷的時候,通常采用“上半部分(Top Half)”和“底半部分(Bottom Half)”這種方式。原因在于,操作系統本身不會對中斷服務程序的處理時間做任何假設和限制,但為了保證系統的實時性,用戶需要保證中斷服務程序在盡可能短的時間內完成。
如何理解“上半部分(Top Half)”和“底半部分(Bottom Half)”這種中斷處理方式?還是以買菜為例。媳婦來電話讓你到菜市場買菜(中斷事件),但你考慮到如果長時間中斷不寫代碼,會導致思路斷鏈,為了避免這種情況(避免長時間處理中斷服務),完全可以在網上下單購買(短時間的中斷處理),生鮮超市收到下單信息(信號量、郵件、消息隊列),就會安排快遞小哥送貨上門,買菜這么耗時的工作就由其他人(其他線程)去完成了。
“上半部分(Top Half)”和“底半部分(Bottom Half)”這種中斷處理方式,主要是應用在一些需要耗時處理中斷事務的場合,比如數據的接收和處理。通常接收數據的時間比較短,只要把接收到的數據保存下來即可,但處理數據的過程就可能比較耗時,這樣就需要分開來處理,上半部分就是接收數據,底半部分就是耗時的數據處理。
RT-Thread中斷相關的API函數接口
為了把操作系統和硬件底層的中斷異常隔離開來,RT-Thread系統內核把中斷和異常封裝為一組抽象的接口,具體的函數接口如下圖所示。
RT-Thread中斷相關的應用示例
RT-Thread中斷相關的應用示例,主要是為了驗證中斷相關的API接口函數,例如全局中斷開關的使用示例,通過按鍵中斷示例來驗證“上半部分(Top Half)”和“底半部分(Bottom Half)”這種中斷處理方式。
全局中斷開關示例,主要是為了驗證多線程訪問同一個變量時,使用開關全局中斷的方式對該全局變量進行臨界區保護。
按鍵中斷示例主要是為了驗證“上半部分(Top Half)”和“底半部分(Bottom Half)”這種中斷處理方式。通過按鍵觸發中斷事件,在中斷服務函數里面發送郵件,通知線程進行相應的處理。
在irq_test.h頭文件里面,通過打開相應的宏定義開關,重新編譯工程源碼,下載到開發板即可驗證實驗現象,如下圖所示。
RT-Thread中斷應用的注意事項
中斷是一種異常,當系統發生中斷異常的時候就必須要進行處理,在RT-Thread實時操作系統里面處理中斷的時候,如果不及時處理或對中斷處理不當,輕則會造成系統出錯或邏輯混亂,重則會導致系統毀滅性地癱瘓。
在處理RT-Thread中斷異常的時候,有以下注意事項:
1.中斷服務程序工作在特權級處理模式,優先級比任何線程要高,任何線程都不能搶占中斷服務程序。
2.在操作系統里面,可以支持中斷嵌套,高優先級中斷可以搶占低優先級中斷,線程的重新調度是在所有中斷都處理完之后才重新啟動的。
3.在Cortex-M架構里面,中斷發生時CPU的寄存器入棧是由硬件自動完成的,中斷的前導程序通常只是記錄中斷的嵌套層數。
4.RT-Thread采用獨立的內存空間作為中斷棧,而不是采用線程棧作為中斷棧,這種方式隨著線程的增加,減少內存占用的效果也越明顯。
5.建議采用“上半部分(Top Half)”和“底半部分(Bottom Half)”這種方式來處理中斷異常,中斷服務程序的處理時間應盡可能短。
6.使用全局中斷開關是禁止多線程訪問臨界區最簡單的一種方式,這種方式可以應用在任何場合,但要注意這種方式對系統實時性影響巨大,使用不當會破壞系統的實時性能。使用全局中斷鎖的時間應盡可能短。
7.全局中斷開關支持多級中斷嵌套使用,每次調用rt_hw_interrupt_enable()函數,可以讓系統恢復到關中斷之前的狀態(這個狀態有可能是關中斷也有可能是開中斷)。
8.中斷服務程序是運行在特權處理模式下的,在這種運行模式里面是不能使用掛起當前線程操作的相關函數的,因為中斷服務程序的運行環境里面根本不存在線程。
以上就是如何進行RT-Thread中斷管理,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。