2.2 开启调度器

开启调度器

void vTaskStartScheduler( void )
{
	BaseType_t xReturn;
	#if( configSUPPORT_STATIC_ALLOCATION == 1 )							// 静态创建空闲任务
	{
		StaticTask_t *pxIdleTaskTCBBuffer = NULL;
		StackType_t *pxIdleTaskStackBuffer = NULL;
		uint32_t ulIdleTaskStackSize;
																		// 设置空闲任务的堆栈
		vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
		xIdleTaskHandle = xTaskCreateStatic(	prvIdleTask,			// 空闲任务函数名
												configIDLE_TASK_NAME,	// 任务名称,用于调试
												ulIdleTaskStackSize,	// 空闲任务堆栈大小
												( void * ) NULL,		// 空闲任务参数
												( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),	// 空闲任务优先级,最低
												pxIdleTaskStackBuffer,	// 空闲任务堆栈地址
												pxIdleTaskTCBBuffer );	// 空闲任务控制块
		if( xIdleTaskHandle != NULL )									// 任务创建成功,任务控制块不为空
		{
			xReturn = pdPASS;
		}
		else
		{
			xReturn = pdFAIL;
		}
	}
	#else
	{																	// 动态创建任务
		xReturn = xTaskCreate(	prvIdleTask,							// 空闲任务函数名
								configIDLE_TASK_NAME,					// 空闲任务名称,用于调试
								configMINIMAL_STACK_SIZE,
								( void * ) NULL,
								( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
								&xIdleTaskHandle );
	}
	#endif 

	#if ( configUSE_TIMERS == 1 )										// 使能定时器功能
	{
		if( xReturn == pdPASS )
		{
			xReturn = xTimerCreateTimerTask();							// 创建定时器任务
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif

	if( xReturn == pdPASS )												// 空闲任务创建成功,并且定时器任务创建成功
	{
		#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
		{
			freertos_tasks_c_additions_init();
		}
		#endif
		// 关闭中断,确保不会发生中断。开启任务调度器之前,或期间,堆栈的创建任务包含打开中断的状态,当第一个任务时,中断将自动重启开始运行
		portDISABLE_INTERRUPTS();

		#if ( configUSE_NEWLIB_REENTRANT == 1 )
		{
			_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
		}
		#endif

		xNextTaskUnblockTime = portMAX_DELAY;		// 下一任务唤醒任务的时间,本次计时不会唤醒任务
		xSchedulerRunning = pdTRUE;					// 为pdTRUE表示调度器在运行
		xTickCount = ( TickType_t ) 0U;				// 用于记录系统运行时长
		portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();	// 配置定时器的时基
		if( xPortStartScheduler() != pdFALSE )		// 开启调度器,启动系统节拍,启动后直接开始执行第一个任务
		{
			// 启动成功,则不会到达此处,直接执行第一个任务
		}
		else
		{
			// 除非调用 xTaskEndScheduler 函数才可到达此处
		}
	}
	else
	{
		// 只有在内核无法启动时才会运行到达慈航,因为没有足够的堆内存创建空闲任务或计时器任务
		configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );	// 断言函数输出错误信息,定位错误位置
	}
	( void ) xIdleTaskHandle;
}

BaseType_t xPortStartScheduler( void )
{
	configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) );

	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;		// 设置pendsv中断优先级,为最低优先级
	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;		// 设置systick中断优先级,为最低优先级

	prvSetupMPU();			
	prvSetupTimerInterrupt();							// 调用 vPortSetupTimerInterrupt 设置滴答定时周期,使能滴答中断
	uxCriticalNesting = 0;								// 初始化临界区嵌套计数器
	vPortEnableVFP();									// 调用函数使能FPU
	*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;			// 设置FPCCR的bit31和bit30为1
	prvStartFirstTask();								// 启动第一个任务

	return 0;
}

__asm void prvStartFirstTask( void )
{
	PRESERVE8				// 8位对齐

	ldr r0, =0xE000ED08		// 读取 向量表偏移量寄存器的值,也就是向量表保存位置,MSP 地址
	ldr r0, [r0]			// 读取 向量表偏移量寄存器的值 ,读取MSP
	ldr r0, [r0]			// 读取最先压栈的数据

	msr msp, r0				// msp指针写入msp寄存器中
	mov r0, #0				// 目前 R0 = MSP,清空R0寄存器的值
	
	cpsie i					// primask寄存器
	cpsie f					// faultmask寄存器
	dsb						// 数据操作完毕后,同步数据和命令
	isb

	svc 0					// 调用SVC指令触发SVC中断
	nop
	nop
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值