vxWorks中断处理.docx
- 文档编号:9163946
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:13
- 大小:70.36KB
vxWorks中断处理.docx
《vxWorks中断处理.docx》由会员分享,可在线阅读,更多相关《vxWorks中断处理.docx(13页珍藏版)》请在冰豆网上搜索。
vxWorks中断处理
Vxworks作为一个实时嵌入式操作系统,通常采用中断的方式来满足系统实时性的要求,因此,熟悉其中断的处理过程对于VxWorks操作系统的开发是至关重要的.本文通过编写和调试基于AT91RM9200处理器的VxWorks嵌入式操作系统的BSP,来讨论VxWorks操作系统的中断机制。
1VxWorks中断处理机制及AIC
AT91RM9200使用一个8优先级,可单独屏蔽中断的中断向量控制器AIC。
在ARM体系结构中,有7种异常中断,对应有一个异常中断向量表。
ARM体系结构要求这个异常中断向量表从0地址处开始,对于外部中断请求IRQ,系统又增加了一块由中断控制器控制的中断向量表。
2AT91RM9200BSP的中断驱动的实现
2.1中断驱动中定义的函数
STATUSat91rm9200LvlVecChk(int*,int*);
STATUSat91rm9200LvlVecAck(int,int);
STATUSat91rm9200LvlEnable(int);
STATUSat91rm9200LvlDisable(int);
2.2高级中断控制器AIC的初始化
在usrInit()中excVecInit()函数对异常中断向量进行初始化.整个中断库,以及中断控制器的初始化都是在syslib.c中的sysHwInit2()函数中完成的.该函数在sysClkConnect()中被调用,因为系统时钟中断要在内核开放中断后就要使能,因此内核在初始化为一个多任务环境后,就产生一个usrRoot()的任务,在该任务中要建立系统时钟中断,因此调用了sysClkConnect()函数,中断库以及中断控制器的初始化也就完成了。
高级中断控制器必须进行初始化,其初始化是在板级支持包BSP的中断驱动程序中。
具体的实现函数是voidat91rm9200IntDevInit(void)。
该函数在文件syslib.c的sysHwInit2()函数中调用。
at91rm9200IntDevInit(void)函数中主要是配置系统的钩子函数,然后对中断源向量寄存器和中断模式寄存器进行配置,同时要清除并禁止AIC中所有的中断。
2.3中断驱动中的回调函数
在intEnt中,程序很快就进入了特权模式(SVC32),如果是中断可嵌套模式,要设置该模式下的堆栈,并且将中断深度intCnt值加1.然后跳转到intIntRtnPreempt中,在intIntRtnPreempt中为后来调用中断驱动中的函数开辟了32个字节的堆栈空间,并且将程序指针拉到at91rm9200LvlVecChk函数处执行,at91rm9200LvlVecChk函数是在中断驱动中定义的函数,是用来检测当前挂起的中断中,优先级最高的中断源。
检测出最高优先级的中断后,首先要禁止该中断,因此要调用at91rm9200LvlDisable函数,该函数也在中断驱动中定义。
在禁止中断的过程中,需要通过intLock和intUnLock函数来保护临界代码不被新的中断打断。
at91rm9200LvlVecChk()函数是通过读AIC_IVR寄存器来获取当前最高优先级的中断,将获得的中断号和中断向量赋给2个变量,并且禁止该中断。
at91rm9200LvlVecAek()函数是在中断处理结束后,通过写AIC_EIOC寄存器来清除刚刚处理的中断,并将其使能。
at91rm9200LvlEnable(intleve1)和at91rm9200LvlDisable(intlevel)来允许和禁止中断,从而保护临界代码不被新的中断所打断。
2.4中断驱动程序实现的流程图
中断驱动程序实现的流程图如图1所示。
图1中断驱动程序实现的流程图
3VxWorks中断模块实现机制
3.1异常中断向量表的生成及实现
在usrInit()函数中通过intVecBaseSet((FUNCPTR*)VEC_BASE_ADRS)函数对异常中断向量表的基址进行设置,VEC_BASE_ADRS在configall.h中定义为程序运行空间的起始地址,但是在ARM中并没有中断基址寄存器,由于ARM9有重影射机制,可以将程序运行空间的起始地址影射成0地址,这也符合ARM体系结构通常都是把异常中断向量表放在0地址处的惯例,异常中断向量表可以从反汇编bootrom_uncmp后的0地址处看到。
当有内置的外设中断或外部中断产生时,系统首先跳转到异常中断向量表的0x18处,此处是IRQ中断向量的位置,该内存中放置的是一条跳转指令,因为excVecInit()对中断向量表初始化后,生成了一个exeEnterTbl,在这个表中列出了异常向量和对应入口函数的结构表,exeEnterTbl结构如图2所示。
图2excEnterTbl的结构
由于ARM9用了重影射机制,因此重影射之后,系统将LOCAL_MEM_LOCAL_ADRS影射成0地址,中断向量表从0地址处开始。
从excVecInit()的反汇编代码可以看出,系统把指令ldrpc,[pc,#244]的反汇编代码放在了从0x00000004开始的每个异常中断向量地址处,也就是将excEnterTbl中每个异常处理函数的入口地址都放在了(0xF4+0x8+0x4+所对应异常相对于未定义指令异常(0x00000004)的偏移)的内存中,这样就将异常向量和异常处理入口函数关联起来了。
3.2中断向量表的结构及生成
那么当系统产生中断后,VxWorks是如何设置中断向量表,并且将中断向量和中断处理入口程序关联起来的呢?
和异常向量表有点类似,但是中断向量表是VxWorks操作系统动态分配的一段连续的内存空间,这个空间的结构如图3所示。
图3VxWorks中断向量表的结构
因为是动态分配,所以在这段内存空间中,操作系统只给当前中断分配了中断号、中断处理函数的入口和被传递的参数。
每个中断源按照中断号顺序排列,在为每个中断源分配的内存空间中头4个字节是中断向量表的初始化函数的入口,该函数对于每个中断源来说是通用的,然后顺序放置的是中断号、中断处理函数入口和被传递的参数.通过intconnect()函数可以将中断向量和中断处理函数关联起来,因此在系统获知了发生中断的中断号时,就可以找到相应的中断处理函数去处理该中断。
当发生IRQ异常时,系统强制把程序指针拉到0x18处,在0x18处是这样一条指令ldrpc,[pc,#244],IRQ异常相对于未定义指令异常的偏移是0x14,所以相当于把0x114地址处的内容赋给pc,而0x114处的内容正是IRQ异常向量处理的入口函数intEnt的地址,因此程序跳转到intent处去执行。
4中断处理跟踪调试的部分反汇编代码
通过使用ARMDeveloperSite仿真器,在0x18处设置断点后单步执行来分析中断处理的过程。
中断处理函数的入口处代码如下:
2070b174[0xe59fb410]ldrr11,0x2070b58c; /*=#0x207a40c8,0x207a40c8是中断向量表的位置*/
2070b178[0xe59dc018]ldrr12,[r13,#0x18]/*将0x207b1ce8中的内容给r12应该是中断号!
!
!
*/
2070b17c[0xe59bb000]ldrr11,[r11,#0]/*0x207a40c8处的内容是0x21ffbef8*/
2070b180[0xe08b318c]addr3,r11,r12,lsl#3/*将0x21ffbef8(内存地址)给r3,0x21ffbef8的内容是向量0x207064b0,这是debug口中断处理函数的入口*/
2070b184[0xe79ba18c]ldrr10,[r11,r12,lsl#3]
2070b188[0xe5930004]ldrr0,[r3,#4]/*相应的参数传递给r0*/
2070b18c[0xe1a0e00f]movr14,pc
2070b190[0xe1a0f00a]movpc,r10/*r10=0x207064b0,跳转到debug口中断处理函数处执行*/
0x21ffbef8(中断向量表基址)处的情况是:
21ffbef8[0x2070b434]dcd0x2070b4344.p
21ffbefc[0x00000000]dcd0x00000000....
21ffbf00[0x207064b0]dcd0x207064b0.dp
21ffbf04[0x207a9990]dcd0x207a9990..z
21ffbf08[0x2070b434]dcd0x2070b4344.p
21ffbf0c[0x00000002]dcd0x00000002....
21ffbf10[0x2070b434]dcd0x2070b4344.P
21ffbf14[0x00000003]dcd0x00000003....
21ffbf18[0x2070b434]dcd0x2070b4344.P
21ffbf1c[0x00000004]dcd0x00000004....
5结语
Vxworks操作系统首先调用excVecInit()生成一个异常中断向量表excEnterTbl,当有IRQ中断发生时,根据excEnterTbl中0x00000018处的指令ldrpc,[pc,#244]跳转到0x00000114处,即IRQ异常中断的入口处intEnt执行,随后通过读AIC_IVR寄存器得到当前优先级最高的中断,返回这个中断号,并跳转到intConnect()函数给该中断号关联的中断处理程序入口去执行。
在这个过程中,中断向量表的生成是Vxworks动态分配的,在AT91RM9200中,为0到31号中断源在中断向量表中都分配了空间,该空间的格式固定。
中断处理结束后,通过往AIC_EIOC寄存器中写任意值,从中断中返回。
点灯调试S3C44B0vxworksBSP
1.romInit的调试方法:
/*************点亮0号端口的LED,验证内存配置是否成功*******************/
LDRr1,L$_PCONC
LDRr2,L$_PCONC_VALUE
STRr2,[r1]
LDRr1,L$_PUPC
LDRr2,L$_PUPC_VALUE
STRr2,[r1]
LDRr1,L$_PDATC
LDRr2,L$_PDATC_LED0
STRr2,[r1]
B./*为了防止后面语句的影响,用该语句进行无限循环,使用ADS进行内存访问*/
/*****************************************************************************/
2.C函数的调试方法
#defineIOPDATA(*(volatileunsigned*)(0x1d20014))
IOPDATA=0xFFF8;
while
(1);
/*****************代码运行到此函数,2004-10-10,9:
39******************/
3.中断处理函数的调试方法:
验证时钟中断服务程序是否工作正常
voidsysClkInt(void)
{
if(intTimers==0)
{
IOPDATA=0xFFF2;/*点亮LED1*/
intTimers=1;
}
else
{
IOPDATA=0xFFF1;/*熄灭LED1*/
intTimers=1;
}
if(sysClkRoutine!
=NULL)
(*sysClkRoutine)(sysClkArg);
}
关于xworks中断的处理函数实现:
STATUSintEnable(intlevel/*leveltobeenabled*/)
{
return(*sysIntLvlEnableRtn)(level);/*在自己的BSP中实现*/
}
STATUSintDisable(intlevel/*leveltobedisabled*/)
{
return(*sysIntLvlDisableRtn)(level);
}
STATUSintConnect
(
VOIDFUNCPTR*vector,/*vectorid*/
VOIDFUNCPTRroutine,/*interruptserviceroutine*/
intargument/*argumentforisr*/
)
{
intvecNum;
VEC_ENTRY*pVec;
if(intVecTable==NULL)
returnERROR;/*librarynotinitialized*/
vecNum=IVEC_TO_INUM(vector);
/*checkvectorspecifiedisinrangeallocated*/
if(vecNum<0||vecNum>=intNumVectors)
returnERROR;
pVec=&intVecTable[vecNum];
if(routine==NULL)
{
routine=intUninitVec;
argument=vecNum;
}
pVec->routine=routine;
pVec->arg=argument;
returnOK;
}
STATUSintLibInit
(
intnumLevels,/*numberoflevels*/
intnumVectors,/*numberofvectors*/
intmode/*typeofinterrupthandling*/
)
{
inti;
if(intVecTable==NULL)
{
/*Allocateandinitializethevectortable*/
intVecTable=malloc(numVectors*sizeof(VEC_ENTRY));
if(intVecTable!
=NULL)
{
intNumVectors=numVectors;
/*initializetablewithuninitializedvechandler*/
for(i=0;i { intConnect(INUM_TO_IVEC(i),NULL,0); } /*connectarchitectureinterruptexception*/ if(mode&INT_PREEMPT_MODEL) EXC_CONNECT_INTR_RTN(intIntRtnPreempt); else EXC_CONNECT_INTR_RTN(intIntRtnNonPreempt); returnOK; } returnERROR;/*mallocfailure*/ } returnOK;/*alreadyinitialized*/ } STATUSexcVecInit(void) { FASTinti; /*initialiseARMexceptionmoderegisters*/ armInitExceptionModes(); /*initialisehardwareexceptionvectors*/ for(i=0;i { /* *EachvectorcontainsaLDRPC,[PC,#offset]instructionto *loadthePCfromatableofaddressesstoredat *EXC_VEC_TABLE_BASE.Thisallowsfull32bitaddressingrather *than12bit(MOV#)or24bit(B). */ *(UINT32*)excEnterTbl[i].vecAddr=0xE59FF000| (EXC_VEC_TABLE_BASE-8-FIRST_VECTOR); *(VOIDFUNCPTR*) (excEnterTbl[i].vecAddr+EXC_VEC_TABLE_BASE-FIRST_VECTOR)= excEnterTbl[i].fn; } /* *Branchthroughzerohastobehandleddifferentlyifitis *possibleforaddress0tobebebranchedtoinARMandThumb *states(noLDRpc,[pc,#n]inThumbstate).Thefollowing *instruction,installedataddress0,willcauseanundefined *instructionexceptioninbothARMandThumbstates. */ *(UINT32*)EXC_OFF_RESET=0xE7FDDEFE; /*nowsortouttheinstructioncachetoreflectthechanges*/ CACHE_TEXT_UPDATE(EXC_OFF_RESET,EXC_OFF_IRQ+4); /*installdefaultIRQhandler*/ _func_armIrqHandler=excIntHandle; returnOK; } 中断的调试: 1.验证romInit.s能否捕获中断,中断控制器能否正确产生中断,在romInit.s的IRQ中断处理入口处点灯: _romIRQ: SUBsp,sp,#4 STMFDsp! {r1} /******点亮1号端口的LED,验证是否捕获到中断**************************************/ LDRr1,L$_PDATC LDRr2,L$_PDATC_LED0 STRr2,[r1] /****************************************************************************************/ LDRr1,L$_IRQVec LDRr1,[r1] STRr1,[sp,#4] LDMFDsp! {r1,pc} 为了验证中断发生时,是否可以跳转到intEnter中处理,写了如下测试代码替代intEnter: voidsysKeyInt(void) { FS44B0XIntLvlVecAck(21,21); if(IOPDATA&(0x08)! =0x08) IOPDATA=0xFFF8;/*点亮LED*/ else IOPDATA=0xFFF1;/*熄灭LED*/ } voidFS44B0XExcVecSet(void) { inti; i=(int)&excEnterUndef; *(volatileint*)(S3C_EXE_BASE+0x0)=i; i=(int)&excEnterSwi; *(volatileint*)(S3C_EXE_BASE+0x4)=i; i=(int)&excEnterPrefetchAbort; *(volatileint*)(S3C_EXE_BASE+0x8)=i; i=(int)&excEnterDataAbort; *(volatileint*)(S3C_EXE_BASE+0xC)=i; i=(int)&sysKeyInt;/*intEnt;*/ *(volatileint*)(S3C_EXE_BASE+0x14)=i; return; } 为了验证intEnter函数是否被执行,添加如下调试代码: STATUSFS44B0XIntLvlVecChk ( int*pLevel,/*ptrtoreceiveoldinterruptlevel*/ int*pVector/*ptrtoreceivecurrentinterruptvector*/ ) { intnewLevel; intintPendMask=0x2000000;/*0~26位为正常中断,27位保留*/ intcount; UINT32isr; inti; for(i=0;i<5;i++) { Delay(2000); Led_DisplayOn(0x01);/*VPINT(FS44B0X_PDATC)=0xFFF2;点亮第1盏灯*/ Delay(2000); Led_DisplayOn(0x02);/*VPINT(FS44B0X_PDATC)=0xFFF4;*/ } Led_DisplayOn(0x02); /*Readpendinginterruptregisterandmaskundefinedbits*/ FS44B0X_INT_REG_READ(FS44B0X_INT_PEND,newLevel); /* *Stepthroughthebitslookingfora1.This*will*terminate. *WecoulduseffsLsb()forthisifwedon'tmindthefunctioncall *overhead */ for(count=0,isr=25;count
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- vxWorks 中断 处理