共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 跳转至页
回复
我要赚赏金打赏帖 |
|
|---|---|
| PCF8574功能模块及其使用被打赏¥20元 | |
| 传感器LSM6DSO及LIS3MDL的功能检测被打赏¥18元 | |
| LPS25HB气压传感器及其检测被打赏¥18元 | |
| HTS221温湿度传感器及其检测被打赏¥18元 | |
| 【S32K3XX】HSE FW 版本更新被打赏¥21元 | |
| 基于ArduinoUNO开发板的AT24C02读写测试被打赏¥16元 | |
| TCS3472S传感器及其色彩检测被打赏¥19元 | |
| 【S32DS】S32K3 RTD7.0.1 HSE 组件配置报错问题解决被打赏¥27元 | |
| 【S32K3XX】MCME 启动 CORE1被打赏¥23元 | |
| AG32VH407下温度大气压传感器及其检测被打赏¥20元 | |
我要赚赏金
