FreeRTOS(二)任务调度

vTaskStartSchedular()任务调度函数

void vTaskStartScheduler( void )
{
	BaseType_t xReturn;
	/*创建空闲任务,并返回xReturn判断是否创建成功*/
	xReturn = xTaskCreate(	prvIdleTask,
									"IDLE", configMINIMAL_STACK_SIZE,
									( void * ) NULL,
									( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
									&xIdleTaskHandle );
	//如果启用了configUSE_TIMERS宏定义则表明使用定时器,需要创建定时器任务
	#if ( configUSE_TIMERS == 1 )
	{
		if( xReturn == pdPASS )
		{
			xReturn = xTimerCreateTimerTask();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
		#endif /* configUSE_TIMERS */
	if( xReturn == pdPASS )
	{
		/* 此处关闭中断,确保不会发生中断,在调用xPortStartScheduler()
		  之前或调用期间。栈的创建任务中包含打开中断的状态,因此当执行
		  第一个任务时,中断将自动重新启用,开始运行*/
		portDISABLE_INTERRUPTS();
		
		xNextTaskUnblockTime = portMAX_DELAY; //下个任务解锁时间,赋值为最大延迟时间
		xSchedulerRunning = pdTRUE; //调度器状态为开始运行
		xTickCount = ( TickType_t ) 0U;  //时钟节拍计数器清零
		
		portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();  //初始化定时器
		
		if( xPortStartScheduler() != pdFALSE )
		{
			/* 如果 xPortStartScheduler()函数启动,则不会运行到这里*/
		}
		else
		{
			/* 除非调用xTaskEndScheduler()函数才会运行到这里. */
		}
	}
	else
	{
		/* 只有在内核无法启动时才会运行至此,因为没有足够的堆内存来创建空闲任务或定时器任务。
		   此处使用了断言,会输出错误信息,方便错误定位 */
		configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
	}

	/* 如果INCLUDE_xTaskGetIdleTaskHandle设置为0,则防止编译器警告
	意味着其他地方均不使用xIdleTaskHandle() */
	( void ) xIdleTaskHandle;
}

portDISABLE_INTERRUPTS()关中断

#define portDISABLE_INTERRUPTS()				vPortRaiseBASEPRI()
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
	//configMAX_SYSCALL_INTERRUPT_PRIORITY这个宏默认值为191,高4位有效,即为11,将这个值赋给ulNewBASEPRI
	uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
	__asm
	{
		/* 将 ulNewBASEPRI这个值赋给basepri寄存器,意味着优先级高于11的中断全部屏蔽*/
		msr basepri, ulNewBASEPRI
		dsb
		isb
	}
}

xPortStartScheduler() 开始调度

BaseType_t xPortStartScheduler( void )
{
	/*将PendSV和SysTick的中断优先级配置为最低. */
	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;

	/* 启动系统节拍定时器,即SysTick定时器,初始化中断周期并使能定时器 */
	vPortSetupTimerInterrupt();

	/* 初始化临界区嵌套计数器 */
	uxCriticalNesting = 0;

	/* 开启第一个任务 */
	prvStartFirstTask();

	/* 不会运行到这里*/
	return 0;
}

vPortSetupTimerInterrupt()启动SysTick定时器

void vPortSetupTimerInterrupt( void )
{
#ifndef configSYSTICK_CLOCK_HZ
	/* 如果没有定义系统时钟,则系统时钟频率为CPU时钟频率 */
	#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
	#define portNVIC_SYSTICK_CLK_BIT	( 1UL << 2UL )
#else
	#define portNVIC_SYSTICK_CLK_BIT	( 0 )
#endif

	/* 系统重装载寄存器的值为CPU时钟频率除以系统时钟节拍(25MHz/1000) */
	portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
	/*系统控制寄存器配置:使用内核时钟,打开sysitck中断,使能systick*/
	portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
}

prvStartFirstTask()开始第一个任务

__asm void prvStartFirstTask( void )
{
	PRESERVE8      //考虑到浮点运算,当前栈按照8字节对齐

	/*0xE000ED08是SCB_VTOR寄存器的地址,里面存放向量表的起始地址,即Msp地址 */
	ldr r0, =0xE000ED08    //将立即数0xE000ED08存入r0
	ldr r0, [r0]           //将0xE000ED08地址指向的内容赋给r0,r0为SCB_VTOR寄存器的值,为0x00000000,即memory的起始地址
	ldr r0, [r0]           //将memory起始地址指向的内容赋给r0,也就是取出向量表中的第一项,主堆栈指针MSP的初始值

	/* 将r0的值存储到主栈指针 */
	msr msp, r0
	/* 使能全局中断 */
	cpsie i
	cpsie f
	dsb
	isb
	/* 产生系统调用,执行SVC中断服务函数开启第一个任务*/
	svc 0
	nop
	nop
}

vPortSVCHandler()SVC中断服务函数


__asm void vPortSVCHandler( void )
{
    PRESERVE8
	 /* pxCurrentTCB指向处于最高优先级的就绪任务TCB */
    ldr r3, =pxCurrentTCB   /*加载pxCurrentTCB的地址到r3 */
    ldr r1, [r3]            /*加载pxCurrentTCB到r1*/
    ldr r0, [r1]            /* 加载pxCurrentTCB指向的任务控制块到r0,即当前堆栈栈顶指针pxTopOfStack */
    ldmia r0!, {r4-r11}     /*将寄存器r4~r11出栈,栈顶指针先操作在递增*/
    msr psp, r0             /* 将最新的栈顶指针赋给线程堆栈指针PSP */
    isb
    mov r0, #0              /*将立即数0赋给r0*/
    msr basepri, r0         /*将0赋给寄存器basepri,打开所有中断*/
    orr r14, #0xd           /* 这里r14最后四位或上x0d(1101)表示:硬件退出使用进程栈指针psp完成出栈后返回后进入线程模式,
                            从进程堆栈中做出栈操作,返回Thumb状态,在SVC中断服务中,使用的是msp指针,处于ARM状态*/
    bx r14                  /*异常返回,bx  r14指令后,硬件自动将寄存器xPSR、PC、LR、R12、R3~R0出栈,
                             这时新任务的任务函数指针会出栈到PC指针中,从而开始执行任务。*/
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值