b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

freertos创建任务_freertos 任务_freertos任务切换(4)

电脑杂谈  发布时间:2017-02-21 01:11:40  来源:网络整理

异常返回后, 系统进入线程模式, 自动从堆栈恢复PC等寄存器,而由于此时栈指针已经更新指向对应准备运行任务的栈,所以,程序会从该任务入口函数开始执行。

到此, 第一个任务启动。

前面提到, 第一个任务启动通过 SVC 异常, 而后续的任务切换, 使用的是 PendSV 异常, 而其对应的服务函数是 xPortPendSVHandler。 后续介绍任务切换再分析。

FreeRTOS 支持时间片轮序和优先级抢占。系统调度器通过调度算法确定当前需要获得CPU 使用权的任务并让其处于运行状态。对于嵌入式系统,某些任务需要获得快速的响应,如果使用时间片,该任务可能无法及时被运行,因此抢占调度是必须的,高优先级的任务一旦就绪就能及时运行;而对于同优先级任务,系统根据时间片调度,给予每个任务相同的运行时间片,保证每个任务都能获得CPU 。

最高优先级任务 Task 1 运行,直到其被阻塞或者挂起释放CPU

就绪链表中最高优先级任务Task 2 开始运行, 直到...

调用接口进入阻塞或者挂起状态

任务 Task 1 恢复并抢占 CPU 使用权

同优先级任务TASK 3 就绪,时间片调度

没有用户任务执行,运行系统空闲任务。

FreeRTOS 在两种情况下执行任务切换:

同等级任务时间片用完,提前挂起触发切换

在 SysTick 节拍计数器中断中触发异常

高优先任务恢复就绪(如信号量,队列等阻塞、挂起状态下退出)时抢占

最终都是通过调用移植层提供的 portYIELD() 宏悬起 PendSV 异常

但是无论何种情况下,都是通过触发系统 PendSV 异常,在该服务程序中完成切换。

使用该异常切换上下文的原因是保证切换不会影响到其他中断的及时响应(切换上下文抢占了 ISR 的执行,延时时间不可预知,对于实时系统是无法容忍的),在SysTick 中或其他需要进行任务切换的地方悬起一个 PendSV 异常,系统会直到其他所有 ISR 都完成处理后才执行该异常的服务程序,进行上下文切换。

系统响应 PendSV 异常,在该中断服务程序中,保存当前任务现场, 选择切换的下一个任务,进行任务切换,退出异常恢复线程模式运行新任务,完成任务切换。

以下是 Cotex-M3 的服务程序,

首先先要明确的是,系统进入异常处理程序的时候,使用的是主堆栈指针 MSP, 而一般情况下运行任务使用的线程模式使用的是进程堆栈指针 PSP。后者使用是系统设置的,前者是硬件强制设置的。

对应这两个指针,系统有两种堆栈,系统内核和异常程序处理使用的是主堆栈,MSP 指向其栈顶。而对应而不同任务,我们在创建时为其分配了空间,作为该任务的堆栈,在该任务运行时,由系统设置进程堆栈 PSP 指向该栈顶。

如下分析该服务函数的执行:

void xPortPendSVHandler( void )
{
    /* This is a naked function. */
    __asm volatile
    (
    /*取出当前任务的栈顶指针 也就是 psp -> R0*/
    "    mrs r0, psp                            \n"
    "    isb                                    \n"
    "                                        \n"
    /*取出当前任务控制块指针 -> R2*/
    "    ldr    r3, pxCurrentTCBConst            \n"
    "    ldr    r2, [r3]                        \n"
    "                                        \n"
    /*R4-R11 这些系统不会自动入栈,需要手动推到当前任务的堆栈*/
    "    stmdb r0!, {r4-r11}                    \n"
    /*最后,保存当前的栈顶指针 
    R0 保存当前任务栈顶地址
    [R2] 是 TCB 首地址,也就是 pxTopOfStack
    下次,任务激活可以重新取出恢复栈顶,并取出其他数据
    */
    "    str r0, [r2]                        \n"
    "                                        \n"
    /*保护现场,调用函数更新下一个准备运行的新任务*/
    "    stmdb sp!, {r3, r14}                \n"
    /*设置优先级 第一个参数,
    即:configMAX_SYSCALL_INTERRUPT_PRIORITY
    进入临界区*/
    "    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"
    /*函数返回 退出临界区
    pxCurrentTCB 指向新任务
    取出新的 pxCurrentTCB 保存到 R1
    */
    "    ldr r1, [r3]                        \n"
    /*取出新任务的栈顶*/
    "    ldr r0, [r1]                        \n"
    /*恢复手动保存的寄存器*/
    "    ldmia r0!, {r4-r11}                    \n"
    /*设置线程指针 psp 指向新任务栈顶*/
    "    msr psp, r0                            \n"
    "    isb                                    \n"
    /*返回, 硬件执行现场恢复
    开始执行任务
    */
    "    bx r14                                \n"
    "                                        \n"
    "    .align 4                            \n"
    "pxCurrentTCBConst: .word pxCurrentTCB    \n"
    ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
    );
}


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-33581-4.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...