×

UCOSIII移植中的汇编接口函数讲解

消耗积分:1 | 格式:rar | 大小:未知 | 2017-12-06

分享资料个

 1:开始多任务函数 void OSStartHighRdy(void)
  在OSInit()初始化完毕之后,会调用OSStart(),在OS开始函数里面会调用void OSStartHighRdy(void)函数,这是一个纯汇编编写的函数,在os_cpu_a.s这个汇编文件里面实现,具体的如下,我已经给每一句代码都添加了注释。
    ; 开始多任务
  ; void OSStartHighRdy(void)
  ;
  ; 注意 : 1) 这个函数触发了一个PendSV异常,导致第一个任务开始运行。
  ;
  ; 2) OSStartHighRdy() 必须:
  ; a) 设置PendSV的优先级为最低;
  ; b) 初始化进程堆栈指针PSP等于0, 表明这是第一次上下文切换;
  ; c) 设置主堆栈指针等于OS_CPU_ExceptStkBase
  ; d) 触发PendSV异常;
  ; e) 使能中断,任务开始运行。
    ;********************************************************************************************************
  ; 开始多任务
  ; void OSStartHighRdy(void)
  ;
  ; 注意 : 1) 这个函数触发了一个PendSV异常,导致第一个任务开始运行。
  ;
  ; 2) OSStartHighRdy() 必须:
  ; a) 设置PendSV的优先级为最低;
  ; b) 初始化进程堆栈指针PSP等于0, 表明这是第一次上下文切换;
  ; c) 设置主堆栈指针等于OS_CPU_ExceptStkBase
  ; d) 触发PendSV异常;
  ; e) 使能中断,任务开始运行。
  ;********************************************************************************************************
  OSStartHighRdy
  ; 设置PendSV中断优先级
  LDR R0, =NVIC_SYSPRI14
  LDR R1, =NVIC_PENDSV_PRI
  STRB R1, [R0] ;*R0=R1(低字节),因为表达优先级只需要8bit
  ; 初始化PSP=0
  MOVS R0, #0 ; 把0加载到R0
  MSR PSP, R0 ; 把R0的值加载到特殊寄存器PSP
  ; 初始化MSP地址
  LDR R0, =OS_CPU_ExceptStkBase ; 把OS_CPU_ExceptStkBase这个指针变量的地址加载到R0
  LDR R1, [R0] ; *R0 = R1,实际上就是把OS_CPU_ExceptStkBase的值加载到R1
  MSR MSP, R1 ; 把R1的值加载到MSP,此时MSP=OS_CPU_ExceptStkBase
  ; 触发PendSV异常 (进入上下文切换)
  LDR R0, =NVIC_INT_CTRL
  LDR R1, =NVIC_PENDSVSET
  STR R1, [R0] ; *R0 = R1
  ; 打开中断
  CPSIE I
  ; 正常情况下,永远不会运行到这,因为这是一个死循环
  OSStartHang
  B OSStartHang
  1:PendSV 异常服务函数 void OS_CPU_PendSVHandler(void)
 
OS_CPU_PendSVHandler
    CPSID   I                                                          ; 关中断,执行上下文切换的时候不能被中断,属于临界段
    MRS     R0, PSP                                                ; 加载PSP(即R13)的值到R0
    CBZ     R0, OS_CPU_PendSVHandler_nosave     ; R0的值为0则跳转到OS_CPU_PendSVHandler_nosave; CBZ:比较,如果结果为0就跳转
                                                                           ; 第一次进行上下文切换的时候PSP等于0,所以要进行跳转
                                                                                                                                                                                                                                                                
    SUBS    R0, R0, #0x20                                     ; 压栈之前先调整堆栈指针,要压栈的寄存器R4-R11有8个,所以偏移为8*0x04=0x20
    STM     R0, {R4-R11}                                       ; 手动将R4-R11压栈
 
    ; 实现 OSTCBCurPtr->OSTCBStkPtr = SP;
    LDR     R1, =OSTCBCurPtr                              ; R1=&OSTCBCurPtr,这个时候R1里面存的是OSTCBCurPtr这个指针变量的地址                
    LDR     R1, [R1]                                             ; R1=*R1=OSTCBCurPtr,这个时候,R1等于OSTCBCurPtr这个指针变量
    STR     R0, [R1]                                             ; *R1=R0,这个时候OSTCBCurPtr指向的TCB的第一个成员(即OSTCBCurPtr->OSTCBStkPtr)等于R0
                                                                        ; R0又是一开始进行压栈的PSP,所以OSTCBCurPtr->OSTCBStkPtr = SP
                                                                        ; 程序运行到这个点上,进入上下文切换的过程已经保存好了
OS_CPU_PendSVHandler_nosave
    PUSH    {R14}                                               ; 保存 LR exc_return 的值
    LDR     R0, =OSTaskSwHook                         ; 调用OSTaskSwHook()
    BLX     R0
    POP     {R14}
 
    ; 实现 OSPrioCur = OSPrioHighRdy;
    LDR     R0, =OSPrioCur                                ; R0=&OSPrioCur                                
    LDR     R1, =OSPrioHighRdy                         ; R1=&OSPrioHighRdy
    LDRB    R2, [R1]                                         ; R2=*R1(低字节),因为优先级是8bit的,所以是低字节
    STRB    R2, [R0]                                          ; R0=*R2(低字节),因为优先级是8bit的,所以是低字节
 
    ; 实现 OSTCBCurPtr = OSTCBHighRdyPtr;
                LDR     R0, =OSTCBCurPtr                ; R0=&OSTCBCurPtr                                  
    LDR     R1, =OSTCBHighRdyPtr                     ; R1=&OSTCBHighRdyPtr
    LDR     R2, [R1]                                           ; R2=*R1
    STR     R2, [R0]                                           ; R0=*R2
 
    LDR     R0, [R2]                                          ; R0等于新的进程的SP; SP = OSTCBHighRdyPtr->StkPtr
                                                                      ; R2=OSTCBHighRdyPtr,则[R2]=*R2=OSTCBHighRdyPtr=StkPtr,因为TCB的第一个成员就是StkPtr
    LDM     R0, {R4-R11}                                  ; 从新的堆栈中弹出R4-R11
    ADDS    R0, R0, #0x20                                ; 重新调整堆栈指针,R4-R11为8个寄存器,每个寄存器为四个字节,8*4=32=0X20
    MSR     PSP, R0                                          ; 更新PSP的值
    ORR     LR, LR, #0x04                                ; 判断LR寄存器的位4是否为1,确保异常返回用用的是PSP
    CPSIE   I                                                    ; 打开中断,上下文切换结束
    BX      LR                                                   ; 异常返回
 
    END                                                          ; 汇编程序结束
  ; 只有在特权级下,才可以访问下面三个寄存器
  ; PRIMASK :这是个只有单一比特的寄存器。 在它被置 1 后,就关掉所有可屏蔽的异常,只剩下 NMI 和硬 fault 可以响应。它的缺省值是 0,表示没有关中断。
  ; FAULTMASK:这是个只有 1 个位的寄存器。当它置 1 时,只有 NMI 才能响应,所有其它的异常,甚至是硬 fault,也通通闭嘴。它的缺省值也是 0,表示没有关异常。
  ; BASEPRI :这个寄存器最多有 9 位( 由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号
  ; 越大,优先级越低)。但若被设成 0,则不关闭任何中断, 0 也是缺省值。
  ;
  ; 为了快速的开关中断,CM3专门设置了一条CPS指令,有4种用法
  ; CPSID I //PRIMASK = 1, ;关中断
  ; CPSIE I //PRIMASK = 0, ;开中断
  ; CPSID F //FAULTMASK = 1, ;关异常
  ; CPSIE F //FAULTMASK = 0, ;开异常
 

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !