OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5476|回复: 4

UCOS-III中断程序编写的疑问

[复制链接]

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
118
金钱
118
注册时间
2015-9-7
在线时间
8 小时
发表于 2015-12-7 15:33:21 | 显示全部楼层 |阅读模式
5金钱
1.在学习ucos-iii时,看到资料的工程---SYSTEM文件夹---usatr.c中的串口中断中断服务程序void USART1_IRQHandler(void) 如下:
void USART1_IRQHandler(void)                 //串口1中断服务程序
{
……
OSIntEnter();    
………………//省略了串口的代码。
OSIntExit();    
……

在这个程序中,体现了ucos-iii中断的编写模板。
对于Cortex-M3内核的异常来说,进入异常自动保存SR\PC\R12\R0~R3,那剩下的R4~R11寄存器的保存怎么在如上的
串口1中断服务程序”找不到相关代码呢?查看了一下OSIntEnter()中确实没有啊。源代码如下:
void  OSIntEnter (void) 
{
    if (OSRunning != OS_STATE_OS_RUNNING) {                 /* Is OS running?                                         */
        return;                                             /* No                                                     */
    }
    if (OSIntNestingCtr >= (OS_NESTING_CTR)250u) {          /* Have we nested past 250 levels?                        */
        return;                                             /* Yes                                                    */
    }
    OSIntNestingCtr++;                                      /* Increment ISR nesting level                            */
}
为什么?

最佳答案

查看完整内容[请看2#楼]

问题已经解决。详见cortex-M3权威指南的136页
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
118
金钱
118
注册时间
2015-9-7
在线时间
8 小时
 楼主| 发表于 2015-12-7 15:33:22 | 显示全部楼层
问题已经解决。详见cortex-M3权威指南的136页
回复

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2015-12-7 18:44:31 | 显示全部楼层
剩下的R4~R11是手动不保存的,典型的看资料不认真!我们的UCOS教程对这个有非常详细的讲解!
开往春天的手扶拖拉机
回复

使用道具 举报

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
118
金钱
118
注册时间
2015-9-7
在线时间
8 小时
 楼主| 发表于 2015-12-8 15:30:15 | 显示全部楼层
回复【2楼】zuozhongkai:
---------------------------------

对于初始化阶段OSStartHighRdy和任务级调度器OSCtxSw、中断级调度器OSIntCtxSw来说都是通过挂起PendSV异常实现的任务切换。因此重点在PendSV异常的编写。

由于OSStartHighRdy之前已经使用C语言编写的OSTaskStkInit()函数(位于cpu_core.c)将现场初始化完毕,因此进入PendSV后执行执行PendSVHandler_nosave 之后的代码。而任务级调度器OSCtxSw、中断级调度器OSIntCtxSw将会执行PendSV异常所有的代码。

 我的疑问如下:

PendSV异常之外的其他异常的模型和初始化阶段OSStartHighRdy和任务级调度器OSCtxSw、中断级调度器OSIntCtxSw稍稍有些不同,不难发现PendSV一开始就赶紧保存R4~R11,但为什么其他异常刚进入后却不需要先保存R4~R11,而仅在最后才使用OSIntExit()在确定会发生调度时才保存R4~R11

 

Void xxxxx_xxxHandler(void)  //endSV异常之外的其他异常的“C代码”模型

{ OSIntEnter();   

    中断服务代码; 

OSIntExit();    

 

在进入异常时切换为handler mode,这种模式下是“privileged LEVEL特权模式”,所有的通用寄存器R0~R7(Low registers)+R8~R12(high registers)都可以使用。对于使用C编写的中断服务函数(如上模型),编译为机器码后难道只使用R0~R3R12而不会对R4~R11造成破坏?

 版主大人,怎么看?

 

;//////////////////////////////////os_cpu_a.s///////////////////////////////////////////

OSStartHighRdy

    LDR     R0, =NVIC_SYSPRI4                                  ; Set the endSV exception priority

    LDR     R1, =NVIC_PENDSV_PRI

    STRB    R1, [R0]

;NVIC_SYSPRI4是配置PendSV优先级的寄存器的物理地址。NVIC_PENDSV_PRI是将要配置的PendSV的优先级别,通过宏定义可知,

;要将PendSV的优先级设置为255.注:这是cortex-M3的最低优先级。

 

 

;Cortex-M3内核提供了两个堆栈指针MSPPSP。在《Cortex-M3 Devices Generic User Guide.pdf》的2.13节的介绍如下

;////////////////////////////

;Stack ointer

;The Stack ointer (SP) is register R13. In Thread mode, bit[1] of the CONTROL register

;indicates the stack pointer to use:

; 0 = Main Stack ointer (MSP). This is the reset value.

; 1 = rocess Stack ointer (PSP).

;On reset, the processor loads the MSP with the value from address 0x00000000.

;///////////////////////////////////

;下面5句话的作用:将PSR清零+将“异常的堆栈基地址赋”给MSP

    MOVS    R0, #0                                              ; Set the SP to 0 for initial context switch call

    MSR     SP, R0

 

    LDR     R0, =OS_CPU_ExceptStkBase                           ; Initialize the MSP to the OS_CPU_ExceptStkBase

    LDR     R1, [R0]

    MSR     MSP, R1    

;uC/OS-III专门为异常提供了一个堆栈空间,其基地址为OS_CPU_ExceptStkBase

;如上3句话的作用:将异常的堆栈的基地址给堆栈指针MSP.

 

 

    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the endSV exception (causes context switch)

    LDR     R1, =NVIC_PENDSVSET

    STR     R1, [R0]

;上边的三句汇编完成了对PendSV的挂起(触发)。挂起PendSV的唯一方法就是置位ICSRbit[28]位。

;NVIC_INT_CTRL就是ICSR寄存器的地址。NVIC_PENDSVSET=0x10000000。都是宏定义。

;1句: 将ICSR寄存器的地址NVIC_INT_CTRL放在R0中。

;2句: 将NVIC_PENDSVSET放在R1中。

;3句: 将R1放进R0所指向的存储器地址。也就是说向存储器的NVIC_INT_CTRL处(即ICSR寄存器)写入NVIC_PENDSVSET

;说白了,这3句的作用就是将0x10000000写入到ICSR寄存器。这样一来,ICSRbit[28]位被置位,即将PendSV挂起了。

    CPSIE   I                                                   ; Enable interrupts at processor level

 

;///////////

OSStartHang

    B       OSStartHang                                         ; Should never get here

 

;/////////

 

OSCtxSw

    LDR     R0, =NVIC_INT_CTRL    ; Trigger the endSV exception (causes context switch)

    LDR     R1, =NVIC_PENDSVSET

    STR     R1, [R0]

    BX      LR

;//////////////

 

OSIntCtxSw

    LDR     R0, =NVIC_INT_CTRL         ; Trigger the PendSV exception (causes context switch)

    LDR     R1, =NVIC_PENDSVSET

    STR     R1, [R0]

    BX      LR


;/////////////////////

 

PendSV_Handler

    CPSID   I                                        ; Prevent interruption during context switch;关中断

    MRS     R0, PSP                                  ; PSP is process stack pointer;PSP的值写入到R0中。

    CBZ     R0, PendSVHandler_nosave                 ; Skip register save the first time

;如果R0=0则跳转到PendSVHandler_nosave处执行。PendSVHandler_nosave是个汇编编写的子函数。

;c代码的等价转化:   ifR0==0PendSVHandler_nosave();

 

    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack

    STM     R0, {R4-R11}

 

    LDR     R1, =OSTCBCurPtr                                    ; OSTCBCurPtr->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

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, =OSTCBCurPtr                                    ; OSTCBCurPtr = OSTCBHighRdyPtr;

    LDR     R1, =OSTCBHighRdyPtr

    LDR     R2, [R1]

    STR     R2, [R0]

 

    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;

    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

 

    END

回复

使用道具 举报

12

主题

126

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
281
金钱
281
注册时间
2013-1-5
在线时间
22 小时
发表于 2015-12-18 21:27:58 | 显示全部楼层
以本为本还是有道理的,学习了
天道酬勤
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 16:24

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表