第四章 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();

}
 
 
 
 
 

 

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