在stm32移植ucos时PendSV_Handler的问题

2020-01-02 19:38发布

移植是建立在官网的历程,并参照了野火的教程。

野火的教程中没有使用OS_CPU_SysTickHandler(),而调用了stm32库中的systick-handler()。我也赞成这种方法,因为我认为为了统一代码,启动文件startup_stm32f10x_hd.s尽量少该,能不改就不改。

所以基于上述理由,pendsv中断函数,我也没有把启动文件中中断向量表的pendsd_handler改成OS_CPU_PendSVHandler,而是在stm32f10x_it.c作如下调用。
void PendSV_Handler(void)
{
    OS_CPU_PendSVHandler();
}


但是发现,ucos无法启动,而是停在了
CPSIE   I                                                   ; Enable interrupts at processor level

OSStartHang
    B       OSStartHang   


单步调的时候也有些麻烦,我用的是IAR,显示“ARM breakpoints can only be set on even points”, 貌似pendsv的代码在odd point,仿真不能。

我用MDK仿真野火给例程时没有出错,就以为是IAR的问题。纠结了一个晚上,也始终不得其解。后来没办法,开始仔细读《CM3权威指南》。
下面是我对此的解释。

在启动文件startup_stm32f10x_hd.s,跳转到中断服务程序时使用的时 B 指令,如 B PendSV_Handler,而在
void PendSV_Handler(void)
{
    OS_CPU_PendSVHandler();
}

汇编出来的代码,disassembly出来的是
PUSH    {R7,LR}
BL        OS_CPU_PendSVHandler
POP     {R0,PC}


在ucos 的 os_cpu_a.asm中OS_CPU_PendSVHandler的汇编代码是
OS_CPU_PendSVHandler
    CPSID   I                                                   ; Prevent interruption during context switch
    MRS     R0, PSP                                             ; PSP is process stack pointer
    CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time

    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
    STM     R0, {R4-R11}

    LDR     R1, =OSTCBCur                                       ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]                                            ; R0 is SP of process being switched out

                                                                ; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
    PUSH    {R14}                                               ; Save LR exc_return value
    LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();
    BLX     R0
    POP     {R14}

    LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;
    LDR     R1, =OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]

    LDR     R0, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, =OSTCBHighRdy
    LDR     R2, [R1]
    STR     R2, [R0]

    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    ADDS    R0, R0, #0x20
    MSR     PSP, R0                                             ; Load PSP with new process SP
    ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack
    CPSIE   I
    BX      LR                                                  ; Exception return will restore remaining context


其中    ORR     LR, LR, #0x04  会改变堆栈,由MSP改成PSP,故如果按我最开始的移植方法,
void PendSV_Handler(void)
{
    OS_CPU_PendSVHandler();
}

OS_CPU_PendSVHandler(); 结束时,应该还在中断服务程序中,但ORR     LR, LR, #0x04  已经改变了堆栈,不再是MSP,PendSV_Handler()再执行就会出错(因为堆栈指针,保存的寄存器已经被弹出)。


故在移植时不能在 PendSV_Handler() 中调用OS_CPU_PendSVHandler(), 因为OS_CPU_PendSVHandler()本质上已经是个完整的中断handdler。

其实在官网下载的文件包中 AN-1018.pdf 文件中已经说明(23页):
Note that you must place a pointer to OS_CPU_PendSVHandler() in the exception vector table at vector location 14 (based of the vector table +4*14 or, offset 56).

希望我的解释是对的,并对大家有帮助。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
8条回答
it_yrj
1楼-- · 2020-01-03 14:33
 精彩回答 2  元偷偷看……
micyoco
2楼-- · 2020-01-03 14:43
2楼的方法好用, 不用修改启动文件了。

一周热门 更多>