天天看點

學習FreeRTOS(3):兩種中斷學習FreeRTOS(3):兩種中斷

學習FreeRTOS(3):兩種中斷

典型情況下,程式進入臨界區将關閉所有中斷。FreeRTOS則提供了一種機制,在進入臨界區時僅關閉部分中斷,另一部分中斷可以繼續響應。這種機制讓系統享有多任務特性的同時保證極高的實時性。

http://blog.csdn.net/zoomdy/article/details/50659822

mingdu.zheng at gmail dot com

概述

FreeRTOS的選項configMAX_SYSCALL_INTERRUPT_PRIORITY把中斷根據優先級分成了兩種,一種是優先級低于或等于該選項的中斷,另一種是優先級高于該選項的中斷。當調用taskENTER_CRITICIAL進入臨界區時FreeRTOS僅關閉了優先級低于或等于該選項的中斷,而優先級高于該選項的中斷則仍然可以得到響應。不妨把前一種中斷稱之為臨界區相關中斷,把後一種中斷稱之為臨界區無關中斷。

高實時性

引入臨界區無關中斷機制後,系統獲得了更高的實時性能。臨界區無關中斷不會因為系統進入臨界區而被關閉,是以系統進入臨界區也可以零延時地響應關鍵事件中斷。系統層的代碼不會對臨界區無關中斷進行任何幹涉,該部分中斷的控制權完全掌握在應用層,應用層可以根據具體的需求使用或不使用臨界區無關中斷,可以根據具體算法和時機關閉或開啟臨界區無關中斷。通過嚴格控制臨界區無關中斷的關閉時間可以獲得系統能提供的最高實時性能。

限制

由于系統層代碼是使用臨界區作為共享資源保護的基本機制,而臨界區無關中斷是不受臨界區控制的,那麼在臨界區無關中斷中使用系統層API是不安全的,會導緻共享資源競争問題,會導緻資料破壞。是以臨界區無關中斷有一個限制,那就是其中斷服務例程不能調用任何系統API,即使是被标注為可以從中斷服務例程調用的API也不能被臨界區無關中斷服務例程調用。

共享資源保護

任務在處理與臨界區相關中斷之間的共享資源保護時非常簡單,隻要進入臨界區即可。而任務在處理與臨界區無關中斷的共享資源保護時除了進入臨界區外還要做一些額外的工作,即關閉臨界區無關中斷。之是以還要進入臨界區是因為需要避免中斷優先級反轉,如果僅僅關閉了高優先級的臨界區無關中斷,而沒有關閉低優先級的臨界區相關中斷,那麼在關閉臨界區無關中斷期間發生了臨界區相關中斷時,将轉而執行臨界區相關中斷,這導緻因為執行低優先級終端而使高優先級中斷的關中斷時間變長,也就是發生了中斷優先級反轉。

關中斷

這裡以Cortex-M架構的微控制器為例講一下如何關閉臨界區無關中斷。Cortex-M有兩個特殊功能寄存器可用來關閉或打開中斷,primask和basepri,将primask置1将屏蔽所有中斷(HardFault和NMI除外,這兩個算是異常不算中斷吧),将basepri設定為某個優先級,則可以屏蔽優先級低于或等于設定值的中斷。另外Cortex-M的NVIC也可以對單獨的中斷源進行屏蔽。

FreeRTOS的臨界區保護函數taskENTER_CRITICAL是設定basepri寄存器值為configMAX_SYSCALL_INTERRUPT_PRIORITY來實作的。也就是說隻是關閉了優先級低于或等于configMAX_SYSCALL_INTERRUPT_PRIORITY的中斷。也隻有使用basepri才能将中斷分成上述兩種。

// taskENTER_CRITICAL()
__asm volatile
    (
    "    mrs r0, basepri    \n"
    "    mov r1, %0         \n"
    "    msr basepri, r1    \n"
    "    bx lr              \n"
    :: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "r0", "r1"
);
           

關閉臨界區無關中斷的辦法有這麼幾種,一是設定primask為1,這将關閉所有中斷,包括所有臨界區相關中斷和臨界區無關中斷,這種方式最簡單,但是如有多個臨界區無關中斷并且其優先級不同,那這種方式是不太适用的,因為這種方式會使高優先級的中斷也被關閉。二是将basepri設定為要關閉中斷的優先級,這會關閉臨界區相關中斷的同時關閉所期望的臨界區無關中斷,而更高優先級的中斷仍然可以響應,這是最理想的方式。三是使用NVIC關閉單獨的中斷,在使用NVIC關閉臨界區無關中斷之前首先要調用臨界區函數taskENTER_CRITICAL關閉所有臨界區相關中斷,否則會引起嚴重的中斷優先級反轉。

需要注意的是,Cortex-M的中斷優先級以0為最高,以255為最低,數值和優先級是反的。

喚醒任務

臨界區無關中斷不能調用任何系統API,是以是不能直接喚醒任務的。不過辦法總是有的,仍然以Cortex-M架構的微控制器為例。Cortex-M除了可以由硬體産生中斷信号外,也可以由軟體來觸發中斷信号。可以将某一個空閑的中斷源與臨界區無關中斷配合使用。這個空閑的中斷源需要配置成臨界區相關中斷,即其中斷優先級應該小于等于configMAX_SYSCALL_INTERRUPT_PRIORITY,這樣才可以調用系統API喚醒任務。當臨界區無關中斷需要喚醒任務時,通過NVIC觸發與之配合的臨界區相關中斷,當退出臨界區無關中斷服務例程後就可以執行相配合的臨界區相關中斷服務例程來喚醒任務,這算是曲線救國嗎?

總結

如果使用FreeRTOS時,某些中斷響應時間不符合要求,或者實時性不達标,或者事件輸出抖動比較厲害,都可以使用FreeRTOS提供的這種機制提高系統性能,當然任何優化都是有代價,這種優化的代價是需要額外處理關中斷和喚醒任務等。當然,滿足系統需求才是最終目标。現在,我終于明白eCos為什麼使用basepri寄存器關中斷而不是使用primask,也是同樣的緣由啊。我也終于明白Cortex-M為什麼還會有basepri寄存器,沒有硬體的支援,軟體鬧翻天也不濟事吧。

繼續閱讀