共2条
1/1 1 跳转至页
smartARM2200uC,OSII,for,ARM7 关于smartARM2200uC/OSII for ARM7通用中断服务程序的疑惑

问
MACRO
$IRQ_Label HANDLER $IRQ_Exception_Function
EXPORT $IRQ_Label ; 输出的标号
IMPORT $IRQ_Exception_Function ; 引用的外部标号
$IRQ_Label
SUB LR, LR, #4 ; 计算返回地址
STMFD SP!, {R0-R3, R12, LR} ; 保存任务环境
MRS R3, SPSR ; 保存状态
STMFD SP, {R3, SP, LR}^ ; 保存用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R2, =OSIntNesting ; OSIntNesting++
LDRB R1, [R2]
ADD R1, R1, #1
STRB R1, [R2]
SUB SP, SP, #4*3
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
CMP R1, #1
LDREQ SP, =StackUsr
BL $IRQ_Exception_Function ; 调用c语言的中断处理程序
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
LDR R2, =OsEnterSum ; OsEnterSum,使OSIntExit退出时中断关闭
MOV R1, #1
STR R1, [R2]
BL OSIntExit
LDR R2, =OsEnterSum ; 因为中断服务程序要退出,所以OsEnterSum=0
MOV R1, #0
STR R1, [R2]
MSR CPSR_c, #(NoInt | IRQ32Mode) ; 切换回irq模式
LDMFD SP, {R3, SP, LR}^ ; 恢复用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R0, =OSTCBHighRdy
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1
ADD SP, SP, #4*3 ;
MSR SPSR_cxsf, R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不进行任务切换
LDR PC, =OSIntCtxSw ; 进行任务切换
MEND
以上是源码,让我疑惑的地方就是 BL OSIntExit
当调用OSIntExit后,如果须做任务切换,则在OSIntExit()内调用OSIntCtxSw()进行任务切换,然后退出中断运行新任务。但是通用中断程序最后两句是:
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不进行任务切换
LDR PC, =OSIntCtxSw ; 进行任务切换
既然已经在OSIntExit()进行了任务切换,而且退出中断了,为什么还要在通用中断程序最后加上
LDR PC, =OSIntCtxSw ; 进行任务切换
而且,如果在OSIntExit()进行了任务切换,就自然运行不到
LDMFD SP, {R3, SP, LR}^ ; 恢复用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
这样,堆栈的结构就不符合LR,R12,R3,R2,R1,R0这种情形,在调用OSIntCtxSw()时就会出错。
但是周公的书一般出错的可能性不大,但是我又搞不懂这段逻辑,所以请高手们提携我一把,谢谢!
答 1: 没认真看。不过觉得很容易理解,只是一种预防机制。如果正常切换了只是一段不运行的‘死’代码。 答 2: OSIntCtxSw()是includes.h里面的一个宏定义OSIntExit()并没有进行任务切换,调用OSIntCtxSw()只是从OSIntExit()函数中返回。
$IRQ_Label HANDLER $IRQ_Exception_Function
EXPORT $IRQ_Label ; 输出的标号
IMPORT $IRQ_Exception_Function ; 引用的外部标号
$IRQ_Label
SUB LR, LR, #4 ; 计算返回地址
STMFD SP!, {R0-R3, R12, LR} ; 保存任务环境
MRS R3, SPSR ; 保存状态
STMFD SP, {R3, SP, LR}^ ; 保存用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R2, =OSIntNesting ; OSIntNesting++
LDRB R1, [R2]
ADD R1, R1, #1
STRB R1, [R2]
SUB SP, SP, #4*3
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
CMP R1, #1
LDREQ SP, =StackUsr
BL $IRQ_Exception_Function ; 调用c语言的中断处理程序
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
LDR R2, =OsEnterSum ; OsEnterSum,使OSIntExit退出时中断关闭
MOV R1, #1
STR R1, [R2]
BL OSIntExit
LDR R2, =OsEnterSum ; 因为中断服务程序要退出,所以OsEnterSum=0
MOV R1, #0
STR R1, [R2]
MSR CPSR_c, #(NoInt | IRQ32Mode) ; 切换回irq模式
LDMFD SP, {R3, SP, LR}^ ; 恢复用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R0, =OSTCBHighRdy
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1
ADD SP, SP, #4*3 ;
MSR SPSR_cxsf, R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不进行任务切换
LDR PC, =OSIntCtxSw ; 进行任务切换
MEND
以上是源码,让我疑惑的地方就是 BL OSIntExit
当调用OSIntExit后,如果须做任务切换,则在OSIntExit()内调用OSIntCtxSw()进行任务切换,然后退出中断运行新任务。但是通用中断程序最后两句是:
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不进行任务切换
LDR PC, =OSIntCtxSw ; 进行任务切换
既然已经在OSIntExit()进行了任务切换,而且退出中断了,为什么还要在通用中断程序最后加上
LDR PC, =OSIntCtxSw ; 进行任务切换
而且,如果在OSIntExit()进行了任务切换,就自然运行不到
LDMFD SP, {R3, SP, LR}^ ; 恢复用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
这样,堆栈的结构就不符合LR,R12,R3,R2,R1,R0这种情形,在调用OSIntCtxSw()时就会出错。
但是周公的书一般出错的可能性不大,但是我又搞不懂这段逻辑,所以请高手们提携我一把,谢谢!
答 1: 没认真看。不过觉得很容易理解,只是一种预防机制。如果正常切换了只是一段不运行的‘死’代码。 答 2: OSIntCtxSw()是includes.h里面的一个宏定义OSIntExit()并没有进行任务切换,调用OSIntCtxSw()只是从OSIntExit()函数中返回。
共2条
1/1 1 跳转至页
回复
打赏帖 | |
---|---|
汽车+汽车地线之间连接处理被打赏20分 | |
【Zephyr】使用Zephyr外设初始化过程解析被打赏30分 | |
【S32K146】S32DS watchdog 配置使用被打赏20分 | |
【Zephyr】使用 IAR 调试 Zephyr 镜像被打赏20分 | |
赚取电动螺丝刀+电源电路理论知识分享1被打赏5分 | |
我想要一部加热台+分享常见运算放大器电路的应用被打赏5分 | |
【Zephyr】MCXN947 Zephyr 开发入门适配shell被打赏20分 | |
我想要一部加热台+常见的MOS管驱动电路被打赏5分 | |
【我要开发板】6.联合MATLAB记录数据被打赏50分 | |
【换取手持数字示波器】MicrochipMPLABHarmony框架下串口调试printf输出记录被打赏29分 |