Nucleus 实时操作系统中断(上)
Nucleus 實時操作系統(tǒng)中斷(上)
Interrupts in the Nucleus SE RTOS
所有現(xiàn)代微處理器和微控制器都有某種中斷設(shè)施。這種能力對于提供許多應(yīng)用程序所需的響應(yīng)能力是必不可少的。當(dāng)然,響應(yīng)性和可預(yù)測性也是使用實時操作系統(tǒng)背后的一個關(guān)鍵目標(biāo),因此這兩個主題確實存在輕微的沖突。使用中斷可能會損害操作系統(tǒng)的實時完整性。這一主題,以及沖突的解決方法,目前不講。在這里,我們將了解Nucleus SE使用的中斷處理策略。
在所有情況下,中斷都不是由Nucleus SE控制的,它們是在中斷發(fā)生時根據(jù)優(yōu)先級進行處理的,并以通常的方式進行矢量化。它們的執(zhí)行時間只是從運行主線應(yīng)用程序代碼和調(diào)度程序的可用時間中“偷走”的。顯然,這意味著所有的中斷服務(wù)程序都應(yīng)該簡單、簡短和快速。
本機中斷和托管中斷
Nucleus SE確實提供了兩種處理中斷的方法:“本機”中斷服務(wù)例程沒有什么特別的,并且與操作系統(tǒng)交互的機會有限(至少在選擇優(yōu)先級調(diào)度器時是這樣);“托管”中斷服務(wù)例程可以進行更廣泛的API調(diào)用。
通過一些進入/退出宏,與Nucleus SE應(yīng)用程序一起使用的中斷服務(wù)例程可以被指定為本機或托管的。
本機中斷
Nucleus SE本機中斷是標(biāo)準(zhǔn)的中斷服務(wù)例程,您可以將其視為“非托管的”。當(dāng)am中斷可能以很高的頻率發(fā)生并且需要以非常低的開銷進行服務(wù)時,通常使用它們。由于許多現(xiàn)代嵌入式編譯器都支持通過interrupt關(guān)鍵字編寫中斷服務(wù)例程,所以這個例程很可能是用C編寫的。唯一保存的上下文信息是編譯器認為必要的信息。這導(dǎo)致本機中斷例程可以執(zhí)行的操作有很大的限制,我們將很快看到。
要構(gòu)造Nucleus SE本機中斷服務(wù)例程,只需按通常的方式編寫ISR,包括在開始時調(diào)用NUSE_NISR_Enter()宏,在末尾調(diào)用NUSE_NISR_Exit()。這些宏在nuse_types.h中定義,只需將全局變量nuse_Task_State設(shè)置為nuse_NISR_CONTEXT。
托管中斷
如果您需要在ISR可以執(zhí)行的操作方面有更大的靈活性,Nucleus SE管理的中斷可能是解決方案。與本機中斷的關(guān)鍵區(qū)別是上下文保存。托管中斷不僅僅允許編譯器堆疊幾個寄存器,而是在輸入時保存完整的任務(wù)上下文(在上下文塊中)。然后從當(dāng)前任務(wù)的上下文塊中加載當(dāng)前任務(wù)的上下文。這考慮到了當(dāng)前任務(wù)可能被ISR代碼的操作改變的可能性;當(dāng)優(yōu)先級調(diào)度器正在使用時,這是完全可能的。包含了對Nucleus SE上下文保存和恢復(fù)的完整描述。
顯然,完整的上下文保存比由本機中斷執(zhí)行的幾個寄存器的堆棧開銷更高。這是額外靈活性的代價,也是為什么可以選擇處理中斷的方法的原因。
托管中斷是使用NUSE_managed_ISR()宏構(gòu)造的,該宏在NUSE_types.h中定義。此宏構(gòu)造包含以下序列的函數(shù):
· 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
宏接受兩個參數(shù):中斷的名稱,用作構(gòu)造的例程的函數(shù)名;包含用戶提供的ISR邏輯的函數(shù)名。
本文后面將介紹Nucleus SE實時時鐘ISR,它是受管ISR的一個示例。
中斷服務(wù)例程的API調(diào)用
可以從本機或托管ISR調(diào)用的API函數(shù)的范圍取決于選擇了哪個調(diào)度程序。一般來說,優(yōu)先級調(diào)度程序的使用為在API函數(shù)調(diào)用的結(jié)果下調(diào)用調(diào)度程序提供了許多機會,這在本機ISR中是一個問題。
使用優(yōu)先級調(diào)度程序從本機ISR調(diào)用API
允許使用優(yōu)先級調(diào)度程序從本機ISR調(diào)用有限范圍的API函數(shù)。這一限制是由于Nucleus SE API的靈活性造成的–許多調(diào)用都會導(dǎo)致任務(wù)準(zhǔn)備就緒,并且本地ISR不可能調(diào)用調(diào)度器(因為任務(wù)上下文未被保存)。如果不啟用任務(wù)阻塞,則具有更大的靈活性。
始終允許以下API調(diào)用:
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(),因為這提供了一個很好的方法來指示任務(wù)需要一些工作。
如果禁用了阻塞(這意味著許多API調(diào)用可能無法使任務(wù)就緒),則可以使用許多其他API函數(shù):
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(),因為這提供了一個很好的方法來指示任務(wù)需要一些工作。
如果禁用了阻塞(這意味著許多API調(diào)用可能無法使任務(wù)就緒),則可以使用許多其他API函數(shù):
NUSE_Task_Suspend()
NUSE_Task_Resume()
NUSE_Task_Sleep()
NUSE_Task_Relinquish()
NUSE_Task_Reset()
NUSE_Signals_Receive()
來自托管ISR或具有非優(yōu)先級調(diào)度程序的本機ISR的API調(diào)用
當(dāng)使用run-to-completion、round-robin或time-sliced調(diào)度器時,可以從ISR調(diào)用范圍更廣的API函數(shù)。如果使用類似的ISR優(yōu)先級,則受管調(diào)度器有助于提高ISR的優(yōu)先級。這是因為允許調(diào)用可能導(dǎo)致調(diào)度不同的任務(wù)。NUSE_Reschedule()中的代碼有助于此功能,該代碼檢測調(diào)用的上下文是ISR,并禁止上下文切換(允許它在ISR結(jié)束時發(fā)生)。調(diào)度程序操作的完整細節(jié)在前面的一篇文章中介紹過。
一個關(guān)鍵的要求是ISR中的API調(diào)用不能導(dǎo)致當(dāng)前任務(wù)的掛起,例如等待一個資源。換句話說,這種調(diào)用應(yīng)該在suspend選項設(shè)置為NUSE_NO_suspend的情況下進行。
鑒于此規(guī)定,可使用以下API調(diào)用:
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調(diào)用是不允許的,因為它們與當(dāng)前任務(wù)相關(guān):
NUSE_Task_Relinquish()
NUSE_Signals_Receive()
NUSE_Task_Sleep()
實時時鐘ISR
實時時鐘(RTC)ISR是Nucleus SE提供的唯一完整的中斷服務(wù)例程。除了為Nucleus SE提供所有所需的定時功能外,它還可以作為如何編寫受管中斷的示例。
RTC ISR操作
RTC ISR提供的設(shè)施已在前面的一篇文章中概述,其中涵蓋了Nucleus SE中的系統(tǒng)時間這一廣泛主題。根據(jù)應(yīng)用程序的配置方式,所有功能都是可選的。這是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的四個功能領(lǐng)域:
計時器
如果配置了任何應(yīng)用程序計時器,ISR將通過遞減其計數(shù)器值來循環(huán)為每個計時器提供服務(wù)。如果計時器過期(即計數(shù)器達到零),則兩個操作將生效:
如果配置了計時器過期例程,并且計時器具有指向函數(shù)的有效(非空)指針(在NUSE_timer_expiration_Routine_Address[]),則執(zhí)行例程,并從NUSE_timer_expiration_Routine_parameter[]接收參數(shù)。
如果計時器有一個重定時時間(即NUSE_timer_reschedule_time[]中的非零值),則計時器將重新加載該值。
應(yīng)用程序計時器在上一篇文章中有更詳細的描述。
系統(tǒng)時鐘
如果配置了系統(tǒng)時鐘,那么NUSE_Tick_clock的值只會遞增。關(guān)于系統(tǒng)時間的進一步討論可以在上一篇文章中找到。
任務(wù)睡眠
如果啟用了任務(wù)休眠(即配置了API調(diào)用NUSE_task_sleep()),則會檢查每個任務(wù)的超時計數(shù)器(NUSE_task_timeout_counter[]中的條目),如果不是零,則遞減。如果任何計數(shù)器達到零,則相應(yīng)的任務(wù)將被喚醒。
時間片調(diào)度
如果正在使用時間片調(diào)度程序,則時間片計數(shù)器(NUSE_time_slice_Ticks)將遞減。如果達到零,則調(diào)用調(diào)度程序。對NUSE_Reschedule()的調(diào)用負責(zé)重置計數(shù)器。
有管理的中斷
對RTC ISR是受管中斷的原因進行一些解釋可能是有用的,因為在正確的情況下,用戶可能希望將其重新編碼為本機中斷,以減少開銷。例如,如果只使用系統(tǒng)時間工具(即沒有應(yīng)用程序計時器、沒有任務(wù)睡眠和時間片調(diào)度器),則本機中斷就可以了。管理中斷的需求如下:
如果使用了計時器并配置了過期例程,這些例程可能會(從中斷上下文)進行API調(diào)用,從而導(dǎo)致重新調(diào)度。它們受到與從isr發(fā)出的API調(diào)用相同的限制(請參閱本章前面的部分)。
如果優(yōu)先級調(diào)度程序正在使用中,任務(wù)休眠到期可能需要調(diào)度更高優(yōu)先級的任務(wù)。
如果正在使用時間片調(diào)度程序,它肯定會從RTC ISR調(diào)用,因此必須使用托管中斷。
總結(jié)
以上是生活随笔為你收集整理的Nucleus 实时操作系统中断(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 系统时间
- 下一篇: Nucleus 实时操作系统中断(下)