- UID
- 1029342
- 性别
- 男
|
NXP的ARM7带ucos中硬中断与软中断响应详细分析(2)
这部分程序也是移植时自己写的,里面有汇编。
其中的switch部分程序,对应的关系可以os_cpu.h文件中:
__swi(0x00) void OS_TASK_SW(void); /* 任务级任务切换函数 */
__swi(0x01) void _OSStartHighRdy(void); /* 运行优先级最高的任务 */
__swi(0x02) void OS_ENTER_CRITICAL(void); /* 关中断 */
__swi(0x03) void OS_EXIT_CRITICAL(void); /* 开中断 */
__swi(0x40) void *GetOSFunctionAddr(int Index); /* 获取系统服务函数入口 */
__swi(0x41) void *GetUsrFunctionAddr(int Index);/* 获取自定义服务函数入口 */
__swi(0x42) void OSISRBegin(void); /* 中断开始处理 */
__swi(0x43) int OSISRNeedSwap(void); /* 判断中断是否需要切换 */
__swi(0x80) void ChangeToSYSMode(void); /* 任务切换到系统模式 */
__swi(0x81) void ChangeToUSRMode(void); /* 任务切换到用户模式 */
__swi(0x82) void TaskIsARM(INT8U prio); /* 任务代码是ARM代码 */
__swi(0x83) void TaskIsTHUMB(INT8U prio); /* 任务代码是THUMB */
注意:上面的程序OS_TASK_SW任务切换,_OSStartHighRdy优先级最高的任务切换,不是在void SWI_Exception(int SWI_Num, int *Regs)函数中实现,被屏蔽了,直接改在OS_cpu_a.s文件中实现的:
;软件中断
SoftwareInterrupt
。。。。
为什么要调整在OS_cpu_a.s文件中实现,这个没有深入研究,我想应该都是可以的。
到现在整个软中断过程分析完了。
注意:上面的各个部分,每个阶段具体安排在哪里和哪个文件中,是可以认为改动的,甚至响应的形式也可以调整,但是每一个软中断的过程和要完成的工作是一样的,因为在用lpc21xx 系列时上面的整个程序结构基本一致的,现在用LPC23XX的时候有一些变化。
二.带UCOS系统的硬中断响应过程
硬中断,就是我们常说的中断,一般指的是外围设备中断,如串口,I2C,TCP,USB等。
硬中断一般分为普通和快速中断,对应上面所说的中断向量表中:
LDR PC, [PC, #-0xff0]
LDR PC, FIQ_Addr
如果发生了普通的硬中断,程序会跳到LDR PC, [PC, #-0xff0]行,由于对于一个ARM7不同的硬件中断响应时的入桟和出桟以及现场保护是相同的,所以写一个汇编的宏定义就可以实现多个硬中断响应共用,这个宏在IQR.INC有:
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
END
每个中断要申明一个宏,如:
/*定时器0中断*/
;/*Time0 Interrupt*/
Timer0_Handler HANDLER Timer0_Exception
其中:Timer0_Exception为自己的C响应中断函数。
说明:在上面的宏汇编程序中:
BL $IRQ_Exception_Function ; 调用c语言的中断处理程序
是每次中断响应时c语言的中断处理程序,这个是每个中断初始化时给每个中断向量地址的(对应nxp芯片的寄存器)。中断响应时会跳到中断向量表LDR PC, [PC, #-0xff0]行,然后系统根据中断响应的通道号值(NXP的arm7每个外围设备对应唯一的中断通道值,51里也是这样的,就是中断号)执行对应的宏汇编程序,在汇编里执行
BL $IRQ_Exception_Function ; 调用c语言的中断处理程序初始化时
这个IRQ_Exception_Function 对应与中断初始化时的函数,如定时器的:VICVectAddr0 = (uint32)Timer0_Handler; //定时器0中断函数地址分配
这样可以响应中断函数了。
注意:上面的硬件中断过程,也有可能写法不完全一致,但是对应nxp的ARM7的响应过程是一致的,对于快速中断响应过程也是一样的。 |
|