Freertos 任务(二)调度器设计和上下文切换

Freertos 调度器的设定和处理器的架构联系非常紧密
所以这部分的内容属于移植层,以ARM cortex-M3为例
FreeRTOS-Kernel-10.4.6\portable\GCC\ARM_CM3

调度器设计的功能有两个,围绕调度
1:调度,完成调度这个动作,也就上下文切换
2:调度策略, 该怎么调度好

调度器本身也是一段在处理器上的代码,为了让它保持对处理器的控制权,只要控制了CPU才能对CPU上的任务进行调度。简单说就是 这个CPU我说的算。设计嵌入式系统根据需求,实时性有时是摆在第一位的,所以调度器的位置得要让一让。因为嵌入式任务是静态设计的,不像PC可以安装软件。所以我们可以放心的让调度器放权,也就是放弃最高的优先级。调度器周期性执行是由一个计时器中断产生的。所以对这个计时器的中断的优先级进行配置就可以把调度器的优先级定义下来。同样和调度器一个党派的调度器/操作系统的组件也要保持这个优先级,所以定义了一个最大的优先级。

这里的原则 让有些中断可以绕过复杂的调度系统 ,及时的得到响应保证实时性。

调度器相关的组件:SVCHandler,PendSVHandler
他两就是完成任务切换的,改变CPU的运行环境。把旧任务的数据从CUP中搬出来入栈,把新任务的数据从栈中搬进去
在这里插入图片描述

SVCHandler,PendSVHandler两个异常服务函数的调转是通过异常向量表进行的。在表上查找一个函数的入口地址然后调转到指定地址运行。
简单说就是家里的冰箱突然坏了,报了一个错误代码,当然是拿出说明书查一下故障代码看看怎么处理。这个说明书的故障代码表(异常向量表)在哪里,在0xE000ED08这个地址下。所以CPU发生了异常它也很无助只能去找故障代码表。

所以SVCHandler,PendSVHandler的入口地址都是存在与异常向量表中。

异常向量表的第一地址存的是主堆栈 的初始位置,也就是栈空间的起始位置
在这里插入图片描述
Cortex-M3 的双堆栈机制
任务创建的时候我们为每个任务设定了栈空间,这个空间用来保存任务在CPU中运行的上下文,也就是CPU中和任务执行相关的数据,如果这些数据丢了,那么任务也就没办法恢复运行了。
一般来说CPU再进行异常调转的时候,因为异常调转是硬件进行的,所以他会自动保存一些数据。这个是下上文的一部分。那么自动保存到哪里去了呢?默认情况下是主栈MSP。开机到运行Main,都在使用MSP。裸机的情况下所有的代码都是一个任务,这个MSP就是大任务的栈。有个时候,要把这个 栈切换 到任务自己的栈。

使用线程模式,CPU硬件入栈 对应的栈为PSP栈
使用内核模式,CPU硬件入栈,对应的是MSP栈
在这里插入图片描述

通过读取 PSP 的值, OS 就能够获取用户应用程序使用的堆栈,进一步地就知道了在发
生异常时,被压入寄存器的内容,而且还可以把其它寄存器进一步压栈(使用STMDB 和LDMIA
的书写形式)。 OS 还可以修改 PSP,用于实现多任务中的任务上下文切换。

上下文的切换的重点
1:搞清楚所使用的栈 MSP,PSP,各个任务的栈
2:上下文寄存器 哪些手动保存,哪些由硬件自动保存。
3:不同模式下,内核选择使用什么栈

笼统地讲,堆栈操作就是对内存的读写操作,但是其地址由 SP 给出。寄存器的数据通
过 PUSH 操作存入堆栈,以后用 POP 操作从堆栈中取回。在 PUSH 与 POP 的操作中, SP 的
值会按堆栈的使用法则自动调整,以保证后续的 PUSH 不会破坏先前 PUSH 进去的内容。
SVCHandler,PendSVHandler 的代码设计到太多的汇编指令。
就到这里

void xPortPendSVHandler( void )
{
    /* This is a naked function. */

    __asm volatile
    (
        "	mrs r0, psp							\n"
        "	isb									\n"
        "										\n"
        "	ldr	r3, pxCurrentTCBConst			\n"/* Get the location of the current TCB. */
        "	ldr	r2, [r3]						\n"
        "										\n"
        "	stmdb r0!, {r4-r11}					\n"/* Save the remaining registers. */
        "	str r0, [r2]						\n"/* Save the new top of stack into the first member of the TCB. */
        "										\n"
        "	stmdb sp!, {r3, r14}				\n"
        "	mov r0, %0							\n"
        "	msr basepri, r0						\n"
        "	bl vTaskSwitchContext				\n"
        "	mov r0, #0							\n"
        "	msr basepri, r0						\n"
        "	ldmia sp!, {r3, r14}				\n"
        "										\n"/* Restore the context, including the critical nesting count. */
        "	ldr r1, [r3]						\n"
        "	ldr r0, [r1]						\n"/* The first item in pxCurrentTCB is the task top of stack. */
        "	ldmia r0!, {r4-r11}					\n"/* Pop the registers. */
        "	msr psp, r0							\n"
        "	isb									\n"
        "	bx r14								\n"
        "										\n"
        "	.align 4							\n"
        "pxCurrentTCBConst: .word pxCurrentTCB	\n"
        ::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
    );
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值