转载于: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();
}
}
}