Day 3:任务调度

PendSV异常:

PendSV异常全称为可挂起的系统调用,其优先级可通过编程设置,在FreeRTOS中,一般将其设置为最低优先级。FreeRTOS系统的任务切换都是在PendSV中断服务函数中完成的。

SVC:

全称系统服务调用,用于产生系统函数的调用请求。

任务切换场合:

认识这两个概念以后熟悉一下,FreeRTOS在什么情况下会进行任务的切换:

  • 执行系统调用 SVC;
  • 系统嘀嗒定时器中断;

执行系统调用 就是FreeRTOS系统提供的相关 API函数,比如 函数,比如 任务切换函数 taskYIELD(), FreeRTOS有些 API函数 也会调用taskYIELD(),这些 ,这些 API函数都会导致任务切换,统称为系统调用;

#define 	taskYIELD() 	portYIELD()

#define portYIELD() 
{ 
	//通过向中断控制和壮态寄存器ICSR的bit28写入1挂起PendSV来启动PendSV中断,进行任务切换
	portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; 
	__dsb( portSY_FULL_READ_WRITE );
	__isb( portSY_FULL_READ_WRITE ); 
}

#define 	portEND_SWITCHING_ISR( xSwitchRequired )\	
			if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )

系统嘀嗒定时器中断 也会进行任务切换:

void SysTick_Handler(void)
{
	if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)      //系统已经运行
	{
		xPortSysTickHandler();
	}
	
	HAL_IncTick();
}

void xPortSysTickHandler( void )
{
	vPortRaiseBASEPRI();										//关闭中断
	
	if( xTaskIncrementTick() != pdFALSE )						//进入PendSV中断
	{
		portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
	}

	vPortClearBASEPRIFromISR();									//打开中断
}

PendSV解析

FreeRTOS在PendSV中完成任务切换,具体不具体展开,因为是汇编语言,核心信息是利用vTaskSwitchContext() 来获取下一个要运行的任务,并将pxCurrentTCB更新为这个要运行的任务:

void vTaskSwitchContext( void )
{
	if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )   	//挂起状态不能进行任务切换
	{
		xYieldPending = pdTRUE;									
	}
	else
	{
		xYieldPending = pdFALSE;								
		traceTASK_SWITCHED_OUT();								
		taskCHECK_FOR_STACK_OVERFLOW();
		taskSELECT_HIGHEST_PRIORITY_TASK();                     //切换至就绪状态下的优先级最高的任务
		traceTASK_SWITCHED_IN();
	}
}

#define taskSELECT_HIGHEST_PRIORITY_TASK()
{
	UBaseType_t uxTopPriority = uxTopReadyPriority;
	
	//pxReadyTasksLists[]为就绪任务列表数组,一个优先级一个列表,同优先级都挂到相对应的列表
	while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) )
	{
		configASSERT( uxTopPriority );
		--uxTopPriority;
	}
	
	listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB,&( pxReadyTasksLists[ uxTopPriority ] ) );
	uxTopReadyPriority = uxTopPriority;
}

时间片调度方式:

  1. 任务3 正在运行;
  2. 嘀嗒器中断,任务时间片用完(时间片的长度用configTICK_RATE_HZ来确定),切换任务至任务1(就绪的下一个任务);
  3. 不断切换至任务3运行完成,调用portYIELD强行进行任务切换,并放弃剩余的时间片;
  4. 其余任务不断切换;

    FreeRTOS从入门到摔倒-TaskScheduler

内核控制函数概览:

这些函数应用层是不使用的,请注意!!!


FreeRTOS从入门到摔倒-TaskScheduler

相关文章: