天天看點

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

作者:楊為民

一、uC/OS-II原移植程式中斷的中斷嵌套保護方法問題

(1)“RTOS中斷嵌套保護問題”,是指如果在一個中斷尚未結束并且被中斷的任務的優先級較低的情況下,剛好優先級較高系統中斷發生中斷,就産生“中斷嵌套”,在系統中斷中如果又檢測到一個優先級更高的任務休眠到期了,那麼系統中斷将會退出中斷并把任務切換到新任務,CPU轉向到新任務程式去執行。

發生這種情況時先前的中斷現場(堆棧中的寄存器)留在被切換走的老任務中,餘下的中斷代碼也沒有執行,包括中斷傳回指令“RETI”也沒有沒有執行,這意味上一個被嵌套的中斷沒有退出。

如果這樣就會帶來兩個極危險的後果:一是如果老任務由于優先級低而遲遲得不到執行,這時第一個中斷的剩餘程式也就遲遲得不到執行,中斷遲遲不會退出,這将會阻塞優先級和它一樣以及比它低的所有中斷。二是如果第一個中斷正在執行不能被打斷的任務,比如正在與外界進行通訊,比如正在進行機電控制,這時會産生執行逾時等不可預料的故障。

避免這種危險的問題就稱為“RTOS中斷嵌套保護問題”。

(2)如果系統中斷采用不可屏蔽中斷,則其優先級最高,且不受EA和ET0的控制,它可以中斷其他任何中斷程式的執行,是以産生中斷嵌套的機會非常大,很容易産生RTOS中斷嵌套保護問題。

(3)RTOS中常見的解決中斷嵌套保護問題的方法是設定一個中斷嵌套計數變量,每次進入任何中斷時就将其加1,退出任何中斷時減1,這樣在系統中斷任務排程程式中讀取中斷嵌套計數變量就知道有沒有發生中斷嵌套,如果有,就不進行排程,等到下次系統中斷發生時再檢測和排程。

(4)筆者認為對于任何單片機RTOS采用中斷嵌套保護措施都是必要的,主流的單片機RTOS比如uC/OS-II、FreeRTOS和RT-Thread都采用了中斷嵌套保護措施,隻是方法不同而已。

(5)原移植uC/OS-II的中斷嵌套保護程式如下圖:

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

其中“OSIntNesting”是中斷嵌套計數變量,進入中斷時第639行将其加1,進行系統級任務排程時,第655行先将其減1,然後第657行判斷是否有中斷嵌套,如果沒有再進行第666行的任務排程,如果有就跳過第666行,不進行任務排程。

(6)不過移植的uC/OS-II的中斷嵌套保護程式存在隐患,它的中斷ISR程式如下圖:

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

1)每個中斷開始和結尾移植者都試圖用一對關閉中斷和打開中斷語句來避免中斷嵌套,但是這是沒有用的。一是在中斷過程中第415行系統時間Tick函數調用和第439行序列槽通訊中斷處理函數中都包括臨界區保護語句,這些語句中的退出保護語句“EA=1”等不到中斷ISR最後一行程式,提前就将總中斷打開了。二是系統中斷是不可屏蔽中斷模式,序列槽中斷中的第434行根本不能避免系統中斷的嵌入。

2)由于原中斷嵌入保護程式是用C語言寫的,是以在中斷ISR中,進入中斷語句第436行隻能寫在寄存器現場儲存語句第435行之後,退出中斷語句第442行隻能寫在寄存器現場恢複語句第443行前面。這就産生一個隐患,由于第435行和第443行時宏定義包含多條彙編指令,如果在這時發生系統中斷,則會産生中斷嵌套保護問題。

二、改造後uC/OS-II中斷嵌套的保護方法

(7)改變中斷嵌入計數變量的存儲類型。原移植程式的定義是:

OS_EXT INT8U OSIntNesting;

變量是XDATA類型的。

改造後的uC/OS-II中的定義是:

OS_EXT INT8U data uCx51_IntNesting;

變量是DATA類型的。

(8)取消中斷進入和退出函數,直接操作中斷嵌入計數變量。下圖是改造後的uC/OS-II的中斷ISR的程式:

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

其中在進入中斷後的第一行就使用“INC uCx51_IntNesting”指令将中斷嵌入計數加1,在退出中斷前的最後一行程式才使用“DEC uCx51_IntNesting”指令将中斷嵌入計數減1,這就避免了前面說的第二個隐患。由于這兩條指令均不會影響單片機的PSW寄存器,是以可以這樣做不影響中斷的現場。

另外RTOS的中斷嵌套保護不是“保護中斷不被嵌套”,是以原移植程式中的中斷服務程式中開始和結束的關閉和打開中斷語句是多餘的,在改造中去掉了。

(9)改變原中斷退出函數“OSIntExit”為系統級任務排程函數,見下圖:

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

對比前面的移植函數,去掉了将中斷嵌套減1的語句,将第660行判斷嵌套的條件改為等于1(中斷還未退出)。修改之後該函數隻有系統級任務排程功能,是以将函數名也修改為“uCx51_IntSched”,以示差別。

另外,改造還必須将整個uC/OS-II中涉及中斷嵌套計數變量的地方都做相應的修改。

三、改造後的uC/OS-II的系統中斷

(10)改造後的uC/OS-II的系統中斷使用兩個定時器:定時器0和定時器3。這兩個定時器的初始化程式如下:

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

其中定時器0工作頻率為1KHz,模式是16位自動重載,定時器3工作頻率為10KHz,模式是16位自動重載。

最早陳是知先生移植時使用的51單片機是12T的CPU,定時器0隻能工作在50Hz量級,是以任務休眠函數“OSTimeDly”的時間精度是20毫秒。現在工作1KHz頻率,任務休眠函數的時間精度提升到1毫秒。

在改造後的uC/OS-II,直接使用宏定義語句:

#define uCx51_Task_SleepMS OSTimeDly

就實作了以毫秒為機關的休眠函數。

(11)改造後的uC/OS-II的定時器0系統中斷目前隻承擔一個功能:系統節拍處理,見前面改造後的uC/OS-II的中斷ISR的程式的第176行“LCALL _?OSTimeTick”。

(12)改造後的uC/OS-II的定時器3系統中斷目前隻承擔一個功能:系統級任務排程處理,見前面改造後的uC/OS-II的中斷ISR的程式的第196行系統級任務排程函數“LCALL _?uCx51_IntSched”,這個定時器3中斷優先級固定為最低級。

四、改造後的uC/OS-II系統名額測試

(13)為了進行RTOS性能名額的數量測試,本文範例在P2端口連接配接了一個8通道邏輯分析儀,并且在程式中加入了測試語句。下圖是實時任務程式:

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

其中P22第2通道顯示任務A波形,P24和P25顯示任務B波形,P26和P27顯示任務C波形。

(14)上面程式中第75行P23=1顯示任務級排程函數“OSTaskResume(3)”的開始,由于任務B(優先級3)的優先級比任務C(優先級4)的高,是以這個函數會立即将任務控制權切換給任務B。

任務B是在第55行被挂起的,獲得任務控制權後會執行下面的第56行程式P23=0,是以測量P23第3通道的正脈沖時間就是任務級排程(非中斷任務切換)的時間。

(15)在前面定時器3的中斷中,隻調用了系統級任務排程(中斷任務切換)函數“_?uCx51_IntSched”,如果沒有更高優先級的任務就緒,該函數傳回,這時上面程式中第185行(P20=1)執行到第192行(P20=0)的正脈沖時間就是一輪系統級任務排程查詢時間,如果進行了任務切換,則會調用“OSIntCtxSw()”函數,在那裡退出,正脈沖時間就是系統級任務排程任務切換時間。

(16)下面是本文系統測量範例運作的整體效果邏輯分析儀截圖:

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

其中第4通道高電平時間是任務B獲得CPU控制權的時間,第6通道高電平時間是任務C獲得CPU控制權的時間。

第3通道的尖峰是任務C到任務B的切換時間,将這部分放大看為下圖:

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

測量結果是:任務級切換時間為32.25微秒。

(17)下圖第1通道的測量圖:

STC單片機uC/OS-II移植記(6):RTOS系統中斷研究與測量

第1通道對應系統節拍的時間,其中“OSTimeTick()”函數處理那些按指定時間休眠的任務,将它們的時間節拍計數減1,然後判斷是否已經完成了休眠并喚醒它。

測量結果是:每個系統節拍最少花費29微秒。

(18)上圖第0通道有寬窄不同的正脈沖,其中寬的脈沖對應系統級任務排程時間,測量結果是:系統級切換時間為20微秒。

窄的脈沖對應系統級任務排程查詢時間,測量結果為中斷查詢時間為5.75微秒。

繼續閱讀