1. 程式人生 > >FreeRTOS(7)---FreeRTOS 核心控制

FreeRTOS(7)---FreeRTOS 核心控制

FreeRTOS 核心控制

核心控制的一些功能需要移植層提供,為了方便移植,這些API函式用巨集來實現,比如上下文切換、進入和退出臨界區、禁止和使能可遮蔽中斷。核心控制函式還包括啟動和停止排程器、掛起和恢復排程器以及用於低功耗模式的調整系統節拍函式。

強制上下文切換巨集

  • taskYIELD:用於強制上下文切換的巨集。在中斷服務程式中的等價版本為portYIELD_FROM_ISR,這也是個巨集,其實現取決於移植層。

用於上下文切換的實際程式碼由移植層提供。對於Cortex-M3硬體,這個巨集會引起PendSV中斷。

進入臨界區巨集

  • taskENTER_CRITICAL:用於進入臨界區的巨集。在臨界區中不會發生上下文切換。

進入臨界區的實際程式碼由移植層提供,對於Cortex-M3硬體,先禁止所有RTOS可遮蔽中斷,這可以通過向basepri 暫存器寫入configMAX_SYSCALL_INTERRUPT_PRIORITY來實現。basepri暫存器被設定成某個值後,所有優先順序號大於等於此值的中斷都被禁止,但若被設定為0,則不關閉任何中斷,0為預設值。然後臨界區巢狀計數器增1。

退出臨界區巨集

  • taskEXIT_CRITICAL:用於退出臨界區的巨集。

退出臨界區的實際程式碼有移植層提供,對於Cortex-M3硬體,先將臨界區巢狀計數器減1,如果臨界區計數器為零,則使能所有RTOS可遮蔽中斷,這可以通過向basepri 暫存器寫入0來實現。

禁止可遮蔽中斷巨集

  • taskDISABLE_INTERRUPTS:禁止所有RTOS可遮蔽中斷。在呼叫巨集taskENTER_CRITICAL進入臨界區時,也會間接呼叫該巨集禁止所有RTOS可遮蔽中斷。

使能可遮蔽中斷巨集

  • taskENABLE_INTERRUPTS:使能所有RTOS可遮蔽中斷。在呼叫巨集taskEXIT_CRITICAL退出臨界區時,也會間接呼叫該巨集使能所有RTOS可遮蔽中斷。

啟動排程器

函式描述

void vTaskStartScheduler( void );      

啟動RTOS排程器,之後RTOS核心控制哪個任務執行以及何時執行。

當呼叫vTaskStartScheduler()後,空閒任務被自動建立。如果configUSE_TIMERS被設定為1,定時器後臺任務也會被建立。 如果vTaskStartScheduler()成功執行,則該函式不會返回,直到有任務呼叫了vTaskEndScheduler()。如果因為RAM不足而無法建立空閒任務,該函式也可能執行失敗,並會立刻返回呼叫處。

停止排程器

函式描述

void vTaskEndScheduler( void );      

僅用於x86硬體架構中。

停止RTOS核心系統節拍時鐘。所有建立的任務自動刪除並停止多工排程。

掛起排程器

函式描述

掛起排程器,但不禁止中斷。當排程器掛起時,不會進行上下文切換。排程器掛起後,正在執行的任務會一直繼續執行,核心不再排程(意味著當前任務不會被切換出去),直到該任務呼叫了xTaskResumeAll ()函式。

核心排程器掛起期間,那些可以引起上下文切換的API函式(如vTaskDelayUntil()、xQueueSend()等)決不可使用。

恢復被掛起的排程器

函式描述

BaseType_t xTaskResumeAll( void );     

恢復因呼叫vTaskSuspendAll()函式而掛起的實時核心排程器。xTaskResumeAll()僅恢復排程器,它不會恢復那些被vTaskSuspend()函式掛起的任務。

返回值

返回pdTRUE 表示恢復排程器引起了一次上下文切換,否則,返回pdFALSE。

用法舉例

voidvTask1( void * pvParameters )
 {
     for( ;; )
     {
         /* 任務程式碼寫在這裡 */
 
         /* ... */
 
         /* 有些時候,某個任務希望可以連續長時間的執行,但這時不能使用taskENTER_CRITICAL ()/taskEXIT_CRITICAL ()的方法,這樣會遮蔽掉中斷,引起中斷丟失,包括系統節拍時鐘。可以使用vTaskSuspendAll ()停止RTOS核心排程:*/
         xTaskSuspendAll ();
 
         /* 執行操作程式碼放在這裡。這樣不用進入臨界區就可以連續長時間執行了。在這期間,中斷仍然會得到響應,RTOS核心系統節拍時鐘也會繼續保持運作 */
 
         /* ... */
 
         /* 操作結束,重新啟動RTOS核心 。我們想強制進行一次上下文切換,但是如果恢復排程器的時候已經執行了上下文切換,再執行一次是沒有意義的,因此會進行一次判斷。*/
         if( !xTaskResumeAll () )
         {
              taskYIELD ();
         }
     }
 }

調整系統節拍

函式描述

void vTaskStepTick( TickType_txTicksToJump );      

如果RTOS使能tickless空閒功能,每當只有空閒任務被執行時,系統節拍時鐘中斷將會停止,微控制器進入低功耗模式。當微控制器退出低功耗後,系統節拍計數器必須被調整,將進入低功耗的時間彌補上。

如果FreeRTOS移植檔案中定義了巨集portSUPPRESS_TICKS_AND_SLEEP()實體,則函式vTaskStepTick用於在這個巨集portSUPPRESS_TICKS_AND_SLEEP()實體內部調整系統節拍計數器。函式vTaskStepTick是一個全域性函式,所以也可以在巨集portSUPPRESS_TICKS_AND_SLEEP()實體中重寫該函式。

在檔案FreeRTOSConfig.h中,巨集configUSE_TICKLESS_IDLE必須設定為1,此函式才有效。

引數描述

  • xTickToJump:時間值,單位是系統節拍週期,表示微處理器進入低功耗的時間,函式根據這個值來調整系統節拍計數器的值。

用法舉例

/* 首先定義巨集portSUPPRESS_TICKS_AND_SLEEP()。巨集引數指定要進入低功耗(睡眠)的時間,單位是系統節拍週期。*/
#defineportSUPPRESS_TICKS_AND_SLEEP( xIdleTime ) vApplicationSleep( xIdleTime )
 
/* 定義被巨集portSUPPRESS_TICKS_AND_SLEEP()呼叫的函式 */
void vApplicationSleep(TickType_t xExpectedIdleTime )
{
    unsigned long ulLowPowerTimeBeforeSleep,ulLowPowerTimeAfterSleep;
 
    /* 從時鐘源獲取當前時間,當微控制器進入低功耗的時候,這個時鐘源必須在執行 */
    ulLowPowerTimeBeforeSleep =ulGetExternalTime();
 
    /*停止系統節拍時鐘中斷。*/
    prvStopTickInterruptTimer();
 
    /* 配置一箇中斷,當指定的睡眠時間達到後,將處理器從低功耗中喚醒。這個中斷源必須在微控制器進入低功耗時也可以工作。*/
    vSetWakeTimeInterrupt( xExpectedIdleTime );
 
    /*進入低功耗 */
    prvSleep();
 
    /* 確定微控制器進入低功耗模式持續的真正時間。因為其它中斷也可能使得微處理器退出低功耗模式。注意:在呼叫巨集portSUPPRESS_TICKS_AND_SLEEP()之前,排程器應該被掛起,portSUPPRESS_TICKS_AND_SLEEP()返回後,再將排程器恢復。因此,這個函式未完成前,不會執行其它任務。*/
    ulLowPowerTimeAfterSleep =ulGetExternalTime();
        
    /*調整核心系統節拍計數器。*/
    vTaskStepTick( ulLowPowerTimeAfterSleep –ulLowPowerTimeBeforeSleep );
 
    /*重新啟動系統節拍時鐘中斷。*/
    prvStartTickInterruptTimer();
}