单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:5916|回复:0
打印上一主题下一主题

S3C2440中断过程详解(ADS,TQ2440)

[复制链接]
跳转到指定楼层
楼主
ID:68618发表于 2014-11-11 18:58|显示全部楼层回帖奖励
下面以串口UART0接收中断为例:
串口接收中断初始化时有这么一句:pISR_UART0=(unsigned)__irq UART0 _GetInt   /把 UART0 _GetInt这个中断服务子程序的入口地址放到pISR_TICK,
S3C2440addr.h中#define pISR_UART0  (*(unsigned *)(_ISR_STARTADDRESS+0x90))
option.inc中_ISR_STARTADDRESS EQU 0x33ffff00 //也就是中断服务子程序的入口地址放到0x33ffff00+0x90这个地址单元,即放入相应的中断向量表中,当中断发生时可通过查向量表(S3C2440addr.h最后有向量表,有这么一句HandleUART0  #   4,此处即放的UART0的中断入口地址)找到入口地址,执行中断服务子程序
再看S3C2440addr.h中下面几句指令,所在地址已标出,这些地址上的指令称为“异常向量”,当复位时,CPU进入系统模式,并跳到0x00地址执行, 再跳到ResetHandler   处执行相应的复位程序,其他异常也是一样的执行过程。
b ResetHandler   ;  @0x00
b HandlerUndef   ;  @0x04
b HandlerSWI     ;  @0x08
b HandlerPabort   ;  @0x0c
b HandlerDabort   ; @0x10
b .  ;reserved  ,保留@0x14
b HandlerIRQ       ;@0x18
b HandlerFIQ       ;@0x1c
言归正传,当中断(IRQ)发生时,CPU进入中断模式,并跳到0x18处执行b HandlerIRQ (在S3C2440addr.h中)这条指令,程序跳到HandlerIRQ HANDLER HandleIRQ(还在S3C2440addr.h中)处,此处将根据下面的宏定义展开:
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel     ;相当于$HandleIRQ
sub sp,sp,#4  ;sp=sp-4
stmfd sp!,{r0} ; r0内容保存到sp对应的栈中,应为入在下边用到所以先保存起来
ldr     r0,=$HandleLabel;   把HandleLabel这个地址放r0
ldr     r0,[r0]  ;  把HandleLabel这个地址的内容放r0
str     r0,[sp,#4]     ;把r0保存到sp+4的栈中,中断函数首地址HandleLabel入栈
ldmfd   sp!,{r0,pc}     ;   把sp对应的内容出栈放r0,sp+4放PC中,即原来保存的r0回复到r0,程序跳到HandleLabel,即HandleIRQ
MEND
上边这段程序执行完了之后,程序跳到HandleIRQ处执行,再看下面一段程序(S3C2440addr.h中),
ldr r0,=HandleIRQ     ;This routine is needed
ldr r1,=IsrIRQ   ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0]
2440启动时执行这段程序,此段程序即把IsrIRQ和HandleIRQ标号等价起来,接着上面,程序跳到HandleIRQ处执行即跳到IsrIRQ处,在看下面程序IsrIRQ(S3C2440addr.h中)查向量表找入口地址:
IsrIRQ
sub sp,sp,#4     ;给PC寄存器保留;reserved for PC
stmfd sp!,{r8-r9}; 把r8-r9压入栈
ldr r9,=INTOFFSET ;INTOFFSET的值在2440addr.inc中定义为0x4a000014,
                       ; 把中断偏移INTOFFSET寄存器的地址装入r9
ldr r9,[r9]               ;把中断偏移INTOFFSET寄存器内容装入r9,
ldr r8,=HandleEINT0; 这就是向量表的入口HandleEINT0装入r8,中断向量表的基址
add r8,r8,r9,lsl #2     ;R8=R8+(R9<<2) ,基址加变址得到中断向量表地址
ldr r8,[r8]   ; 装入中断服务程序的入口
str r8,[sp,#8]   ;把入口压入堆,
ldmfd sp!,{r8-r9,pc} ;出栈,入口地址给PC即跳到中断服务程序执行,
关于INTOFFSET看下面截图:

至此程序跳到C编写的中断服务程序中执行。
为什么上面都没讲到中断的现场保护和现场恢复,请看下面(摘抄):
中断服务函数往往带有__irq 这样的标识
关于__irq 的使用
__irq为一个标识,用来表示一个函数是否为中断函数。对于不同的编译器,__irq在函数名中的位置不一样,例如:
ADS编译器中 : void __irq IRQ_Eint0(void);
Keil编译器中 : void IRQ_Eint0(void) __irq;
但是其意义一样,它所完成的任务是标识该函数为中断函数,在编译器编译是调用此函数时,先保护函数入口现场,然后执行中断函数,
函数执行完毕,恢复中断现场,这整个过程不需要用户重新编写代码来完成,由编译器自动完成。当然也可以自己编写现场保护和恢复现场的代码。

手机版|小黑屋|51黑电子论坛|51黑电子论坛6群QQ管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网