您的位置 首页 被动

根据ARM异常中断处理的办法解析

基于ARM异常中断处理的方法解析-1. 在汇编中保存现场,然后调用C语言编写的中断处理程序,任务处理完成之后,再返回到汇编中恢复现场,并返回到断点。其中C语言编写的中断处理程序,通过switch语句对INTOFFSET进行判断,然后散转执行对应的服务函数。

介绍一种简练、高效、灵敏的ARM异常中止处理办法。

在ARM中,因为一切的中止都运用同一个异常中止进口地址,即0x00000018。因而需求在异常中止处理程序中依据相应的中止号调用对应的中止服务函数。

一般有两种处理方式:

1. 在汇编中保存现场,然后调用C言语编写的中止处理程序,使命处理完结之后,再回来到汇编中康复现场,并回来到断点。其间C言语编写的中止处理程序,经过switch句子对INTOFFSET进行判别,然后散转履行对应的服务函数。

IMPORT IRQ_EXCEPTION

0x00000018 LDR PC,=IRQ_ENTRY

IRQ_ENTRY

STMFD SP!,{R0-R8,LR}

BL IRQ_EXCEPTION

LDMFD SP!,{R0-R8,LR}

SUBS PC,LR,#4

void IRQ_EXCEPTION()

{

switch(INTOFFSET)

{

case 0:

break;

case 1:

break;

}

}

缺陷:1)一切的中止处理函数都必须在这个C文件中界说。

2)中止处理函数不能再程序履行进程中被替换。

3)因为不知道中止处理函数用到了哪些寄存器,因而维护现场时,需求把或许用到的一切作业寄存器

都维护起来。再加上C言语中的判别,这些过程都会添加中止呼应时刻。

2. 运用关键字__irq来界说每个中止处理函数,由编译器来刺进维护现场及中止回来的代码,因为编译器知道此函数用到了哪些寄存器,因而它只维护被用到的寄存器。接下来的问题是,当发生中止时,怎么直接调用对应的中止处理函数?

一般会在内存中分配32*4个存储单元,寄存每个中止处理函数的首地址,在汇编中,直接依据INTOFFSET从中止处理函数向量表中取出对应的函数首地址送给PC,直接调用对应的中止处理函数。C言语中需求借用函数指针将中止处理函数首地址写入到中止处理函数向量表里的对应方位上。

IRQ_HandlerStart EQU 0x33FFFF00

0x00000018 LDR PC,=IRQ_ENTRY

………… ………………………………

IRQ_ENTRY

SUB SP,SP,#4 ;为寄存中止处理函数首地址留出空间

STMFD SP!,{R0,R1,R2} ;维护下面的算法用到的作业寄存器

LDR R0,=INTOFFSET

LDR R1,[R0] ;取出中止号

LDR R2,=IRQ_HandlerStart

ADD R0,R2,R1,LSL #2 ;核算中止号对应的中止处理函数在向量表中的方位

LDR R1,[R0] ;取出对应的中止处理函数首地址

STR R1,[SP,#12] ;存储到方才预留的空间里

LDMFD SP!,{R0,R1,R2,PC} ;出栈,数据从左向右康复,最终将中止处理函数首地址给PC

#define ISR_StartAddr 0x33FFFF00

#define pISR_EINT0 (*(unsigned *)(ISR_StartAddr+0*4))

#define pISR_UART0 (*(unsigned *)(ISR_StartAddr+28*4))

void IniTISR()

{

pISR_EINT0 = EINT0_Handler;

pISR_TIMER0 = UART0_Handler;

}

void __irq EINT0_Handler()

{

………………

}

void __irq UART0_Handler()

{

………………

}

缺陷:1)要确保汇编与C中界说的中止处理函数向量表的首地址相同

2)要界说很多个函数指针,编写起来比较费事

咱们能够将中止处理函数向量表当作一个具有32个成员的数组,每个成员都是函数指针,指向的是无形参、无回来值的中止处理函数。咱们能够在汇编顶用SPACE关键字来界说这个函数指针数组变量,并为其分配空间。 在C言语中只需求用extern声明下它是外部界说的即可。

0x00000018 LDR PC,=IRQ_ENTRY

………… ………………………………

IRQ_ENTRY

SUB SP,SP,#4 ;为寄存中止处理函数首地址留出空间

STMFD SP!,{R0,R1,R2} ;维护下面的算法用到的作业寄存器

LDR R0,=INTOFFSET

LDR R1,[R0] ;取出中止号

LDR R2,=INTVECTOR ;获取函数指针数组首地址

ADD R0,R2,R1,LSL #2 ;核算中止号对应的中止处理函数在向量表中的方位

LDR R1,[R0] ;取出对应的中止处理函数首地址

STR R1,[SP,#12] ;存储到方才预留的空间里

LDMFD SP!,{R0,R1,R2,PC} ;出栈,数据从左向右康复,最终将中止处理函数首地址给PC

AREA INTVECT,DATA

INTVECTOR SPACE 32*4

为了将此函数指针数组变量分配到内存中,需求在涣散加载文件中指定这个段的履行域在内存空间

VECT_REGION 0x33FFFF00

{

StartUp.o(INTVECT)

}

typedef void __irq (*INTFUNC)(void); //函数指针类型重界说,

extern INTFUNC INTVECTOR[32];

void InitiISR()

{

INTVECTOR[0] = EINT0_Handler;

INTVECTOR[28] = UART0_Handler;

}

void __irq EINT0_Handler()

{

………………

}

void __irq UART0_Handler()

{

………………

}

特色:1)只需求在涣散加载文件中对这个中止处理函数向量表的首地址指定一次,防止犯错。

2)运用函数指针数组,省掉多个函数指针的界说。

3)在程序履行进程中,能够经过修正函数指针数组里的内容替换中止处理函数。

4)能够再界说一个中止注册函数,进步程序的灵敏性。

void ISR_Register(INT8U num,INT32U addr)

{

INTVECTOR[num] = addr;

}

以上说到的变量都能够只放在interrupt.c中,不同的中止处理函数能够在不同的文件中编写,它们只需求调用ISR_Register即可。这样能够进步程序的结构化。

别的,还能够将中止号用#define界说一下,以进步程序的可读性,如下:

#define INT_TIMER0 10

#define INT_UART0 28

#define INT_RTC 30

INTVECTOR[INT_UART0] = UART0_Handler;

INTVECTOR[INT_RTC] = RTC_Handler;

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/ziliao/beidong/346836.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部