天天看点

FreeRTOS笔记(三):任务调度器FreeRTOS笔记(三):任务调度器

FreeRTOS笔记(三):任务调度器

调度器是 FreeRTOS 操作系统的核心,主要负责任务切换,即找出最高优先级的就绪任务,并使之获得 CPU 运行权。调度器并非自动运行的,需要人为启动它。

使用场景如下:

int main(void)
{
	//....
	//创建任务	           
    vTaskStartScheduler();   //开启任务调度器
}
           

一、任务调度器开启函数

创建任务之后,就会调用vTaskStartScheduler()函数开启调度器,具体函数如下:

void vTaskStartScheduler( void )
{
	BaseType_t xReturn;

	xReturn = xTaskCreate(	prvIdleTask,  //-----------------------------------(1)
							"IDLE", configMINIMAL_STACK_SIZE,
							( void * ) NULL,
							( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
							&xIdleTaskHandle ); 

	#if ( configUSE_TIMERS == 1 )  //使能定时器
	{
		if( xReturn == pdPASS )
		{
			xReturn = xTimerCreateTimerTask();  //----------------------------(2)
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configUSE_TIMERS */

	if( xReturn == pdPASS )   //空闲任务和定时器任务创建成功
	{
		
		portDISABLE_INTERRUPTS();            //----------------------------(3)

		#if ( configUSE_NEWLIB_REENTRANT == 1 )   //使能NEWLIB
		{
			
			_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
		}
		#endif /* configUSE_NEWLIB_REENTRANT */

		xNextTaskUnblockTime = portMAX_DELAY;
		xSchedulerRunning = pdTRUE;    //--------------------------------(4)
		xTickCount = ( TickType_t ) 0U;

		
		portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();  //-------------------(5)

		if( xPortStartScheduler() != pdFALSE )     //---------------------(6)
		{
			//任务调度器启动成功不会运行到这
		}
		else
		{
			//不会运行到这
		}
	}
	else
	{
		//创建空闲任务或定时器任务失败,导致启动失败
		configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
	}
	//防止编译出错
	( void ) xIdleTaskHandle;
}
           

分析如下:

(1)创建空闲任务;

(2)使能软件定时器,并创建定时器任务;

(3)关闭中断,在SVC中断函数中会打开中断;

(4)xSchedulerRunning设置为真,表示调度器开启;

(5) 如果宏configGENERATE_RUN_TIME_STATS被定义,表示使用运行时间统计功能,用于初始化一个基础定时器/计数器;

(6)调用xPortStartScheduler来初始化跟调度器有关的硬件,比如滴答定时器与PendSV。具体将在一下节介绍。

二、内核相关硬件初始化函数分析

FreeRTOS系统时钟由滴答定时器来提供,而且任务切换也会用到PendSV中断,这些硬件都是由xPortStartScheduler()函数完成。

BaseType_t xPortStartScheduler( void )
{
	//省略了条件编译
	
	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; 	//------------------(1)
	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;	//------------------(2)

	vPortSetupTimerInterrupt();						//------------------(3)

	uxCriticalNesting = 0;							//------------------(4)

	prvStartFirstTask();							//------------------(5)

	return 0;
}
           

(1)设置PendSV中断优先级,为最低优先级;

(2)设置滴答定时器中断优先级,为最低优先级;

(3)设定滴答定时器周期以及使能滴答定时器的中断;

(4)初始化临界区嵌套计数器;

(5)调用prvStartFirstTask()开启第一个任务。将在下节介绍

补充:

在 Cortex-M3 架构中,FreeRTOS 为了任务启动和任务切换使用了三个异常:SVC、PendSV 和 SysTick。

●SVC(系统服务调用)用于任务启动,有些操作系统不允许应用程序直接访问硬件,而是通过提供一些系统服务函数,通过 SVC 来调用;

●PendSV(可挂起系统调用)用于完成任务切换,它的最大特性是如果当前有优先级比它高的中断在运行,PendSV 会推迟执行,直到高优先级中断执行完毕;

●SysTick 用于产生系统节拍时钟,提供一个时间片,如果多个任务共享同一个优先级,则每次 SysTick 中断,下一个任务将获得一个时间片。

三、启动第一个任务

硬件初始化的函数最后一步就是开启第一个任务,调用函数prvStartFirstTask()完成,这是一个汇编函数,如下:

__asm void prvStartFirstTask( void )
{
    PRESERVE8
 
    /* Cortext-M3硬件中,0xE000ED08地址处为VTOR(向量表偏移量)寄存器,存储向量表起始地址*/
    ldr r0, =0xE000ED08    
    ldr r0, [r0]
    /* 取出向量表中的第一项,向量表第一项存储主堆栈指针MSP的初始值*/
    ldr r0, [r0]   
 
    /* 将堆栈地址存入主堆栈指针 */
    msr msp, r0
    /* 使能全局中断*/
    cpsie i
    cpsie f
    dsb
    isb
    
    svc 0   //触发SVC中断开启第一个任务
    nop
    nop
}
           

四、SVC中断函数

在函数prvStartFirstTask中通过调用SVC指令触发了SVC中断,第一个任务的启动就是在SCV中断服务函数中完成的。

__asm void vPortSVCHandler( void )
{
    PRESERVE8
 
    ldr r3, =pxCurrentTCB   		//---------------------(1)
    ldr r1, [r3]            		//---------------------(2)
    ldr r0, [r1]            		//---------------------(3)
    ldmia r0!, {r4-r11,r14}    		//---------------------(4) 
    msr psp, r0             		//---------------------(5)
    isb								
    mov r0, #0						
    msr basepri, r0        			//---------------------(6)
    orrr14, #0xd         			//---------------------(7)
    bx r14							//---------------------(8)
}
           

(1) pxCurrentTCB指向处于最高优先级的就绪任务TCB ;

(2) 获取任务TCB地址 ;

(3) 获取任务TCB的第一个成员,即当前堆栈栈顶pxTopOfStack ;

(4) 将寄存器r4~r11和r14出栈 ;

(5) 进程堆栈指针PSP设置成任务堆栈;

(6) 打开中断;

(7) CPU退出中断,进入线程模式并使用线程栈;

(8) 执行此代码后,任务调度正式成功,第一个任务开始运行。

参考资料

https://blog.csdn.net/qq_27114397/article/details/83017422

继续阅读