FreeRTOS任务切换解析

转载于:http://blog.sina.com.cn/s/blog_5f0bed160100tqnu.html

说明:嵌入式系统FreeRTOS任务切换牵涉到具体硬件体系结构的支持,(堆栈类型,寄存器种类,工作模式等不同)

下面根据CortexM3内核---STM32处理器---进行介绍:

一:启动第一个任务,

二:portYIELD_WITHIN_API(任务切换)包括 创建任务,

 一:内核刚刚启动时候,第一个任务是怎样跑起来的。

1.1:主函数:main(){

 

 prvSetupHardware();//初始化硬件(处理器IO,初始化等)

 

//创建第一个任务 vTestTask.任务创建参考----FreeRTOS任务管理与控制--------

 xTaskCreate( vTestTask, ( signed portCHAR *)"Test", configMINIMAL_STACK_SIZE, NULL, (tskIDLE_PRIORITY+1),NULL);

 

//开启内核运行,调度便由此开始。

vTaskStartScheduler();

 

}

1.2:内部调用的函数  在内核文件task.c中实现。

下面解析:VTastStartScheduler的实现:

void vTaskStartScheduler( void )
{
portBASE_TYPE xReturn;

 
 xReturn = xTaskCreate( prvIdleTask, ( signed char* ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY| portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );

 if( xReturn == pdPASS )
 {
  

  。。。。任务运行之前禁止中断的发生,时钟中断将对任务进行轮询。当第一个任务运行的时候开启中断。。。
  portDISABLE_INTERRUPTS();

  xSchedulerRunning =pdTRUE;
  xTickCount = ( portTickType )0;

  
  portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();

  //下面这个函数,实现调度
  if( xPortStartScheduler())
  {
   
  }
  else
  {
   
  }
 }
}

1.3内部第二个函数,在Port.c文件中实现。

xPortStartScheduler代码如下:

portBASE_TYPE xPortStartScheduler( void )
{
 
 *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
 *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;

 
 prvSetupTimerInterrupt();
 
 
 uxCriticalNesting = 0;

 
 vPortStartFirstTask();

 
 return 0;

 1.4;内部第三个函数vPortStartFirstTask

会变函数,用NVIC SVC软中断实现

__asm void vPortStartFirstTask( void )
{
 PRESERVE8

 
 ldr r0, =0xE000ED08
 ldr r0, [r0]
 ldr r0, [r0]
 
 msr msp, r0
 
 svc 0
}

 ldr r1,[r3]    
 ldr r0,[r1]    
 ldmia r0!,{r4-r11}  
 msr psp,r0     
 mov r0, #0
 msr basepri, r0
 orr r14,#0xd    
 bxr14      
}

 二:利用宏实现任务切换  portYIELD_WITHIN_API();

 

 #define portYIELD_WITHIN_API portYIELD

#defineportYIELD()     vPortYieldFromISR()

利用PendSV异常实现任务切换

void vPortYieldFromISR( void )
{
 
 *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
}

出现portYIELD_WITHIN_API的地方有以下几处:

2.1:任务创建,如果创建的任务优先级比正在运行的高,进行切换

 if( xSchedulerRunning != pdFALSE )
  {
   
   if(pxCurrentTCB->uxPriority < uxPriority)
   {
    portYIELD_WITHIN_API();
   }
  }

2.2:任务删除(删除自己)

 
  if( xSchedulerRunning !=pdFALSE )
  {
   if( ( void *) pxTaskToDelete == NULL )
   {
    portYIELD_WITHIN_API();
   }
  }

2.3:任务延时vTaskDelayUntil  vTaskDelay

 

如果延时时间没有到,强迫切换
  if( !xAlreadyYielded )
  {
   portYIELD_WITHIN_API();
  }

2.4:任务优先级设置vTaskPrioritySet

2.4.1:

   The priority of another task is being raised,

     其他某个任务优先级变高. 

    
      xYieldRequired= pdTRUE;标志变量。

2.4.2: 设置自己的优先级变低。


     xYieldRequired= pdTRUE; 标志变量

判断标志变量的数值:

 if( xYieldRequired == pdTRUE )
    {
     portYIELD_WITHIN_API();
    }

2.5:任务挂起 vTaskSuspend 只能挂起自己

if( pxTaskToSuspend == pxCurrentTCB )
   {
    pxTaskToSuspend= NULL;
   }

 
  if( ( void * ) pxTaskToSuspend== NULL )
  {
   portYIELD_WITHIN_API();
  }

2.6:任务唤醒  只能唤醒其他任务 vTaskResume

 
     if(pxTCB->uxPriority >=pxCurrentTCB->uxPriority )
     {
      
      portYIELD_WITHIN_API();
     }

2.7:xTaskResumeAll

 
    while(( pxTCB = ( tskTCB * )listGET_OWNER_OF_HEAD_ENTRY(  ( ( xList * )&xPendingReadyList ) ) ) != NULL )
    {
     vListRemove(&( pxTCB->xEventListItem ) );
     vListRemove(&( pxTCB->xGenericListItem ));
     prvAddTaskToReadyQueue(pxTCB );

     
     if(pxTCB->uxPriority >=pxCurrentTCB->uxPriority )
     {
      xYieldRequired= pdTRUE;
     }
    }

    
    if(uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
    {
     while(uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
     {
      vTaskIncrementTick();
      --uxMissedTicks;
     }

     
     #ifconfigUSE_PREEMPTION == 1
     {
      xYieldRequired= pdTRUE;
     }
     #endif
    }

    if(( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
    {
     xAlreadyYielded= pdTRUE;
     xMissedYield= pdFALSE;
     portYIELD_WITHIN_API();
    }
   }
  }


你可能感兴趣的:(操作系统,内核)