第四章 FreeRTOS內核控制

目錄

taskYIELD

taskENTER_CRITICAL()taskEXIT_CRITICAL()

taskENTER_CRITICAL_FROM_ISR()taskEXIT_CRITICAL_FROM_ISR()

taskDISABLE_INTERRUPTS()

taskENABLE_INTERRUPTS()

vTaskStartScheduler

vTaskEndScheduler

vTaskSuspendAll

xTaskResumeAll

vTaskStepTick

xTaskCatchUpTicks


 


taskYIELD

 

taskYIELD()用於請求將上下文切換到另一個任務。但是,如果沒有其他任務比調用taskYIELD()的任務具有更高或更高的優先級,則RTOS調度程序將簡單地選擇名爲taskYIELD()的任務以再次運行。

如果configUSE_PREEMPTION 設置爲1,則RTOS調度程序將始終運行能夠運行的最高優先級任務,因此調用taskYIELD()將永遠不會導致切換到更高優先級的任務。


taskENTER_CRITICAL()
taskEXIT_CRITICAL()

void taskENTER_CRITICAL( void );
void taskEXIT_CRITICAL( void );

通過調用taskENTER_CRITICAL()輸入關鍵部分,然後通過調用taskEXIT_CRITICAL()退出關鍵部分。taskENTER_CRITICAL()和taskEXIT_CRITICAL()宏提供了一個基本的臨界區實現,可以通過簡單地全局禁用中斷或最高特定中斷優先級來禁用中斷。有關在 不禁用中斷的情況下創建關鍵部分的信息,請參見vTaskSuspendAll() RTOS API函數。

如果正在使用的FreeRTOS端口未使用 configMAX_SYSCALL_INTERRUPT_PRIORITY 內核配置常量(也稱爲

configMAX_API_CALL_INTERRUPT_PRIORITY),則調用taskENTER_CRITICAL()將使中斷全局禁用。如果使用的FreeRTOS端口確實使用了configMAX_SYSCALL_INTERRUPT_PRIORITY內核配置常量,則調用taskENTER_CRITICAL()將使中斷處於configMAX_SYSCALL_INTERRUPT_PRIORITY設置的中斷優先級及以下,並禁用所有優先級較高的中斷。

搶佔式上下文切換僅在中斷內部發生,因此在禁用中斷時不會發生。因此,除非任務顯式嘗試阻止或屈服(它不應在關鍵部分內部執行此操作),否則確保稱爲taskENTER_CRITICAL()的任務將保持在運行狀態,直到退出關鍵部分爲止。

對taskENTER_CRITICAL()和taskEXIT_CRITICAL()的調用被設計爲嵌套。因此,僅當對taskENTER_CRITICAL()的每個先前調用都執行了對taskEXIT_CRITICAL()的調用時,纔會退出關鍵部分。

關鍵部分必須保持很短,否則將對中斷響應時間產生不利影響。每次對taskENTER_CRITICAL()的調用都必須與對taskEXIT_CRITICAL()的調用緊密配對。

不得從關鍵部分調用FreeRTOS API函數。

不得從中斷服務程序(ISR)調用taskENTER_CRITICAL() 和taskEXIT_CRITICAL()–有關等效的中斷安全信息,請參閱 taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()。

參數:

沒有  

返回值:

沒有


用法示例:

/* A function that makes use of a critical section. */
void vDemoFunction( void )
{
    /* Enter the critical section.  In this example, this function is itself called
    from within a critical section, so entering this critical section will result
    in a nesting depth of 2. */
    taskENTER_CRITICAL();

    /* Perform the action that is being protected by the critical section here. */

    /* Exit the critical section.  In this example, this function is itself called
    from a critical section, so this call to taskEXIT_CRITICAL() will decrement the
    nesting count by one, but not result in interrupts becoming enabled. */
    taskEXIT_CRITICAL();
}

/* A task that calls vDemoFunction() from within a critical section. */
void vTask1( void * pvParameters )
{
    for( ;; )
    {
        /* Perform some functionality here. */

        /* Call taskENTER_CRITICAL() to create a critical section. */
        taskENTER_CRITICAL();


        /* Execute the code that requires the critical section here. */


        /* Calls to taskENTER_CRITICAL() can be nested so it is safe to call a
        function that includes its own calls to taskENTER_CRITICAL() and
        taskEXIT_CRITICAL(). */
        vDemoFunction();

        /* The operation that required the critical section is complete so exit the
        critical section.  After this call to taskEXIT_CRITICAL(), the nesting depth
        will be zero, so interrupts will have been re-enabled. */
        taskEXIT_CRITICAL();
    }
}

taskENTER_CRITICAL_FROM_ISR()
taskEXIT_CRITICAL_FROM_ISR()

UBaseType_t taskENTER_CRITICAL_FROM_ISR( void );
void taskEXIT_CRITICAL_FROM_ISR( UBaseType_t uxSavedInterruptStatus );

可以在中斷服務程序(ISR)中使用 的taskENTER_CRITICAL()和taskEXIT_CRITICAL()的版本。

在ISR中,通過調用taskENTER_CRITICAL_FROM_ISR()進入關鍵部分,然後通過調用taskEXIT_CRITICAL_FROM_ISR()退出關鍵部分。

taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()宏提供了一個基本的臨界區實現,可以通過簡單地全局禁用中斷或在特定中斷優先級上禁用中斷來工作。

如果FreeRTOS的端口被用於支持中斷,並在下面被中斷優先級組嵌套然後調用taskENTER_CRITICAL_FROM_ISR()將禁止中斷configMAX_SYSCALL_INTERRUPT_PRIORITY (或configMAX_API_CALL_INTERRUPT_PRIORITY)內核配置不變,並啓用所有其他中斷優先級。如果使用的FreeRTOS端口不支持中斷嵌套,則taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()將無效。

對taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()的調用被設計爲嵌套,但是如何使用宏的語義與taskENTER_CRITICAL()和taskEXIT_CRITICAL()等效。

關鍵部分必須保持非常短,否則它們將對優先級較高的中斷的響應時間產生不利影響,否則該中斷將嵌套。每次對taskENTER_CRITICAL_FROM_ISR()的調用都必須與對taskEXIT_CRITICAL_FROM_ISR()的調用緊密配對。

不得從關鍵部分調用FreeRTOS API函數。

參數:

uxSavedInterruptStatus taskEXIT_CRITICAL_FROM_ISR()將uxSavedInterruptStatus作爲其唯一參數。用作uxSavedInterruptStatus參數的值必須是從對taskENTER_CRITICAL_FROM_ISR()的匹配調用返回的值。

taskENTER_CRITICAL_FROM_ISR()不接受任何參數。

返回值:

taskENTER_CRITICAL_FROM_ISR()返回中斷屏蔽狀態,與調用宏之前一樣。在對taskEXIT_CRITICAL_FROM_ISR()的匹配調用中,必須將taskENTER_CRITICAL_FROM_ISR()返回的值用作uxSavedInterruptStatus參數。

taskEXIT_CRITICAL_FROM_ISR()不返回值。

/* A function called from an ISR. */
void vDemoFunction( void )
{
UBaseType_t uxSavedInterruptStatus;

    /* Enter the critical section.  In this example, this function is itself called from
    within a critical section, so entering this critical section will result in a nesting
    depth of 2. Save the value returned by taskENTER_CRITICAL_FROM_ISR() into a local
    stack variable so it can be passed into taskEXIT_CRITICAL_FROM_ISR(). */
    uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();

    /* Perform the action that is being protected by the critical section here. */

    /* Exit the critical section.  In this example, this function is itself called from a
    critical section, so interrupts will have already been disabled before a value was
    stored in uxSavedInterruptStatus, and therefore passing uxSavedInterruptStatus into
    taskEXIT_CRITICAL_FROM_ISR() will not result in interrupts being re-enabled. */
    taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
}

/* A task that calls vDemoFunction() from within an interrupt service routine. */
void vDemoISR( void )
{
UBaseType_t uxSavedInterruptStatus;

    /* Call taskENTER_CRITICAL_FROM_ISR() to create a critical section, saving the
    returned value into a local stack variable. */
    uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();


    /* Execute the code that requires the critical section here. */


    /* Calls to taskENTER_CRITICAL_FROM_ISR() can be nested so it is safe to call a
    function that includes its own calls to taskENTER_CRITICAL_FROM_ISR() and
    taskEXIT_CRITICAL_FROM_ISR(). */
    vDemoFunction();

    /* The operation that required the critical section is complete so exit the
    critical section.  Assuming interrupts were enabled on entry to this ISR, the value
    saved in uxSavedInterruptStatus will result in interrupts being re-enabled.*/
    taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
}

taskDISABLE_INTERRUPTS()

如果所採用的端口支持configMAX_SYSCALL_INTERRUPT_PRIORITY(或configMAX_API_CALL_INTERRUPT_PRIORITY)恆定,那麼taskDISABLE_INTERRUPTS要麼禁止所有中斷,或掩蔽(禁用)中斷到configMAX_SYSCALL_INTERRUPT_PRIORITY設置。檢查正在使用的端口的taskDISABLE_INTERRUPTS的實現。

如果使用的端口不支持configMAX_SYSCALL_INTERRUPT_PRIORITY常量,則taskDISABLE_INTERRUPTS()將全局禁用所有可屏蔽中斷。通常,不會直接調用此宏,而應在其位置使用taskENTER_CRITICAL()和taskEXIT_CRITICAL()。


taskENABLE_INTERRUPTS()

啓用微控制器中斷的宏。

通常,不會直接調用此宏,而應在其位置使用taskENTER_CRITICAL()和taskEXIT_CRITICAL()。

 


vTaskStartScheduler

vTaskStartScheduler(void);

啓動RTOS調度程序。調用RTOS內核後,可以控制執行哪些任務以及何時執行。

在空閒任務和可選的 定時器守護任務的RTOS調度程序啓動時自動創建。

僅當沒有足夠的RTOS堆來創建空閒或計時器守護程序任務時,vTaskStartScheduler()纔會返回。

所有RTOS演示應用程序項目都包含使用vTaskStartScheduler()的示例,通常在main.c的main()函數中。

用法示例:

void vAFunction( void )
 {
     // Tasks can be created before or after starting the RTOS
     scheduler
     xTaskCreate( vTaskCode,
                  "NAME",
                  STACK_SIZE,
                  NULL,
                  tskIDLE_PRIORITY,
                  NULL );

     // Start the real time scheduler.
     vTaskStartScheduler();

     // Will not get here unless there is insufficient RAM.
 }

vTaskEndScheduler

void vTaskEndScheduler( void );
 

 

注意:這僅適用於x86實模式PC端口。

停止RTOS內核滴答。所有創建的任務將被自動刪除,並且多任務處理(搶佔式或協作式)將停止。然後,從調用vTaskStartScheduler()的點繼續執行,就好像vTaskStartScheduler()剛剛返回一樣。

請參閱演示應用程序文件主體。有關使用vTaskEndScheduler()的示例,請參見demo / PC目錄中的c。

vTaskEndScheduler()要求在可移植層中定義退出功能(有關PC端口,請參見端口c中的vPortEndScheduler())。這將執行特定於硬件的操作,例如停止RTOS內核滴答。

vTaskEndScheduler()將導致釋放RTOS內核分配的所有資源-但不會釋放應用程序任務分配的資源。

用法示例:


 void vTaskCode( void * pvParameters )
 {
     for( ;; )
     {
         // Task code goes here.

         // At some point we want to end the real time kernel processing 
         // so call ...
         vTaskEndScheduler ();
     }
 }

 void vAFunction( void )
 {
     // Create at least one task before starting the RTOS kernel.
     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );

     // Start the real time kernel with preemption.
     vTaskStartScheduler();

     // Will only get here when the vTaskCode () task has called 
     // vTaskEndScheduler ().  When we get here we are back to single task 
     // execution.
 }

vTaskSuspendAll

void vTaskSuspendAll( void );
 
 

掛起調度程序。掛起調度程序可以防止發生上下文切換,但可以使中斷保持啓用狀態。如果在掛起調度程序時中斷請求上下文切換,則該請求將保持掛起狀態,並且僅在重新啓動調度程序(未掛起)時才執行該請求。

調用xTaskResumeAll()過渡調度出掛起狀態下一次調用vTaskSuspendAll()。

可以嵌套對vTaskSuspendAll()的調用。在調度程序將退出“掛起”狀態並重新進入“活動”狀態之前,必須對xTaskResumeAll()進行與先前對vTaskSuspendAll()相同的調用。

xTaskResumeAll()只能從正在執行的任務中調用,因此,在調度程序處於初始化狀態(在啓動調度程序之前)時,不得調用xTaskResumeAll()。

調度程序掛起時,不得調用其他FreeRTOS API函數。

掛起調度程序時,不得調用可能導致上下文切換的API函數(例如vTaskDelayUntil(),xQueueSend()等)。

用法示例:

/* A function that suspends then resumes the scheduler. */
void vDemoFunction( void )
{
    /* This function suspends the scheduler.  When it is called from vTask1 the 
    scheduler is already suspended, so this call creates a nesting depth of 2. */
    vTaskSuspendAll();
        
    /* Perform an action here. */
        
    /* As calls to vTaskSuspendAll() are nested, resuming the scheduler here will 
    not cause the scheduler to re-enter the active state. */
    xTaskResumeAll();
}


void vTask1( void * pvParameters )
{
    for( ;; )
    {
        /* Perform some actions here. */
            
        /* At some point the task wants to perform an operation during which it does 
        not want to get swapped out, or it wants to access data which is also 
        accessed from another task (but not from an interrupt).  It cannot use
        taskENTER_CRITICAL()/taskEXIT_CRITICAL() as the length of the operation may
        cause interrupts to be missed. */
            

        /* Prevent the scheduler from performing a context switch. */
        vTaskSuspendAll();
            

        /* Perform the operation here.  There is no need to use critical sections as 
        the task has all the processing time other than that utilized by interrupt 
        service routines.*/           
            
            
        /* Calls to vTaskSuspendAll() can be nested so it is safe to call a (non API) 
        function which also contains calls to vTaskSuspendAll().  API functions 
        should not be called while the scheduler is suspended. */
        vDemoFunction();

            
        /* The operation is complete.  Set the scheduler back into the Active 
        state. */
        if( xTaskResumeAll() == pdTRUE )
        {
            /* A context switch occurred within xTaskResumeAll(). */
        }
        else
        {
            /* A context switch did not occur within xTaskResumeAll(). */
        }
    }
}

xTaskResumeAll

BaseType_t xTaskResumeAll(void);
 

使用對vTaskSuspendAll()的調用在掛起調度程序後繼續。

xTaskResumeAll()僅恢復調度程序。它不會取消暫停先前通過調用vTaskSuspend()而暫停的任務。

返回值:

如果恢復調度程序導致上下文切換,則返回pdTRUE,否則返回pdFALSE。

用法示例:
 void vTask1( void * pvParameters )
 {
     for( ;; )
     {
         /* Task code goes here. */

         /* ... */

         /* At some point the task wants to perform a long operation
         during which it does not want to get swapped out.  It cannot
         use taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length
         of the operation may cause interrupts to be missed -
         including the ticks.

         Prevent the RTOS kernel swapping out the task. */
         vTaskSuspendAll();

         /* Perform the operation here.  There is no need to use critical
         sections as we have all the microcontroller processing time.
         During this time interrupts will still operate and the real
         time RTOS kernel tick count will be maintained. */

         /* ... */

         /* The operation is complete.  Restart the RTOS kernel.  We want to force
         a context switch - but there is no point if resuming the scheduler
         caused a context switch already. */
         if( !xTaskResumeAll () )
         {
              taskYIELD ();
         }
     }
 }

vTaskStepTick

 void vTaskStepTick( TickType_t xTicksToJump );

如果將RTOS配置爲使用無滴答空閒功能, 則只要空閒任務是唯一能夠執行的任務,滴答中斷就會停止,微控制器進入低功耗狀態。退出低功耗狀態後,必須校正滴答計數值,以說明停止時經過的時間。

如果FreeRTOS端口包括默認的portSUPPRESS_TICKS_AND_SLEEP() 實現,則內部將使用vTaskStepTick()來確保維護正確的滴答計數值。vTaskStepTick()是公共API函數,它允許覆蓋默認的portSUPPRESS_TICKS_AND_SLEEP()實現,如果使用的端口不提供默認值,則可以提供portSUPPRESS_TICKS_AND_SLEEP()。

必須將configUSE_TICKLESS_IDLE配置常量設置爲1,vTaskStepTick()纔可用。

參數:

xTicksToJump   自滴答中斷停止以來已過去的RTOS滴答次數。爲了正確操作,該參數必須小於或等於portSUPPRESS_TICKS_AND_SLEEP()參數。

返回值:

沒有。

用法示例:

該示例顯示了對多個函數的調用。只有vTaskStepTick()是FreeRTOS API的一部分。其他功能特定於正在使用的硬件上可用的時鐘和省電模式,因此必須由應用程序編寫器提供。

/* First define the portSUPPRESS_TICKS_AND_SLEEP().  The parameter is the time,
in ticks, until the kernel next needs to execute. */
#define portSUPPRESS_TICKS_AND_SLEEP( xIdleTime ) vApplicationSleep( xIdleTime )

/* Define the function that is called by portSUPPRESS_TICKS_AND_SLEEP(). */
void vApplicationSleep( TickType_t xExpectedIdleTime )
{
unsigned long ulLowPowerTimeBeforeSleep, ulLowPowerTimeAfterSleep;

    /* Read the current time from a time source that will remain operational
    while the microcontroller is in a low power state. */
    ulLowPowerTimeBeforeSleep = ulGetExternalTime();

    /* Stop the timer that is generating the tick interrupt. */
    prvStopTickInterruptTimer();

    /* Configure an interrupt to bring the microcontroller out of its low power
    state at the time the kernel next needs to execute.  The interrupt must be
    generated from a source that is remains operational when the microcontroller
    is in a low power state. */
    vSetWakeTimeInterrupt( xExpectedIdleTime );

    /* Enter the low power state. */
    prvSleep();

    /* Determine how long the microcontroller was actually in a low power state
    for, which will be less than xExpectedIdleTime if the microcontroller was
    brought out of low power mode by an interrupt other than that configured by
    the vSetWakeTimeInterrupt() call.  Note that the scheduler is suspended
    before portSUPPRESS_TICKS_AND_SLEEP() is called, and resumed when
    portSUPPRESS_TICKS_AND_SLEEP() returns.  Therefore no other tasks will
    execute until this function completes. */
    ulLowPowerTimeAfterSleep = ulGetExternalTime();

    /* Correct the kernels tick count to account for the time the microcontroller
    spent in its low power state. */
    vTaskStepTick( ulLowPowerTimeAfterSleep - ulLowPowerTimeBeforeSleep );

    /* Restart the timer that is generating the tick interrupt. */
    prvStartTickInterruptTimer();
}

xTaskCatchUpTicks

BaseType_t xTaskCatchUpTicks(TickType_t xTicksToCatchUp);
在應用程序代碼將中斷長時間禁用後,更正滴答計數值。此函數與vTaskStepTick()類似,但是,與vTaskStepTick()不同 ,此函數可以將滴答計數向前移動超過應從阻止狀態中刪除任務的時間。這意味着xTaskCatchUpTicks()可以從阻止狀態中刪除任務。

參數:

xTicksToCatchUp 由於禁用了中斷而錯過的滴答中斷的數量。它的值不會自動計算,因此必須由應用程序編寫器計算。

返回值:

如果向前移動滴答計數導致任務離開阻塞狀態並執行上下文切換,則爲pdTRUE。否則爲pdFALSE。

用法示例:
 
void vExampleFunction( void )
{
    unsigned long ulTimeBefore, ulTimeAfter;

    /* Read the current time before arbitrary processing takes place. */
    ulTimeBefore = ulGetExternalTime();

    /* Stop the timer that is generating the tick interrupt. */
    prvStopTickInterruptTimer();
 
    /* Perform some arbitrary processing. */
    arbitrary_processing();
    
    /* Read the current time for computing elapsed time since ticks 
    were disabled. */
    ulTimeAfter = ulGetExternalTime();

    if ( xTaskCatchUpTicks( ulTimeAfter - ulTimeBefore ) == pdTRUE ) 
    {
        /* Moving the tick count forward resulted in a context switch. */
    }
    
    /* Restart the timer that is generating the tick interrupt. */
    prvStartTickInterruptTimer();

}
 
 
 
 
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章