經過上一節的介紹,我們已經清晰了任務堆棧初始化后任務堆棧的內容,及啟動任務時如何將堆棧內容恢復并跳轉到任務函數。那么本節接著介紹任務切換,任務切換決定了任務的執行順序,包括如優先級高的任務打斷優先級低的任務和同等優先級任務的時間片調度等。
任務切換可以在兩種情況下進行,一種是執行一個系統調用,如直接調用引起任務切換的API函數,比如任務切換函數taskYIELD()。另一種是在滴答定時器Timer1中斷中執行任務切換。無論哪種方法,最終實際都是調用portYIELD()函數來實現的。為了深刻理解這個切換過程,我們有必要再一次回顧涉及到的基本匯編語法。
我們首先看下portmacro.h中portYIELD()的宏定義,可以看出這里有個CALL語句,所以當前任務下一PC 執行地址將自動壓棧。
接著我們看一下CALL調用的子函數vPortYield的內容,可以很容易的看出其首先按照堆棧初始化的方式進行壓棧,直到壓完uxCriticalNesting后將棧頂賦值給當前任務的TCB第一個成員變量pxTopOfStack;然受調用vTaskSwitchContext()來獲取下一個要運行的任務(如存在高優先級的任務),明確該任務堆棧的棧頂指針,先出棧uxCriticalNesting,然后接著順序出棧直到出棧SR,最后借助return匯編語句跳轉到下一個要運行任務的任務函數。
最后在介紹一下時間片調度。FreeRTOS支持多個任務同時擁有一個優先級,同時允許一個任務運行一個時間片(一個時鐘節拍的長度)后讓出CPU的使用權,讓擁有同一個優先級的下一個任務運行。任務是否切換這是通過滴答定時器中斷中的xTaskIncrementTick()來判斷的,并且只有當configUSE_PREEMPTION和configUSE_TIME_SLICING都為1的時候才允許進行時間片調度。在xTaskIncrementTick()中會判斷當前任務的優先級下是否還有其他任務,如果有則返回pdTRUE,執行一次任務切換。
至此已經講完了FreeRTOS在dsPIC33C系列芯片移植的所有內容,已經可以跑起來FreeRTOS的開發環境了,剩下的就是找一本講解FreeRTOS的書,逐步了解FreeRTOS自身的知識點,邊動手邊思考,相信大家一定可以將FreeRTOS熟練應用到后續的項目中去。
額外的,還需要注意的是在例程中我定義了三個宏,通過這些宏可以區分port.c、portasm_dsPIC.S是針對dsPIC33C還是針對PIC24等。換句話說這個移植不僅針對于dsPIC33CK系列芯片,它更適用于Microchip全系16位MCU芯片。