版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
傻瓜實現(xiàn)FreeRTOS系統(tǒng)如果你希望修改FreeRTOS源代碼移植實時內(nèi)核到另一個微控制器或者原型板(prototypingboard)第一次接觸FreeRTOS,希望得到關(guān)于它們在操作和實現(xiàn)上的更多信息這些文檔會有用。本文檔分為兩個章節(jié):1.基本原理和RTOS概念包括多任務(wù)的背景信息和基本實時概念,這是為初學(xué)者準(zhǔn)備的(isintendedforbeginners)2-從底向上(fromthebottomup)解釋實時內(nèi)核源代碼FreeRTOS實時內(nèi)核已經(jīng)移植到許多不同的微控制器架構(gòu)下。這份文檔是以AtmelAVR為范例,因為:AVR架構(gòu)簡單有免費可用的開發(fā)工具WinAVR(GCC)developmenttools.非常便宜的原型板STK500prototypingboard在本文的最后,還一步一步地詳細(xì)描述了一個完整的上下文切換(contextswitch)。RTOS基本原理多任務(wù)調(diào)度上下文切換實時應(yīng)用實時調(diào)度這一節(jié)提供一個關(guān)于實時和多任務(wù)概念的簡介。讀下一節(jié)之前必須理解這些概念。多任務(wù)(Multitasking)在一個操作系統(tǒng)內(nèi)部,內(nèi)核[kernel]是最核心的部件。像Linux那樣的操作系統(tǒng)使用的內(nèi)核,從表面上看(seemingly),允許用戶并發(fā)(simultaneously)訪問計算機(jī)。多個用戶似乎(apparently)可以并行(concurrently)執(zhí)行多個程序。在操作系統(tǒng)的控制下,每個正在執(zhí)行的程序就是一個任務(wù)[task]。如果一個操作系統(tǒng)能夠以這種方法執(zhí)行多個任務(wù),這就叫做多任務(wù)[multitasking].多任務(wù)操作系統(tǒng)的使用可以簡化應(yīng)用程序的設(shè)計:操作系統(tǒng)的多任務(wù)和任務(wù)間通信的機(jī)制允許復(fù)雜的應(yīng)用程序被分成一系列更小的和更多的可以管理的任務(wù)。(程序的)劃分(partitioning)讓軟件測試更容易,團(tuán)隊工作分解(workbreakdownwithinteams),也有利于代碼復(fù)用。復(fù)雜的定時和先后順序的細(xì)節(jié)可以從應(yīng)用程序代碼中刪除。(因為)這成為操作系統(tǒng)的職責(zé)。多任務(wù)Vs并發(fā)傳統(tǒng)的(conventional)的處理器同時只能執(zhí)行一個任務(wù)。但通過快速的任務(wù)切換,一個多任務(wù)操作系統(tǒng)可以使它看起來(appear)好像每個任務(wù)并行執(zhí)行一樣。這可以下面的示意圖來描述(depicted)。它顯示了有關(guān)(withrespectto)時間的3個任務(wù)的執(zhí)行模式。任務(wù)名用顏色標(biāo)注出來,寫在左手邊。時間從左到右增加,相應(yīng)的顏色的線條顯示該任務(wù)在某個特殊時間正在執(zhí)行。上面的圖演示的是用戶所覺察到的并行執(zhí)行模式,下面的圖是實際的多任務(wù)執(zhí)行模式。Allavailabletasksappeartobeexecuting...::t12TimetnTask1ExecutingTask2ExecutingTask3Executing…butonlyonetaskiseverexecutingatanytime.----所有可用的任務(wù)都好像在執(zhí)行,但實際上在任何一個時刻都只有一個任務(wù)在執(zhí)行調(diào)度調(diào)度器(scheduler)是內(nèi)核中負(fù)責(zé)決定在某個特殊時間哪個任務(wù)應(yīng)該執(zhí)行的部分。內(nèi)核可以在任務(wù)的生命期(lifetime)掛起(suspend)/恢復(fù)(resume)一個任務(wù)許多次。調(diào)度策略(schedulingpolicy)是調(diào)度器用來決定哪個任務(wù)在哪個時間點執(zhí)行的算法。一個(非實時)多用戶系統(tǒng)的策略很可能分配(allow)給每個任務(wù)一個"公平"(fair)的處理器時間片(proportionofprocessortime)。用在實時系統(tǒng)/嵌入式系統(tǒng)的策略稍后再描述。除了被RTOS內(nèi)核無意的掛起外,一個任務(wù)還可以自己掛起自己。如果一個任務(wù)想延遲一段固定的時間(也就是sleep),或者等待(也就是block)某個資源可用(比如一個串口),或者等待一個事件出現(xiàn)(比如一個鍵按下)。一個阻塞或者睡眠的任務(wù)是不能執(zhí)行的,不會為它分配任何處理時間。Task1ExecutingTask2ExecutingTask1ExecutingTask2ExecutingTask3ExecutingTaskl正在運行內(nèi)核掛起Taskl恢復(fù)任務(wù)Task2Task2正在執(zhí)行,為獨占訪問(exclusiveaccess),它鎖定一個處理器外設(shè)內(nèi)核掛起Task2恢復(fù)Task3Task3試圖訪問同樣的處理器外設(shè),發(fā)現(xiàn)它被鎖定,Task3不能繼續(xù),所以自己掛起自己。內(nèi)核恢復(fù)Taskl接下來(thenexttime),Task2在9處執(zhí)行。它完成了對處理器外設(shè)的訪問,所以解鎖它再下來,Task3在10處執(zhí)行。它發(fā)現(xiàn)現(xiàn)在可以訪問處理器外設(shè)了,于是開始執(zhí)行,直到被內(nèi)核掛起。上下文切換跟任何其他程序一樣,一個任務(wù)執(zhí)行時,它使用處理器/微控制器的寄存器,訪問RAMROM。這些資源(處理器的寄存器,stack等)一起組成任務(wù)的執(zhí)行上下文(thetaskexecutioncontext).一個任務(wù)是一個連續(xù)有序的代碼片斷。它并不知道它將何時被內(nèi)核掛起或者恢復(fù),甚至不知道這些事情(掛起或者恢復(fù))在什么時候已經(jīng)發(fā)生了。下面考查(Consider)的這個例子是用來求兩個處理器中的寄存器值之和,該任務(wù)在執(zhí)行1條指令后就立即被掛起。bytheADDWhenthetaskisresumedtheADDinstructionwillbethefirstinstructiontoexecute.ThetaskwillnotknowifadifferenttaskmodifiedReg1orReg2inlheinterim-->任務(wù)將要執(zhí)行ADD指令時,被掛起-->先前的指令已經(jīng)把數(shù)取到寄存器(Reg1,Reg2)中了,而這些寄存器(Reg1,Reg2)將要被ADD指令用到。當(dāng)這個任務(wù)被恢復(fù)后,ADD就是要執(zhí)行的第1條指令。這個任務(wù)不知道是否有另一個的任務(wù)會在中間時期修改Reg1或者Reg2)當(dāng)這個任務(wù)掛起時,其他任務(wù)繼續(xù)執(zhí)行,可能會修改處理器寄存器的值。在恢復(fù)之后,這個任務(wù)也不知道處理器的寄存器被修改過(altered).如果它使用這個修改過的值,就會導(dǎo)致計算的和的結(jié)果不正確。為了避免這類錯誤,必須保證,在恢復(fù)一個任務(wù)之后,其上下文環(huán)境跟即將掛起前是一樣的。操作系統(tǒng)內(nèi)核有責(zé)任通過在任務(wù)掛起前保存其上下文來確保這種狀況。當(dāng)任務(wù)恢復(fù)時,保存的上下文就被操作系統(tǒng)內(nèi)核恢復(fù)到先前的執(zhí)行情況。保存一個被掛起的任務(wù)的上下文并在任務(wù)恢復(fù)時恢復(fù)其上下文的這個處理過程就叫做上下文切換(contextswitching)實時應(yīng)用實時操作系統(tǒng)(RTOS's)通過同樣的原理達(dá)到多任務(wù)的目的。但他們的目標(biāo)與那些非實時系統(tǒng)相比是很不一樣的。不同的目標(biāo)影響到不同的調(diào)度策略。實時/嵌入式系統(tǒng)設(shè)計成提供一個對真實世界的事件的及時響應(yīng)(timelyresponse)o出現(xiàn)在真實世界中的事件可能有一個時間限制(deadline),在此期限之前,實時/嵌入式系統(tǒng)必須給出響應(yīng),RTOS調(diào)度策略必須確保時間限制是恰當(dāng)?shù)?met).為了達(dá)到這個目的,軟件工程師必須首先為每個任務(wù)設(shè)置一個優(yōu)先級(priority)oRTOS的調(diào)度策略只是簡單地確認(rèn)能被執(zhí)行的最高優(yōu)先級別的任務(wù)是分配了處理時間的任務(wù)(thetaskgivenprocessingtime)。這可能要求在相同優(yōu)先級的任務(wù)之間公平的共享處理時間,如果他們準(zhǔn)備并發(fā)運行的話。代碼示例:最基本的例子是一個由鍵盤和LCD組成的實時系統(tǒng)。用戶必須在合理的時段為每個鍵盤按下取得視覺反饋(visualfeedback).o如果用戶不能在這時段看到鍵盤按下已經(jīng)被接受,軟件產(chǎn)品將會很難使用(beawkwardtouse)。如果最長的接受期是100ms,那么在0到100ms的響應(yīng)可被接受。這個功能可以用一個下面這樣的結(jié)構(gòu)的獨立(autonomous)任務(wù)實現(xiàn):voidvKeyHandlerTask(void*pvParameters){〃鍵盤處理是一個連續(xù)的過程。就像大多實時任務(wù)那樣,這個任務(wù)〃也是用一個無限循環(huán)實現(xiàn)的。for(;;)[Suspendwaitingforakeypress][Processthekeypress]}}現(xiàn)在假設(shè)實時系統(tǒng)也執(zhí)行一個依賴數(shù)字濾波輸入的控制功能。這個輸入必須被取樣(sampled),濾波(filtered),并且每2ms執(zhí)行一次控制循環(huán)。為了讓濾波器正常操作,取樣的時間規(guī)律(thetemporalregularity)必須精確到0.5ms。這個功能可以用下面這個結(jié)構(gòu)的獨立任務(wù)實現(xiàn):voidvControlTask(void*pvParameters){for(;;){[Suspendwaitingfor2mssincethestartofthepreviouscycle][Sampletheinput][Filterthesampledinput][Performcontrolalgorithm][Outputresult]}}軟件工程師必須設(shè)置控制任務(wù)為最高的優(yōu)先級,因為:控制任務(wù)的時間限制(deadline)比鍵盤處理任務(wù)的要嚴(yán)格;控制任務(wù)錯過最后期限(deadline)的后果比鍵盤處理任務(wù)要嚴(yán)重。下面將演示這些任務(wù)是如何被實時操作系統(tǒng)調(diào)度的.
實時調(diào)度下面的圖演示前面定義的那些任務(wù)是如何被時實操作系統(tǒng)調(diào)度的。RTOS自己已經(jīng)建立了一個任務(wù)—idletask—它只在沒有其他任務(wù)執(zhí)行的時候才被執(zhí)行。R.TOSidletask總是處于可以執(zhí)行的狀態(tài)(注:也就是它不可能會因為等待什么外設(shè)資源而被阻塞,而是處于一種隨時待命的狀態(tài)).vCortrolTaskvKeyHandlerTaskIdleTask—ieTimt514t3t218t7ts讓=KeyPressEvent讓=TimerEvent上圖中vCortrolTaskvKeyHandlerTaskIdleTask—ieTimt514t3t218t7ts在最開始,我們的兩個任務(wù)都不能被執(zhí)行-vControlTask等待合適(correct)的時間開始新的控制循環(huán),vKeyHandlerTask等待鍵盤按下。處理器時間分配給RTOS的idletask.在t1時刻,一個鍵盤按下(事件)出現(xiàn).VKeyHandlerTask任務(wù)現(xiàn)在可以執(zhí)行,它比RTOS的idletask有更高的優(yōu)先級,所以處理器時間給它。在t2時刻LvKeyHandlerTask已經(jīng)完成了對按鍵的處理,并更新了LCD。它不能繼續(xù),直到另一個鍵被按下,所以必須掛起它自己。RTOSidletask又被恢復(fù)執(zhí)行。在t3時刻,一個定時器事件預(yù)示(indicates),可以執(zhí)行下一個控制循環(huán)了。VControlTask現(xiàn)在可以執(zhí)行,作為最高優(yōu)先級的任務(wù)被立刻分配(scheduled)到處理器時間。5.在t3和t4之間,當(dāng)vControlTask任務(wù)還在執(zhí)行的時候,一個鍵按下。VKeyHandlerTask不能被執(zhí)行,因為它沒有vControlTask的優(yōu)先級高。不能分配(scheduled)到任何處理器時間。在t4時刻,vControlTask完成了控制循環(huán)的處理,不能夠重新開始,直到下一個時間事件出現(xiàn),所以它自己掛起自己。而vKeyHandlerTask現(xiàn)在是最高優(yōu)先級的任務(wù),可以運行了,所以,為了處理先前的鍵盤事件,分配(scheduled)到了處理器時間.在t5時刻,鍵盤已經(jīng)被處理。VkeyHandlerTask為了等待下一個鍵盤事件,自己掛起自己?,F(xiàn)在,我們的兩個任務(wù)再度不能執(zhí)行了。RTOSidletask分配到處理器時間。在t5和t6之間,一個定時器事件被處理,但是沒有更多的鍵盤事件出現(xiàn)。下一個鍵盤按下出現(xiàn)在t6時刻,但在vKeyHandlerTask完成處理鍵之前,一個定時器事件出現(xiàn)了。現(xiàn)在兩個任務(wù)都能被執(zhí)行,而vControlTask比vKeyHandlerTask有更多的優(yōu)先級,所以vKeyHandlerTask在它完成處理鍵盤之前就被掛起了。VControlTask分配到處理器時間。在t8時刻LvControlTask完成處理控制循環(huán),掛起自己以等待下一個事件。VKeyHandlerTask再次成為最高優(yōu)先級的任務(wù),能夠運行,所以分配到處理器時間,從而鍵盤按下事件處理能夠完成。RTOS實現(xiàn)模塊(BuildingBlock)詳細(xì)實例(DetailedExample)這一節(jié)從底向上描述了RTOS上下文切換的源代碼。使用FreeRTOSAtmelAVR微控制器移植的代碼作為例子。本節(jié)的最后還一步一步地瀏覽(stepbysteplook)了一個完整的上下文切換。
C開發(fā)工具FreeRTOS的目標(biāo)是簡單且易于理解。為了達(dá)到這個目標(biāo)(Tothisend),RTOS的源代碼的大部分都是用C寫的,而不是匯編。這里演示的例子使用了WinAVRdevelopmenttools°WinAVR是一個自由/免費的在windows下的AVR交叉編譯器,它是基于GCC的。RTOSTick睡眠時,一個任務(wù)將指定多長時間后它會醒來。阻塞時,一個任務(wù)將指定一個希望最多等多久的時間。FreeRTOS實時內(nèi)核用tickcount變量來度量時間的。定時器中斷(RTOStickinterrupt)用嚴(yán)格的時間精度(temporalaccuracy)來增加tickcount允許實時內(nèi)核用一個指定的定時器中斷頻率的精度(resolution)來測量時間。每次tickcount增加后,實時內(nèi)核必須檢查,看現(xiàn)在是否解除阻塞或者喚醒一個任務(wù)。一個比被中斷的任務(wù)有更高的優(yōu)先級的任務(wù)在tickISR期間被喚醒或者解除阻塞是可能的。如果是這種情況,tickISR應(yīng)該返回到新的喚醒/解鎖的任務(wù)---實際(effectively)中斷一個任務(wù),卻返回到另一個任務(wù)。如下所述:iTickISRPseud。Code:IdleTaskvConlrcITaskvKeyHandlerTask牛TicklSR。IdleTaskvConlrcITaskvKeyHandlerTaskIncrementtickcount1lf(Tickincrementreadiedtask)Switchexecutioncontexttoreadiedtask.ReturnfromISRSwitchexecutioncontexttoreadiedtask.RTOSidletask正在運行RTOStick出現(xiàn),控制轉(zhuǎn)移到tickISR(3)RTOStickISR使得vControlTask準(zhǔn)備運行,當(dāng)vControlTask比R.TOSidletask有更高的優(yōu)先級,切換上下文到vControlTask.o現(xiàn)在的執(zhí)行上下文是vControlTask的。從ISR(4)退出返回到vControlTask,vControlTask從(5)開始執(zhí)行。以這種方式出現(xiàn)的上下文切換,稱為Preemptive。因為被中斷的任務(wù)沒有自愿(voluntarily)地掛起它自己就被搶占了(preempted)oFreeRTOS的AVR移植版本用一個在定時器1(timer1)的比較匹配(comparematch)事件來產(chǎn)生RTOStick.后續(xù)將描述RTOStickISR是如何用WinAVR開發(fā)工具實現(xiàn)的。GCC信號屬性(SignalAttribute)GCCdevelopmenttools允許用C來寫中斷程序。一個在AVR定時器1外設(shè)的比較匹配事件可以用下面的語法(syntax)實現(xiàn):voidSIG_OUTPUT_COMPARE1A(void)—attribute_((signal));voidSIG_OUTPUT_COMPARE1A(void){/*ISRCcodeforRTOStick.*/vPortYieldFromTick();}在函數(shù)原型前的'__attribute_((signal))'指示符告知編譯器,這個函數(shù)是一個ISR,會引起編譯器輸出的兩個重要改變:1.signal屬性保證,每個在ISR期間被修改的處理器的寄存器,在從ISR中退出時恢復(fù)到它原來的值。這就要求,當(dāng)中斷將要執(zhí)行時,編譯器不能做任何假定。所以,不能優(yōu)化哪個處理器寄存器要求保護(hù)或者不保護(hù)。2.'signal'也強(qiáng)制使用一個從中斷返回('returnfrominterrupt')指令(RETI),而不是返回(return)指令RET.AVR微控制器在進(jìn)入ISR前禁止中斷,RETI指令要求在退出時重新打開中斷。下面是由編譯器輸出的代碼:;voidSIG_OUTPUT_COMPARE1A(void);{;;CODEGENERATEDBYTHECOMPILERTOSAVE;THEREGISTERSTHATGETALTEREDBYTHE;APPLICATIONCODEDURINGTHEISR.PUSHR1PUSHR0INR0,0x3FPUSHR0CLRR1PUSHR18PUSHR19PUSHR20PUSHR21PUSHR22PUSHR23PUSHR24PUSHR25PUSHR26PUSHR27PUSHR30PUSHR31/;CODEGENERATEDBYTHECOMPILERFROMTHE;APPLICATIONCCODE.;vTaskIncrementTick();CALL0X0000029B;Callsubroutine;};;CODEGENERATEDBYTHECOMPILERTO;RESTORETHEREGISTERSPREVIOUSLY;SAVED.POPR31POPR30POPR27POPR26POPR25POPR24POPR23POPR22POPR21POPR20POPR19POPR18POPR0OUT0x3F,R0POPR0POPR1RETI
GCCNaked屬性前一節(jié)講述了如何在C中用signal屬性來寫一個ISR.,以及它是如何使執(zhí)行上下文自動保存的(只有那些被ISR修改過的處理器寄存器才會得到保存)。然而,執(zhí)行一個上下文切換需要保存完整的上下文應(yīng)用程序代碼能夠在進(jìn)入ISR時,明確(explicit】她保存所有寄存器,但是這樣會使某些處理器寄存器保存兩次——次是由編譯器生成的代碼,另一次是由應(yīng)用程序自己。這不是我們所需要的,可以在'signal屬性后添加’naked'屬性來避免:voidSIG_OUTPUT_COMPARE1A(void)__attribute__((signal,naked));void)voidSIG_OUTPUT_COMPARE1A(voidSIG_OUTPUT_COMPARE1A(void)/*ISRCcodeforRTOStick.*/vPortYieldFromTick();'naked'屬性阻止編譯器生成任何函數(shù)入口或退出代碼?,F(xiàn)在變異這段代碼,會得到更少的編譯器輸出:void);voidSIG_OUTPUT_COMPARE1A(void);NOCOMPILERGENERATEDCODEHERETOSAVE;THEREGISTERSTHATGETALTEREDBYTHE;ISR.;CODEGENERATEDBYTHECOMPILERFROMTHE;APPLICATIONCCODE.;vTaskIncrementTick();CALL0X0000029B;Callsubroutine;;NOCOMPILERGENERATEDCODEHERETORESTORE;THEREGISTERSORRETURNFROMTHEISR.;;}看看,入口和出口代碼都沒有了吧使用naked屬性,編譯器不會生成任何入口和出口代碼,所以必須明確(explicitly)加入。portSAVE_CONTEXT()和portRESTORE_CONTEXT()這兩個宏是用來保存和恢復(fù)完整的執(zhí)行上下文的:voidSIG_OUTPUT_COMPARE1A(void)—attribute_((signal,naked));voidSIG_OUTPUT_COMPARE1A(void){/*Macrothatexplicitlysavestheexecutioncontext.*/portSAVE_CONTEXT();/*ISRCcodeforRTOStick.*/vPortYieldFromTick();/*Macrothatexplicitlyrestorestheexecutioncontext.*/portRESTORE_CONTEXT();/*Thereturnfrominterruptcallmustalsobeexplicitlyadded.*/asmvolatile("reti");naked屬性給了應(yīng)用程序完整的控制權(quán),在何時,怎么樣保存AVR的上下文。如果應(yīng)用程序代碼在進(jìn)入ISR前保存了完整的上下文,在執(zhí)行上下文切換時不必再保存,所以不會有處理器的寄存器被保存兩次。FreeRTOSTickCodeFreeRTOS的AVR移植版本的實際源代碼與前一節(jié)的例子有些輕微的不同。VPortYieldFromTick()是作為一個naked函數(shù)的它自己的實現(xiàn),上下文在vPortYieldFromTick().里被保存和恢復(fù)。這樣做的目的是為了實現(xiàn)一個non-preemptive的上下文切換(這里,一個任務(wù)自己阻塞自己).這里暫時不講這種non-preemptive切換。RTOStick是這樣在FreeRTOS中實現(xiàn)的(看代碼中注釋片斷獲取更多細(xì)節(jié)):voidSIG_OUTPUT_COMPARE1A(void)—attribute_((signal,naked));voidvPortYieldFromTick(void)—attribute_((naked));/**//*RTOStick中斷服務(wù)程序.*/voidSIG_OUTPUT_COMPARE1A(void){/*調(diào)用tick函數(shù).*/vPortYieldFromTick();/*從中斷返回.如果出現(xiàn)上下文切換,將返回到一個不同的任務(wù)中*/asmvolatile("reti");/**/voidvPortYieldFromTick(void){/*這是一個naked函數(shù),所以需要保存上下文*/portSAVE_CONTEXT();/*增加tickcount,檢查新的tickcount值是否引起一個延遲周期過期,這個函數(shù)調(diào)用可導(dǎo)致一個任務(wù)變成準(zhǔn)備運行.*/vTaskIncrementTick();/*檢查是否要求上限文切換。如果由vTaskIncrementTick()準(zhǔn)備好的任務(wù)比已經(jīng)中斷的任務(wù)有更高優(yōu)先級,就切換過去*/vTaskSwitchContext();/*恢復(fù)上下文.如果發(fā)生了上下文切換,這將恢復(fù)要繼續(xù)運行的任務(wù)的上下文*/portRESTORE_CONTEXT();/*從這naked函數(shù)返回.*/asmvolatile("ret");}/**/TheAVRContext上下文切換要求保存完整的上下文。在AVRMCU中,上下文包括32位通用寄存器。Gcc開發(fā)工具假定寄存器R1設(shè)定為0狀態(tài)寄存器。狀態(tài)寄存器的值影響指令的執(zhí)行,必須通過上下文切換保存(preserved)程序計數(shù)器(PC).恢復(fù)執(zhí)行后,一個任務(wù)必須從上次被掛起的地方繼續(xù)執(zhí)行。(ataskmustc
ontinueexecutionfromtheinstructionthatwasabouttobeexecutedimmediatelypriortoitssuspension.)4.兩個stack指針寄存器lIExecutionContextSavingtheContext每個時實任務(wù)都有它自己的stack內(nèi)存區(qū)域,所以上下文可簡單的通過將寄存器壓入到任務(wù)棧來保存上下文。保存AVR的上下文是一個不可避免的要使用到匯編語言的地方。portSAVE_CONTEXT()是作為一個宏來實現(xiàn)的,源代碼在下面給出
#defineportSAVE_CONTEXT()\asmvolatile(\"pushr0\n\t"\(1)"inr0,__SREG_\n\t"\(2)"cli\n\t"\(3)"pushr0\n\t"\(4)"pushr1\n\t"\(5)"clrr1\n\t"\(6)"pushr2\n\t"\(7)"pushr3\n\t"\"pushr4\n\t"\"pushr5\n\t"\"pushr30\n\t"\"pushr31\n\t"\"ldsr26,pxCurrentTCB\n\t"\(8)"ldsr27,pxCurrentTCB+1\n\t"\(9)"inr0,__SP_L_\n\t"\(10)"stx+,r0\n\t"\(11)"inr0,__SP_H_\n\t"\(12)"stx+,r0\n\t"\(13)在上面的源代碼中:1.寄存器R0首先被保存,因為當(dāng)狀態(tài)寄存器被保存時,它會被用到。所以必須先把它的原始值保存下來。狀態(tài)寄存器被搬移到R0(2),所以它能保存到stack(4)禁止處理器中斷。如果portSAVE_CONTEXT(),只是從ISR中調(diào)用,就不需要明確的禁止中斷,因為AVR已經(jīng)這么做了。portSAVE_CONTEXT()宏用在中斷服務(wù)程序的外部(一個任務(wù)自己掛起自己的時候),中斷應(yīng)該盡可能早的明確清除(也就是禁止中斷CLI)從ISR的C源代碼中,由編譯器生成的代碼假定R1被設(shè)置為0。R1的原始值在R1被清除(6)前保存(5)在(7)和(8),所有寄存器都被按順序保存現(xiàn)在被掛起的任務(wù)的棧中還有一個任務(wù)執(zhí)行上下文的拷貝。內(nèi)核保存任務(wù)的棧指針,所以當(dāng)任務(wù)恢復(fù)執(zhí)行時,上下文可以取得并恢復(fù)。TheXprocessorregisterisloadedwiththeaddresstowhichthestackpointeristobesaved(8and9).載入棧指針棧指針保存,先低位(10,11)后高位(1213)RestoringtheContextportRESTORE_CONTEXT。是portSAVE_CONTEXT().的逆過程。要恢復(fù)執(zhí)行的任務(wù)的上下文被預(yù)先存儲到任務(wù)棧中。實時內(nèi)核為該任務(wù)取得棧指針,然后彈出POP上下文到正確的寄存器中。#defineportRESTORE_CONTEXT()\asmvolatile("ldsr26,pxCurrentTCB\n\t"\(1)"ldsr27,pxCurrentTCB+1\n\t"\(2)"ldr28,x+\n\t"\"out__SP_L__,r28\n\t"\(3)"ldr29,x+\n\t"\"out__SP_H__,r29\n\t"\(4)"popr31\n\t"\popr30\n\t"\TOC\o"1-5"\h\z"popr1\n\t"\"popr0\n\t"\(5)"out__SREG__,r0\n\t"\(6)"popr0\n\t"\(7));上面的代碼中:pxCurrentTCB含有任務(wù)棧指針被取得的地址。這被載入到X寄存器(1和2)被恢復(fù)的任務(wù)的棧指針載入到AVR的stackpointer,先低字節(jié)(3),后高半字節(jié)nibble(4)寄存器以相反的順序從棧中,一直到R1狀態(tài)寄存其保存在stack中的位置是在R1和R0之間,所以,它在R0(7)前重新恢復(fù)(6)下面介紹一個完整的上下文切換的例子連起來(PuttingItAllTogether)在第2節(jié)的最后一部分展示了這些積木模塊(buildingblocks)和源代碼模塊(sourcecodemodules)使如何來達(dá)到一個在AVR微控制器上進(jìn)行RTOS上下文切換的目的的。這個例子分幾步演示了從一個低的優(yōu)先級的任務(wù)TaskA,切換到高優(yōu)先級的任務(wù)TaskB的。源代碼與WinAVRC開發(fā)工具兼容。上下文切換-第1步在RTOStick中斷發(fā)生之前這個例子,以TaskA的執(zhí)行開始。TaskB先前已經(jīng)被掛起,所以它的上下文已經(jīng)被保存到TaskB的stack里面。
TaskA的上下文如下圖所示:在每個寄存器里標(biāo)上(A),表示,這寄存器含有任務(wù)A的上下文的正確值。上下文切換一第2步RTOStick中斷發(fā)生了當(dāng)TaskA將要執(zhí)行到一個LDI指令的時候,RTOStick發(fā)生。當(dāng)中斷發(fā)生時,AVR微控制器會在跳入到RTOSticklSR之前,自動放置當(dāng)前的PC到stack里面?!睢睢钪R是人類進(jìn)步的階梯☆☆☆上下文切換第3步RTOStick中斷(服務(wù))執(zhí)行ISR源代碼如下。為便于閱讀,移除注釋。/*InterruptserviceroutinefortheRTOStick.*/voidSIG_OUTPUT_COMPARE1A(void){vPortYieldFromTick();asmvolatile("reti");}/**/voidvPortYieldFromTick(void){portSAVE_CONTEXT();vTaskIncrementTick();vTaskSwitchContext();portRESTORE_CONTEXT();asmvolatile("ret");}/**/SIG_OUTPUT_COMPARE1A()是一個naked函數(shù)。所以第一條指令是調(diào)用vPortYieldFromTick()..vPortYieldFromTick()也是一個naked函數(shù),所以AVR執(zhí)行上下文被portSAVE_CONTEXT().明確保存。portSAVE_C
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024院子買賣合同范本(含裝修)3篇
- 2025年度智能農(nóng)田除草機(jī)械化服務(wù)合同4篇
- 2024自動駕駛測試司機(jī)試驗合同
- 2024起重機(jī)租賃合同:含特種設(shè)備檢測與認(rèn)證服務(wù)3篇
- 2025年度果樹觀光園果樹租賃經(jīng)營合同范本3篇
- 2024虛擬現(xiàn)實技術(shù)托管服務(wù)合同
- 2025年度彩鋼構(gòu)件回收與再利用合同3篇
- 2024版軟件開發(fā)項目分包協(xié)議3篇
- 2025年度商業(yè)地產(chǎn)租賃合同示范文本11篇
- 2025年度智慧城市建設(shè)承包經(jīng)營合同范本3篇
- 軟件項目應(yīng)急措施及方案
- 2025河北邯鄲經(jīng)開國控資產(chǎn)運營管理限公司招聘專業(yè)技術(shù)人才5名高頻重點提升(共500題)附帶答案詳解
- 2024年民法典知識競賽考試題庫及答案(共50題)
- 2025老年公寓合同管理制度
- 2024-2025學(xué)年人教版數(shù)學(xué)六年級上冊 期末綜合卷(含答案)
- 2024中國汽車后市場年度發(fā)展報告
- 鈑金設(shè)備操作培訓(xùn)
- 感染性腹瀉的護(hù)理查房
- 天津市部分區(qū)2023-2024學(xué)年高二上學(xué)期期末考試 物理 含解析
- 水利工程招標(biāo)文件樣本
- 第17課 西晉的短暫統(tǒng)一和北方各族的內(nèi)遷(說課稿)-2024-2025學(xué)年七年級歷史上冊素養(yǎng)提升說課稿(統(tǒng)編版2024)
評論
0/150
提交評論