FreeRTOS内核学习笔记记录(四)——任务调度器

任务调度器的实现

任务调度器调度步骤
![在这里插入图片描述](https://img-blog.csdnimg.cn/7030a991287a415ba146beb0bc98bda9.png

跳入任务后,永远不会回调度器函数。

vTaskStartScheduler函数

void vTaskStartScheduler( void )
{
BaseType_t xReturn;
/*先创建一个空闲任务 优先级最低 使用最小的堆栈内存*/
		xReturn = xTaskCreate(	prvIdleTask,
								"IDLE", configMINIMAL_STACK_SIZE,
								( void * ) NULL,
								( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
								&xIdleTaskHandle ); 
    /*配置 是否启用软件定时器 如果启用软件定时器会进入一个Tmrsvc的任务*、
	#if ( configUSE_TIMERS == 1 )
	{
		if( xReturn == pdPASS )
		{
			xReturn = xTimerCreateTimerTask();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configUSE_TIMERS */
    /*当空闲任务且者tmrsvc任务创建成功*/
	if( xReturn == pdPASS )
	{
	   /*关闭中断 要配置pendsv和systick相关中断*/
		portDISABLE_INTERRUPTS();
        
        /*配置外部的库*/
		#if ( configUSE_NEWLIB_REENTRANT == 1 )
		{
			_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
		}
		#endif /* configUSE_NEWLIB_REENTRANT */
        /*由于第一个是空闲任务 下一个任务阻塞时间是portMAXDELAY 如果有其余任务创建 则会取最小的任务延时替换portMAX_DELAY*/
		xNextTaskUnblockTime = portMAX_DELAY;
		/*开启任务调度器*/
		xSchedulerRunning = pdTRUE;
		/*系统时间戳为0*/
		xTickCount = ( TickType_t ) 0U;
		portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
		if( xPortStartScheduler() != pdFALSE )
		{
           /*调用xPortStartScheduler后永远不会到这里*/
		}
		else
		{
		
		}
	}
	else
	{
		configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
	}
	( void ) xIdleTaskHandle;
}

**

xPortStartScheduler函数

**

BaseType_t xPortStartScheduler( void )
{
    /*配置断言*/
	#if( configASSERT_DEFINED == 1 )
	{
		volatile uint32_t ulOriginalPriority;
		volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
		volatile uint8_t ucMaxPriorityValue;

		ulOriginalPriority = *pucFirstUserPriorityRegister;
		*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
		ucMaxPriorityValue = *pucFirstUserPriorityRegister;
		ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
		ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
		while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
		{
			ulMaxPRIGROUPValue--;
			ucMaxPriorityValue <<= ( uint8_t ) 0x01;
		}
		ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
		ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
		*pucFirstUserPriorityRegister = ulOriginalPriority;
	}
	#endif /* conifgASSERT_DEFINED */

	/*设置PendSV和SYSTICK为最低优先级*/
	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
	vPortSetupTimerInterrupt();
    /*任务调度嵌套值为0*/
	uxCriticalNesting = 0;
	prvStartFirstTask();
	return 0;
}

**

prvStartFirstTask函数 启动第一个任务 汇编实现

**

__asm void prvStartFirstTask( void )
{
	PRESERVE8/*8字节对齐*/
	ldr r0, =0xE000ED08/*取NVIC的地址到r0*/
	ldr r0, [r0]
	ldr r0, [r0]
	msr msp, r0  /*r0的值给主堆栈指针 要求读中断向量表*/
	/*开启全局中断*/
	cpsie i
	cpsie f
	dsb/*要求以上指令强制执行完*/
	isb
	/*调用SVC中断 去进入第一个函数 由于SVC中断优先级高 先进SVC中断 再进入systick  pendsv只有启用任务调度时才会使用*/
	svc 0
	nop
	nop
}

**

SVC函数

由汇编启动

__asm void vPortSVCHandler( void )
{
	PRESERVE8/*8字节对齐*/
	ldr	r3, =pxCurrentTCB/*保存pxCurrentTCB的值到r3 保存上文*/
	ldr r1, [r3]			/* r3再存到r1 */
	ldr r0, [r1]			/* r1再存到r0 */
	ldmia r0!, {r4-r11}		/* r0的地址由低到高依次压入r4-r11 */
	msr psp, r0				/* 将r0存入任务栈指针psp */
	isb                     /*要求上述指令强制执行完成*/
	mov r0, #0        /*寄存器r0清0*/
	msr	basepri, r0   /*设置 basepri 寄存器的值为 0,即打开所有中断。basepri 是一个中
断屏蔽寄存器,大于等于此寄存器值的中断都将被屏蔽*/
	orr r14, #0xd  /*当从 SVC 中断服务退出前,通过向 r14 寄存器最后 4 位按位或上
0x0D,使得硬件在退出时使用进程堆栈指针 PSP 完成出栈操作并返回后进入任务模式、返
回 Thumb 状态。在 SVC 中断服务里面,使用的是 MSP 堆栈指针,是处在 ARM 状态
当从 SVC 中断服务退出前,通过向 r14 寄存器最后 4 位按位或上
0x0D,使得硬件在退出时使用进程堆栈指针 PSP 完成出栈操作并返回后进入任务模式、返
回 Thumb 状态。在 SVC 中断服务里面,使用的是 MSP 堆栈指针,是处在 ARM 状态
*/
	bx r14 /*异常返回,这个时候出栈使用的是 PSP 指针,自动将栈中的剩下
内容加载到 CPU 寄存器: xPSR,PC(任务入口地址),R14,R12,R3,R2,R1,R0
(任务的形参)同时 PSP 的值也将更新,即指向任务栈的栈顶*/
}
SVC会直接转到第一个任务 通过任务入口地址PC 和任务的形参 且正在使用PSP会切入第一个任务


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值