实现调度器

实现调度器

调度器是操作系统的核心,其主要功能就是实现任务的切换,即从就绪列表里面找到优先级最高的任务,然后去执行该任务。

1、启动调度器

(1)

void vTaskStartScheduler( void )
{
	/* 手动指定第一个运行的任务 */
	pxCurrentTCB = &Task1TCB; 

	/* 启动调度器 */
	if ( xPortStartScheduler() != pdFALSE ){
		/* 调度器启动成功,则不会返回,即不会来到这里 */ 
 	}
}

pxCurrentTCB 是一个在 task.c 定义的全局指针,用于指向当前正在运行或者即将要运行的任务的任务控制。

调用函数 xPortStartScheduler()启动调度器,调度器启动成功,则不会返回。

(2)

#define portNVIC_SYSPRI2_REG (*(( volatile uint32_t *) 0xe000ed20))

#define portNVIC_PENDSV_PRI (((uint32_t) 	configKERNEL_INTERRUPT_PRIORITY ) << 16UL)
#define portNVIC_SYSTICK_PRI (((uint32_t) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )

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

	/* 启动第一个任务,不再返回 */
	prvStartFirstTask(); 

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

(3)

prvStartFirstTask()函数用于开始第一个任务,主要做了两个动作,一个是更新 MSP 的值,二是产生 SVC 系统调用,然后去到 SVC 的中断服务函数里面真正切换到第一个任务。

__asm void prvStartFirstTask( void )
{
	PRESERVE8
	
	/* 在 Cortex-M 中,0xE000ED08 是 SCB_VTOR 这个寄存器的地址,里面存放的是向量表的起始地址,即 MSP 的地址 */
	ldr r0, =0xE000ED08 
	ldr r0, [r0] 
	ldr r0, [r0] 

	/* 设置主堆栈指针 msp 的值 */
	msr msp, r0
	
	/* 使能全局中断 */ 
	cpsie i
	cpsie f
	dsb
	isb
	
	/* 调用 SVC 去启动第一个任务 */
	svc 0
	nop
	nop
}

(4)

SVC 中断要想被成功响应,其函数名必须与向量表注册的名称一致,在启动文件的向量表中,SVC 的中断服务函数注册的名称是 SVC_Handler,所以 SVC 中断服务函数的名称我们应该写成 SVC_Handler。

__asm void vPortSVCHandler( void )
{
	extern pxCurrentTCB; 
	
	PRESERVE8
	
	dr r3, =pxCurrentTCB 
	ldr r1, [r3] 
	ldr r0, [r1] 
	ldmia r0!, {r4-r11} 
	msr psp, r0 
	isb
	mov r0, #0
	msr basepri, r0 
	orr r14, #0xd 

	bx r14 
}

2、 任务切换

任务切换就是在就绪列表中寻找优先级最高的就绪任务,然后去执行该任务。

(1)taskYIELD()

portYIELD 的实现很简单,实际就是将 PendSV 的悬起位置 1,当没有其它中断运行的时候响应 PendSV 中断,去执行我们写好的 PendSV中断服务函数,在里面实现任务切换。

(2)xPortPendSVHandler()函数

PendSV 中断服务函数是真正实现任务切换的地方。

__asm void xPortPendSVHandler( void )
{
	extern pxCurrentTCB; 
	extern vTaskSwitchContext; 
	
	PRESERVE8

	mrs r0, psp
	isb
	
	ldr r3, =pxCurrentTCB 
	ldr r2, [r3]
	
	stmdb r0!, {r4-r11}
	str r0, [r2] 
	
	stmdb sp!, {r3, r14} 
	mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
	msr basepri, r0 
	dsb
	isb
	bl vTaskSwitchContext 
	mov r0, #0 
	msr basepri, r0 
	ldmia sp!, {r3, r14} 
	
	ldr r1, [r3] 
	ldr r0, [r1] 
	ldmia r0!, {r4-r11} 
	msr psp, r0 
	isb
	bx r14 
	nop
}

(3)vTaskSwitchContext()函数

void vTaskSwitchContext( void )
{
	/* 两个任务轮流切换 */
	if ( pxCurrentTCB == &Task1TCB ) {
		pxCurrentTCB = &Task2TCB;
		}
	else{
		pxCurrentTCB = &Task1TCB;
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值