zoukankan      html  css  js  c++  java
  • FreeRTOS ------ prvStartFirstTask 和 vPortSVCHandler

    vPortStartFirstTask
        /* Use the NVIC offset register to locate the stack. */

    // cortex-M3 硬件中,0xE000ED08 地址处为VTOR(向量表偏移量)寄存器,存储向量表起始地址
    ldr r0, =0xE000ED08 //将 0xE000ED08 加载到 R0 ldr r0, [r0] //将 0xE000ED08 地址中的值,也就是向量表的实际地址加载到 R0 ldr r0, [r0] //根据向量表实际存储地址,取出向量表中的第一项,向量表第一项存储主堆栈指针 MSP 的初始值 /* Set the msp back to the start of the stack. */ msr msp, r0 //将 MSP 的初始值写入 MSP 中 /*
    Call SVC to start the first task, ensuring interrupts are enabled. */ cpsie i cpsie f dsb isb svc 0 //调用 SVC 启动第一个任务 END

    PRESERVE8 用于 8 字节对齐;

    取 MSP 的初始值的思路是先根据向量表的位置寄存器 VTOR (0xE000ED08) 来获取向量表存储的地址;再根据向量表存储的地址,来访问第一个元素,也就是初始的 MSP;

    Cortex-M3 处理器,上电默认进入线程的特权模式,使用 MSP 作为堆栈指针,从上电跑到这里,经过一系列的函数调用,出栈,入栈,MSP 自然已经不是最开始的初始化的位置,这里通过 MSR 重新初始化 MSP,岂不是堆栈都没了么?是的,因为这是一条不归路,代码跑到这里,首先不会返回,之前压栈的内容再也不会用到,所以破坏之前的堆栈也没关系。

    调用 svc 并传入系统调用号为 0 手动拉 SVC 中断

    vPortSVCHandler:
        /* Get the location of the current TCB. */
        ldr    r3, =pxCurrentTCB
        ldr r1, [r3]
        ldr r0, [r1]    //获取 TCB 的第一个成员,即当前任务堆栈栈顶 pxTopOfstack
        /* Pop the core registers. */
        ldmia r0!, {r4-r11}
        msr psp, r0
        isb
        mov r0, #0
        msr    basepri, r0
        orr r14, r14, #13
        bx r14

    pxCurrentTCB 指向的是最高优先级的 Ready 状态的任务指针;根据 pxCurrentTCB 获取到对应 TCB 的地址;然后获取第一个成员变量,也就是当前栈顶地址 pxTopOfStack;这个值在任务分配的时候,就已经计算好,并且模拟的 Cortex-M3 的异常入栈顺序,手动入栈了;

    使用 LDMIA 指令,以 pxTopOfStack 开始顺序出栈,先出 R4~R11(在创建任务的时候,最后入栈的就是这些个),同时 R0 递增;

    将此刻的 R0 赋值给 PSP(因为出栈的时候,处理器会按照入栈的顺序去取 xPSR、PC、LR、R12、R3、R2、R1、R0,而这些寄存器在我们创建任务的时候已经手动压栈)

    将 BASEPRI 寄存器赋值为 0,也就是允许任何中断

    ORR 指令时按位或,所以 ORR R14, #0xd 相当于 R14 |= 0xd;这个操作也和体系架构相关,R14 是链接寄存器 LR,在 ISR 中(此刻我们在 SVC 的 ISR 中),它记录了异常返回值 EXC_RETURN

    因为当前在 ISR 中还是使用的 MSP,启动任务后,我们期望在任务执行过程中,处于线程模式,并使用 PSP(前面几行已经给 PSP 赋值了),所以我们需要将 LR 设计成为 0xFFFF_FFFD,让处理器知道返回的时候呢,使用线程模式+PSP堆栈;

     最后执行 bx R14,告诉处理器 ISR 完成,需要返回,此刻处理器便会使用 PSP 做为堆栈指针,进行出栈操作,将xPSR、PC、LR、R12、R3~R0 出栈,初始化的时候,PC 被我们赋值成为了执行任务的函数的入口,所以呢,就正常跳入到了优先级最高的 Ready 状态的第一个任务的入口函数了;

  • 相关阅读:
    Java中的CopyOnWrite
    Collection和Collections的区别
    java中值类型与引用类型的关系
    Xml的用途
    js弹框的3种方法
    文件夹重定向失败解决方案
    网络管理人员经常遇到的十个问题(转载)
    QTP之下拉列表单选框…
    Windows脚本宿主对象模型
    QTP报错“缺少对象WScript”
  • 原文地址:https://www.cnblogs.com/god-of-death/p/14855444.html
Copyright © 2011-2022 走看看