Nucleus 实时操作系统中断(上)
Nucleus 實時操作系統中斷(上)
Interrupts in the Nucleus SE RTOS
所有現代微處理器和微控制器都有某種中斷設施。這種能力對于提供許多應用程序所需的響應能力是必不可少的。當然,響應性和可預測性也是使用實時操作系統背后的一個關鍵目標,因此這兩個主題確實存在輕微的沖突。使用中斷可能會損害操作系統的實時完整性。這一主題,以及沖突的解決方法,目前不講。在這里,我們將了解Nucleus SE使用的中斷處理策略。
在所有情況下,中斷都不是由Nucleus SE控制的,它們是在中斷發生時根據優先級進行處理的,并以通常的方式進行矢量化。它們的執行時間只是從運行主線應用程序代碼和調度程序的可用時間中“偷走”的。顯然,這意味著所有的中斷服務程序都應該簡單、簡短和快速。
本機中斷和托管中斷
Nucleus SE確實提供了兩種處理中斷的方法:“本機”中斷服務例程沒有什么特別的,并且與操作系統交互的機會有限(至少在選擇優先級調度器時是這樣);“托管”中斷服務例程可以進行更廣泛的API調用。
通過一些進入/退出宏,與Nucleus SE應用程序一起使用的中斷服務例程可以被指定為本機或托管的。
本機中斷
Nucleus SE本機中斷是標準的中斷服務例程,您可以將其視為“非托管的”。當am中斷可能以很高的頻率發生并且需要以非常低的開銷進行服務時,通常使用它們。由于許多現代嵌入式編譯器都支持通過interrupt關鍵字編寫中斷服務例程,所以這個例程很可能是用C編寫的。唯一保存的上下文信息是編譯器認為必要的信息。這導致本機中斷例程可以執行的操作有很大的限制,我們將很快看到。
要構造Nucleus SE本機中斷服務例程,只需按通常的方式編寫ISR,包括在開始時調用NUSE_NISR_Enter()宏,在末尾調用NUSE_NISR_Exit()。這些宏在nuse_types.h中定義,只需將全局變量nuse_Task_State設置為nuse_NISR_CONTEXT。
托管中斷
如果您需要在ISR可以執行的操作方面有更大的靈活性,Nucleus SE管理的中斷可能是解決方案。與本機中斷的關鍵區別是上下文保存。托管中斷不僅僅允許編譯器堆疊幾個寄存器,而是在輸入時保存完整的任務上下文(在上下文塊中)。然后從當前任務的上下文塊中加載當前任務的上下文。這考慮到了當前任務可能被ISR代碼的操作改變的可能性;當優先級調度器正在使用時,這是完全可能的。包含了對Nucleus SE上下文保存和恢復的完整描述。
顯然,完整的上下文保存比由本機中斷執行的幾個寄存器的堆棧開銷更高。這是額外靈活性的代價,也是為什么可以選擇處理中斷的方法的原因。
托管中斷是使用NUSE_managed_ISR()宏構造的,該宏在NUSE_types.h中定義。此宏構造包含以下序列的函數:
· task context save
· set NUSE_Task_State to NUSE_MISR_CONTEXT
· call user-supplied ISR code function
· restore NUSE_Task_State to previous setting
· task context restore
宏接受兩個參數:中斷的名稱,用作構造的例程的函數名;包含用戶提供的ISR邏輯的函數名。
本文后面將介紹Nucleus SE實時時鐘ISR,它是受管ISR的一個示例。
中斷服務例程的API調用
可以從本機或托管ISR調用的API函數的范圍取決于選擇了哪個調度程序。一般來說,優先級調度程序的使用為在API函數調用的結果下調用調度程序提供了許多機會,這在本機ISR中是一個問題。
使用優先級調度程序從本機ISR調用API
允許使用優先級調度程序從本機ISR調用有限范圍的API函數。這一限制是由于Nucleus SE API的靈活性造成的–許多調用都會導致任務準備就緒,并且本地ISR不可能調用調度器(因為任務上下文未被保存)。如果不啟用任務阻塞,則具有更大的靈活性。
始終允許以下API調用:
NUSE_Task_Current()
NUSE_Task_Check_Stack()
NUSE_Task_Information()
NUSE_Task_Count()
NUSE_Partition_Pool_Information()
NUSE_Partition_Pool_Count()
NUSE_Mailbox_Information()
NUSE_Mailbox_Count()
NUSE_Queue_Information()
NUSE_Queue_Count()
NUSE_Pipe_Information()
NUSE_Pipe_Count()
NUSE_Semaphore_Information()
NUSE_Semaphore_Count()
NUSE_Event_Group_Information()
NUSE_Event_Group_Count()
NUSE_Signals_Send()
NUSE_Timer_Control()
NUSE_Timer_Get_Remaining()
NUSE_Timer_Reset()
NUSE_Timer_Information()
NUSE_Timer_Count()
NUSE_Clock_Set()
NUSE_Clock_Retrieve()
NUSE_Release_Information()
但是,唯一真正有用的是NUSE_Signals_Send(),因為這提供了一個很好的方法來指示任務需要一些工作。
如果禁用了阻塞(這意味著許多API調用可能無法使任務就緒),則可以使用許多其他API函數:
NUSE_Partition_Allocate()
NUSE_Partition_Deallocate()
NUSE_Mailbox_Send()
NUSE_Mailbox_Receive()
NUSE_Mailbox_Reset()
NUSE_Queue_Send()
NUSE_Queue_Receive()
NUSE_Queue_Jam()
NUSE_Queue_Reset()
NUSE_Pipe_Send()
NUSE_Pipe_Receive()
NUSE_Pipe_Jam()
NUSE_Pipe_Reset()
NUSE_Semaphore_Obtain()
NUSE_Semaphore_Release()
NUSE_Semaphore_Reset()
NUSE_Event_Group_Set()
NUSE_Event_Group_Retrieve()
但是,唯一真正有用的是NUSE_Signals_Send(),因為這提供了一個很好的方法來指示任務需要一些工作。
如果禁用了阻塞(這意味著許多API調用可能無法使任務就緒),則可以使用許多其他API函數:
NUSE_Task_Suspend()
NUSE_Task_Resume()
NUSE_Task_Sleep()
NUSE_Task_Relinquish()
NUSE_Task_Reset()
NUSE_Signals_Receive()
來自托管ISR或具有非優先級調度程序的本機ISR的API調用
當使用run-to-completion、round-robin或time-sliced調度器時,可以從ISR調用范圍更廣的API函數。如果使用類似的ISR優先級,則受管調度器有助于提高ISR的優先級。這是因為允許調用可能導致調度不同的任務。NUSE_Reschedule()中的代碼有助于此功能,該代碼檢測調用的上下文是ISR,并禁止上下文切換(允許它在ISR結束時發生)。調度程序操作的完整細節在前面的一篇文章中介紹過。
一個關鍵的要求是ISR中的API調用不能導致當前任務的掛起,例如等待一個資源。換句話說,這種調用應該在suspend選項設置為NUSE_NO_suspend的情況下進行。
鑒于此規定,可使用以下API調用:
NUSE_Task_Current()
NUSE_Task_Check_Stack()
NUSE_Task_Information()
NUSE_Task_Count()
NUSE_Task_Suspend()
NUSE_Task_Resume()
NUSE_Task_Reset()
NUSE_Partition_Allocate()
NUSE_Partition_Deallocate()
NUSE_Partition_Pool_Information()
NUSE_Partition_Pool_Count()
NUSE_Mailbox_Send()
NUSE_Mailbox_Receive()
NUSE_Mailbox_Reset()
NUSE_Mailbox_Information()
NUSE_Mailbox_Count()
NUSE_Queue_Send()
NUSE_Queue_Receive()
NUSE_Queue_Jam()
NUSE_Queue_Reset()
NUSE_Queue_Information()
NUSE_Queue_Count()
NUSE_Pipe_Send()
NUSE_Pipe_Receive()
NUSE_Pipe_Jam()
NUSE_Pipe_Reset()
NUSE_Pipe_Information()
NUSE_Pipe_Count()
NUSE_Semaphore_Obtain()
NUSE_Semaphore_Release()
NUSE_Semaphore_Reset()
NUSE_Semaphore_Information()
NUSE_Semaphore_Count()
NUSE_Event_Group_Set()
NUSE_Event_Group_Retrieve()
NUSE_Event_Group_Information()
NUSE_Event_Group_Count()
NUSE_Signals_Send()
NUSE_Timer_Control()
NUSE_Timer_Get_Remaining()
NUSE_Timer_Reset()
NUSE_Timer_Information()
NUSE_Timer_Count()
NUSE_Clock_Set()
NUSE_Clock_Retrieve()
NUSE_Release_Information()
一些API調用是不允許的,因為它們與當前任務相關:
NUSE_Task_Relinquish()
NUSE_Signals_Receive()
NUSE_Task_Sleep()
實時時鐘ISR
實時時鐘(RTC)ISR是Nucleus SE提供的唯一完整的中斷服務例程。除了為Nucleus SE提供所有所需的定時功能外,它還可以作為如何編寫受管中斷的示例。
RTC ISR操作
RTC ISR提供的設施已在前面的一篇文章中概述,其中涵蓋了Nucleus SE中的系統時間這一廣泛主題。根據應用程序的配置方式,所有功能都是可選的。這是RTC ISR的完整代碼。
#if NUSE_TIMER_NUMBER != 0
{
U8 timer;for (timer=0; timer
{
if
(NUSE_Timer_Status[timer])
{
if (–NUSE_Timer_Value[timer] == 0)
{
NUSE_Timer_Expirations_Counter[timer]++;
#if NUSE_TIMER_EXPIRATION_ROUTINE_SUPPORT ||
NUSE_INCLUDE_EVERYTHING
if (NUSE_Timer_Expiration_Routine_Address[timer]
!= NULL)
{
((PF1)NUSE_Timer_Expiration_Routine_Address[timer])
NUSE_Timer_Expiration_Routine_Parameter[timer]);
}
#endif
/* reschedule? */
if
(NUSE_Timer_Reschedule_Time[timer] != 0)
{
/* yes: set up time */
NUSE_Timer_Value[timer] =
NUSE_Timer_Reschedule_Time[timer];
}
else
{
/* no: disable */
NUSE_Timer_Status[timer] = FALSE;
}
}
}}
}
#endif
#if NUSE_SYSTEM_TIME_SUPPORT || NUSE_INCLUDE_EVERYTHING
NUSE_Tick_Clock++;
#endif
#if NUSE_TASK_SLEEP || NUSE_INCLUDE_EVERYTHING
{
U8 task;for (task=0; task{if (NUSE_Task_Timeout_Counter[task]
!= 0)
{
NUSE_Task_Timeout_Counter[task]–;
if (NUSE_Task_Timeout_Counter[task] == 0)
{
NUSE_Wake_Task(task);
}
}}
}
#endif
#if NUSE_SCHEDULER_TYPE == NUSE_TIME_SLICE_SCHEDULER
if (–NUSE_Time_Slice_Ticks == 0){NUSE_Reschedule();}
#endif
我們將研究RTC ISR的四個功能領域:
計時器
如果配置了任何應用程序計時器,ISR將通過遞減其計數器值來循環為每個計時器提供服務。如果計時器過期(即計數器達到零),則兩個操作將生效:
如果配置了計時器過期例程,并且計時器具有指向函數的有效(非空)指針(在NUSE_timer_expiration_Routine_Address[]),則執行例程,并從NUSE_timer_expiration_Routine_parameter[]接收參數。
如果計時器有一個重定時時間(即NUSE_timer_reschedule_time[]中的非零值),則計時器將重新加載該值。
應用程序計時器在上一篇文章中有更詳細的描述。
系統時鐘
如果配置了系統時鐘,那么NUSE_Tick_clock的值只會遞增。關于系統時間的進一步討論可以在上一篇文章中找到。
任務睡眠
如果啟用了任務休眠(即配置了API調用NUSE_task_sleep()),則會檢查每個任務的超時計數器(NUSE_task_timeout_counter[]中的條目),如果不是零,則遞減。如果任何計數器達到零,則相應的任務將被喚醒。
時間片調度
如果正在使用時間片調度程序,則時間片計數器(NUSE_time_slice_Ticks)將遞減。如果達到零,則調用調度程序。對NUSE_Reschedule()的調用負責重置計數器。
有管理的中斷
對RTC ISR是受管中斷的原因進行一些解釋可能是有用的,因為在正確的情況下,用戶可能希望將其重新編碼為本機中斷,以減少開銷。例如,如果只使用系統時間工具(即沒有應用程序計時器、沒有任務睡眠和時間片調度器),則本機中斷就可以了。管理中斷的需求如下:
如果使用了計時器并配置了過期例程,這些例程可能會(從中斷上下文)進行API調用,從而導致重新調度。它們受到與從isr發出的API調用相同的限制(請參閱本章前面的部分)。
如果優先級調度程序正在使用中,任務休眠到期可能需要調度更高優先級的任務。
如果正在使用時間片調度程序,它肯定會從RTC ISR調用,因此必須使用托管中斷。
總結
以上是生活随笔為你收集整理的Nucleus 实时操作系统中断(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 系统时间
- 下一篇: Nucleus 实时操作系统中断(下)