實戰技能分享,減小開關中斷對系統實時性的影響,提升系統響應速度

一、背景知識:

(1)中斷延遲:從中斷觸發到執行中斷服務程序的第一條指令這段時間就是中斷延遲時間。

對於Cortex-M內核芯片,典型的中斷延遲時間是12-16個時鐘週期

以Cortex-M3/M4內核爲例,中斷觸發後,執行時序效果如下,其中xPSR,PC,R0,R1,R2,R3,R12和LR是硬件自動入棧的:

 

 

(2)那麼問題來了,什麼是零中斷延遲:

零中斷延遲並不是說中斷延遲時間是0,而是中斷觸發後,延遲時間接近芯片特性的延遲時間。

這個裏面影響中斷延遲的關鍵就是開關中斷,關的時間越長,中斷延遲就越長,也是最影響系統實時性的。本帖就是針對這個問題,給大家提供一些實用的解決思路。



二、中斷延遲的影響:

  如果源碼裏面有較多的開關中斷,且關閉時間較長,會給系統帶來什麼問題呢?比如某個任務正在調用系統API函數,此時中斷正好也關閉了,如果有一個緊急的中斷事件被觸發,這個中斷就不能得到及時執行,必須等到中斷開啓纔可以得到執行,如果關中斷時間超過了緊急中斷能夠容忍的限度,危害是可想而知的。

正是基於此,中斷延遲時間也是衡量RTOS實時操作系統的一項重要指標。


三、實戰應用場景一:儘量不要使用全局開關中斷,使用局部中斷

(1)一些外設驅動中,如果僅需開關自己的中斷就能完成效果,建議僅開關自己,不要做全局中斷的開關。以我們的8個串口FIFO驅動爲例:

我們可以修改下,僅對相應串口做開關中斷,這就大大降低了開關中斷影響:

 

 

(2)使用__set_PRIMASK(操作PRIMASK寄存器)做全局開關中斷的地方,改用__set_BASEPRI(操作BASEPRI寄存器)

Basepri寄存器僅對指定優先級及其以下優先級中斷做開關處理,其它高於此優先級的中斷不受影響。

現在各種RTOS基本都是採用的BASEPRI做開發中斷,這樣可以讓一些需要高實時性的中斷完全不受RTOS內核中斷API影響。

如果我們自己的程序裏面想調用BASEPRI寄存器,可以採用如下方法:

宏定義MAX_PRIORITY爲0x10,表示調用函數TX_DISABLE關閉中斷的時候,僅關閉搶佔優先級1到15,搶佔優先級0未不關閉(NVIC的優先級分組爲4,STM32僅使用高4bit),大家可以根據自己的情況做修改調整。



四、實戰應用場景二:儘量不使用全局調度鎖,而使用調度閥值

當前ThreadX帶了這麼個功能,大家有需要,可以借鑑下,這種方式的優勢是我們可以僅關閉指定範圍內的任務調度,而不是一刀切關閉所有任務調度。

這種功能在實際項目中還是非常實用的。比如中斷裏面將掛起的高優先級任務加入到就緒列表了,退出中斷後,由於全局調度鎖的問題,無法得到執行。

 


五、實戰應用場景三:RTOS內核源碼帶的各種開關中斷

現在常用的RTOS內核源碼裏面都有各種開關中斷,僅僅這一項的存在就很難做的零延遲,所以各家都搞了一些解決方案

(1)uCOS-III早期源碼搞了箇中斷延遲提交功能:

從uCOS-III V3.07.XX已經將其刪除了,不過大家使用可以借鑑下。

 

 

(2)採用BASEPRI寄存器做開關中斷處理

也就是應用場景一里的用法,這種方式也有缺點,不受控的中斷服務程序裏面不能RTOS裏面的API。

像uCOS-II,uCOS-III,FreeRTOS和ThreadX都是採用的方式了。



(3) 零中斷延遲RTOS,典型代表是RTX4和RTX5

能實現主要得益於RTX充分發揮了M內核特性,缺點是RTX主要面向ARM自家內核芯片。

那麼問題來了,爲什麼可以做到零中斷延遲?

a、任務級API通過SVC軟中斷調用,這樣就無需做開關中斷操作了(這麼做的本意是爲了將RTX內核代碼和用戶應用層代碼隔離)
b、中斷級API最終實現都會整到ISR FIFO統一處理。
c、還有一個是需要互斥的地方使用CM內核指令 LDREX 和 STREX。

關於RTX,我們可以借鑑的是文件rtx_core_cm.h裏面提供了一批原子操作API,這樣就不需要開關中斷了, 支持MDK,IAR和GCC:

部分截圖:

 

六、實戰應用場景四:降低中斷服務程序執行時間

如果中斷服務程序執行時間過長,會影響影響低優先級中斷的執行,反過來還會影響任務的響應速度。

(1) 用戶自己的代碼比較好控制,在中斷裏面要執行的代碼,最好發送消息給任務,在任務裏面跑實際功能。像LwIP,RTX的各種中間和ThreadX的各種中間件底層驅動基本都是這種玩法。
(2) 一些C庫函數執行時間比較長,中斷裏面慎用,比如sprintf。
(3)中斷裏面最好也不要調用uint64_t類型變量,uint64_t除法執行時間賊長,如果帶硬件雙精度浮點,推薦使用硬件雙精度浮點,速度能差10倍出來,這差距太大了。

不過使用時注意雙精度浮點的精度,雙精度浮點不能覆蓋所有64bit整數,精度到15個小數位左右。

MATLAB:

比如整數9223372036854775807用雙精度浮點來表示。

下面是利用H7-TOOL的LUA小程序在H750上的硬件雙精度運行效果:

 



總結:

程序做的龐大且複雜時,建議中斷越少越好,中斷頻率越低越好,任務之間耦合度越低越好

1、很多地方,其實可以完全用不到中斷,中斷太多會大大增加程序的不可預測性,以及各種中斷優先級配置造成的奇葩問題     
    比如QSPI Flash字庫,圖庫存儲加載,如果用QSPI MDMA方式就必須整個中斷(因爲要查詢執行是否完畢),此時就可以上內存映射方式,簡單方便,一下子省去兩個中斷。

2、另外就是中斷不要搞得太頻繁,造成僅僅進出中斷時間就給系統增加很大的負擔。

3、使用了RTOS的話,任務之間的耦合問題也相當重要,能夠獨立的最好獨立,不要跟太任務有消息的管理,否則出了問題,後期維護非常辛苦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章