分类: 嵌入式
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();
}
}
}