Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1875488
  • 博文数量: 376
  • 博客积分: 2147
  • 博客等级: 大尉
  • 技术积分: 3642
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-06 10:47
文章分类

全部博文(376)

文章存档

2019年(3)

2017年(28)

2016年(15)

2015年(17)

2014年(182)

2013年(16)

2012年(115)

我的朋友

分类: 嵌入式

2014-09-27 15:29:33

说明:嵌入式系统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    
 bx r14      
}

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

 

 #define portYIELD_WITHIN_API portYIELD

#define portYIELD()     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;
     }

     
     #if configUSE_PREEMPTION == 1
     {
      xYieldRequired = pdTRUE;
     }
     #endif
    }

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

阅读(3007) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~