《VxWorks7編程指南》筆記(四)——中斷服務程序ISR

目錄

 

1.中斷服務程序ISR

2.針對ISR的VxWorks配置

3.ISR可用資源

4.ISR編程與調試

5.修改系統時鐘ISR

6.運行時的ISR信息

7.ISR與工作隊列死機


1.中斷服務程序ISR

外部事件通常通過中斷的方式通知系統,因此硬件中斷處理是實時操作系統中的關鍵功能。

爲了以最快速度響應中斷,VxWorks中斷服務程序執行在獨有的上下文,而非任何任務是上下文中。除非系統專門進行過配置,否則不會推遲ISR的執行。

2.針對ISR的VxWorks配置

VxWorks系統默認支持SIR。中斷棧可以按大小和附加特性進行配置。中斷棧必須足夠大,以處理中斷嵌套時的最壞情況。

中斷棧配置

所有的的ISR使用相同的中斷棧空間。系統將在初始化時根據設定的配置參數爲中斷棧分配空間。其大小必須足夠大,以應付中斷嵌套時的最壞情況。中斷棧大小由宏ISR_STACK_SIZE定義。

注意:某些架構不允許使用獨立的中斷棧,而需要使用被中斷任務的棧空間。在這種架構下,必須確保創建任務時分配了足夠大的棧空間,以處理中斷嵌套和嵌套調用的最壞情況。

 

中斷棧填充

默認情況下,中斷棧空間被填充爲0xEE。對棧空間進行填充的做法,對於開發過程中的調試很有幫助。具體可以使用checkStack()函數進行棧空間檢查。

在進行系統配置時,建議不要對中斷棧空間進行填充,以獲得更佳的性能。可以使用配置參數VX_GLOBAL_NO_STACK_FILL關閉棧空間填充功能。

 

中斷棧保護

如果使能了MMU功能,系統就可以通過配置INCLUDE_PROTECT_INTERRUPT_STACK組件,提供對中斷棧始末的guard zone保護。

可以通過如下配置參數設置guard zone的大小:

  • INTERRUPT_STACK_OVERFLOW_SIZE:設置中斷棧上溢大小;
  • INTERRUPT_STACK_UNDERFLOW_SIZE:設置中斷棧下溢大小;

當添加了guard zone,棧空間的大小通常是MMU大小的整數倍。

3.ISR可用資源

所有的VxWorks功能庫,如鏈表、環形緩衝區,都可以在ISR中使用。然而對於從ISR中調用函數還是有一些限制。

全局變量errno可以作爲中斷進入與退出代碼的一部分而被保存和獲取。所以,ISR刻意像其他代碼一樣引用和修改errno。

 

4.ISR編程與調試

對於ISR的最基礎的要求就是,ISR代碼應該儘可能的短。ISR中不應該添加耗時的函數,此外還有一些限制:ISR不能調用會導致ISR阻塞的函數,也不能調用使用浮點數協處理器的函數;對於C++使用也有限制。

非阻塞函數

雖然ISR中可以使用許多VxWorks功能,但是需要注意一些重要的限制條件。這些限制都是源於如下事實:ISR不是運行在常規的任務上下文中,且沒有任務控制塊,因此所有的ISR都共享同一個棧空間。

因爲上述原因,對於ISR的最基礎的限制條件就是,不能在ISR中調用會導致ISR自身阻塞的函數。例如,在ISR中不能嘗試獲取一個信號量,因爲如果當前無法獲取該信號量,那麼內核將嘗試把ISR切換到掛起狀態。然而,ISR可以釋放信號量,從而釋放任何在等待該信號量的任務。

內存相關函數malloc()和free()中會嘗試獲取信號量,所以在ISR中不應該調用這兩個函數。因此在ISR中不應該調用任何創建或刪除函數。

ISR也不能通過VxWorks驅動執行I/O操作。儘管對I/O系統沒有內在的限制條件,大多數的設備驅動仍然需要一個任務上下文環境,因爲它們可能阻塞等待設備的任務。一個例外時VxWorks pipe驅動,ISR可以使用該驅動執行寫操作。VxWorks還提供了幾個供ISR調用的函數,用於向系統控制檯中輸出信息:logMsg()、kprintf()、kputs()。

 

浮點數協處理器函數

默認條件下,中斷驅動代碼不保存和讀取浮點數寄存器。如果一個ISR需要執行浮點數指令,那麼它必須使用fppArchLib庫中提供的函數,對浮點數協處理器中的寄存器進行顯示的保存和讀取。

 

共享數據區的間接訪問

ISR不應該直接訪問共享數據區。一個ISR將繼承被它搶佔的任務的內存環境,如果該任務不包括共享數據區,那麼ISR就不能訪問共享內存,否則會導致系統異常。

爲了可靠地訪問共享數據區,ISR必須使用一個已經包含了共享數據區的任務。該任務在ISR執行完畢後可以執行對共享數據區的相關操作。

 

中斷與任務之間的通信

儘管VxWorks支持直接連接運行在中斷級的ISR,但是中斷事件通常會傳播到任務級代碼中。許多VxWorks功能不適用於中斷級代碼,包括任何設備的I/O(除了pipe)。然而,如下技術可以用於ISR到任務級代碼之間的通信。

  • 共享內存與環形緩衝區

ISR可以與任務級代碼共享變量、緩衝區和環形緩衝區。

  • 信號量

ISR可以釋放任務所需要的信號量(除了互斥信號量和VxMP共享信號量)。

  • 消息隊列

ISR可以向等待接收消息隊列中的消息的任務發送消息(除了VxMP中使用的共享消息隊列)。如果隊列已滿,則該消息將被丟棄。

  • 管道

ISR可以向供任務讀取的管道中寫入消息。任務和ISR可以向同一個管道中寫入消息。因爲ISR不能被阻塞,所以如果管道已滿,那麼寫入的消息將被丟棄。除了write()函數,ISR中不能在管道中觸發任何I/O函數。

  • 信號

ISR可以向任務發送信號,從而異步調度相關的信號處理函數。

  • VxWorks事件

ISR可以向任務發送VxWorks事件。

 

高中斷優先級保留

大多數應用程序都可以使用VxWorks中斷。但是有些情況下,類似於關鍵運動控制或系統失效響應等事件,需要擁有低級別的控制。在這些情況下,最好能夠保留最高級別的中斷,確保以零延時響應這些事件。爲了實現零延時,VxWorks提供了intLockLevelSet()函數,用於將系統範圍內的中斷鎖級別設定到一個特定的級別。如果沒有指定一個級別,那麼將使用處理器架構所支持的最高級別。

 

對高中斷級別ISR的限制

對鏈接到未屏蔽的中斷優先級(既可以是比intLockLevelSet()函數設置的中斷優先級高的級別,也可以是由硬件定義的非屏蔽中斷優先級)的ISR由特殊的限制:

  • ISR只能通過intVecSet()函數連接
  • ISR不能使用任何基於中斷鎖的VxWorks操作系統功能。否則後果就是,除了系統重啓,ISR不能安全地執行任何VxWorks函數調用。

 

對於I/O的使用限制

通常,ISR不能通過VxWorks驅動執行I/O操作,因爲這些操作會導致ISR阻塞。這意味着標準的I/O函數,如printf()和puts()不能用於調試ISR。基礎的供ISR調試使用的方法包括:

  • 在ISR中使用全局變量,該全局變量可以根據相關數據進行更新。之後就可以在運行時通過shell顯示這些變量的值。
  • 在ISR中使用如下函數向控制檯輸出信息:logMsg()、kprintf()、kputs()。

使用全局變量的優點在於:實現簡單且對ISR執行的性能影響最小。缺點在於如果系統因爲ISR中的某個bug導致掛起,就不能使用shell顯示變量的值了。

使用logMsg()函數的優點在於:可以自動向控制檯打印消息,相較於kprintf()和kputs(),對於ISR的執行性能的影響更小。缺點在於,如果系統在調用該函數後短暫地掛起了,那麼消息可能無法顯示在控制檯中。原因是由於logMsg()的異步操作首先是把消息寫入到一個消息隊列,然後logging任務將消息打包再發送到控制檯。

使用kprintf()與kputs()的優點在於:它們可以同步地輸出消息(使用輪詢模式),因此可以在bug出現時精確地反映出ISR已經執行到哪個階段(也可用於內核啓動期間或任務切換鉤子函數中)。缺點在於,因爲它們使用串口輸出信息,所以或顯著影響ISR的執行性能。

 

中斷級異常

當一個任務產生了硬件異常,如非法指令或總線錯誤,那麼該任務將被掛起。系統中的其他任務將繼續執行,而不被中斷。然而,當一個ISR導致了類似的異常,系統中將沒有相應的安全保障用於處理這些異常。ISR不具備可以掛起的上下文環境。相反,VxWorks將這些異常描述信息保存在內存空間的一個特殊區域,並執行系統重啓。

VxWorks的BootLoader將檢測低內存空間中的異常描述信息是否存在,如果檢測到,則會在系統控制檯中顯示出來。BootLoader的“e”命令用於重新顯示異常描述信息。類似的異常信息如下:

workQPanic:Kernel work queued from ISR overflowd.

 

ISR與內核工作隊列死機(work queueu panic)

爲了減少工作隊列溢出,可以使用WIND_JOBS_MAX內核配置參數增加內核工作隊列大小。

與內核工作隊列死機相關的錯誤信息如下:

workQPanic:kernel work queue overflow

5.修改系統時鐘ISR

可以根據應用程序需要,在usrClock()函數中添加相關的函數。

在系統啓動的初始化過程中,系統時鐘ISR usrClock()函數被掛接到系統時鐘定時器中斷上。每個系統時鐘中斷都將調用usrClock(),用於更新系統tick值並執行調度。

在usrClock()函數中添加代碼也要遵守在ISR中調用函數的要求。

6.運行時的ISR信息

針對每個與VxWorks連接的ISR,系統都創建了一個內核對象。ISR對象提供了一種管理系統中所有ISR信息的方法。

可以參考isrLib和isrShow API參考手冊,瞭解用於獲取ISR信息的相關函數。

INCLUDE_ISR_SHOW組件提供了isrShow(),INCLUDE_ISR_OBJECT提供了isrLib。

7.ISR與工作隊列死機

如果ISR以非常高的頻率填充內核工作隊列,導致內核處理不過來,那麼會將工作隊列填滿,使得無法再將新的工作項添加到工作隊列中。這將導致稱爲工作隊列死機(work queue panic)的致命錯誤。

爲了降低中斷響應時間,VxWorks內核在執行關鍵區代碼時不會鎖中斷,如任務狀態改變、上下文切換、重新調度等等。使能中斷後,ISR將以儘可能快的速度執行。如果在內核執行關鍵區代碼的過程中產生了一箇中斷,而ISR同樣調用了需要執行關鍵代碼的內核函數,那麼內核將延遲關鍵區代碼的執行,知道具備安全執行的條件爲止。這個過程是通過內核工作隊列實現的。工作隊列可以高效地將內核關鍵區排入隊列,並且不會阻塞ISR中非關鍵區的代碼執行。

考慮到性能因素,工作隊列被設計爲一個具有固定大小的環形緩衝區。可以通過WIND_JOBS_MAX配置參數配置其大小,該大小必須是2的冪次。

 

工作隊列死機(work queue panic)

通常,工作隊列死機是由於設備驅動不恰當的寫操作導致的。例如:

  • 確認中斷失敗。如果一個ISR未能確認一箇中斷,那麼將導致一直產生相同的中斷。
  • 在中斷上下文執行了太多的操作。爲了最佳的實時性能,可以將ISR中的複雜操作轉移到與中斷源相關的合適優先級的任務中執行。ISR應該使用一個內核調用喚醒該任務(例如semGive()).
  • 將設備突發事件作爲獨立中斷處理。應該在關閉設備相關的中斷之後在任務上下文中處理突發事件。當沒有再檢測到未處理的事件且任務將會掛起時,就可以再次使能中斷源了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章