引言
硬件中断处理在实时操作系统设计中起着十分重要的作用,它是外部事件通知操作系统的最常用手段。中断的正常运行是操作系统稳定工作的先决条件。VxWorks作为一款优秀的实时嵌入式系统,通常采用中断的方式来满足系统实时性要求。因此,熟悉其中断的处理过程对于VxWorks操作系统的开发至关重要。本文通过基于S3C44B0X处理器VxWorks嵌入式操作系统的BSP移植,详细分析了VxWorks操作系统基于ARM处理器的中断处理方法。
1 ARM异常中断处理
ARM体系结构支持复位(Reset)等7种异常中断类型,各异常中断的向量地址及中断的处理优先级如表1所示。当异常中断发牛时,硬件逻辑根据异常类型给程序计数器(PC)强制赋值,使程序从表1给出的相应的矢量地址开始执行异常处理程序。在异常中断向量表中指定了各异常中断与其处理程序的对应关系,一般来说,矢量地址处将包含一条指向相应程序的转移指令,从而可跳转到相应的中断服务程序。异常中断向量表存放在存储器的0地址处,大小为32字节,每个异常中断占4字节大小,保留了4字节空间。
表1 各异常中断的向量地址以及中断处理优先
b.gif
S3C44BOX的中断控制器町以接收来自26个中断源的30个中断请求,其中有4个外部中断(EINT/4/5/6/7)是逻辑或的关系,它们共用一条中断请求线。当片内外围中断和片外中断模式设定为IRQ时,如有多重中断发生,中断控制器经过优先级判断选择其中一个中断,通过IRQ向ARM7TDMI内核发出IRQ中断请求。另外.在中断服务程序中需特别注意:必须加入对L_ISPC或F_ISPC寄存器相应的中断位写1操作,来清除只读中断挂起寄存器INTPEND的挂起位,以使中断正常运行。
2 VxWorks中断处理机制
VxWorks中断处理主要包括:保存被中断任务的上下文,调用中断服务程序(ISR),中断返回恢复被中断任务的上下文,其具体流程如图1所示。对被中断任务现场信息的保存,在S3C44B0处理器体系结构中,VxWorks采用集中式的保存方式,即在内存中专门设置一个中断保存堆栈.所有中断的现场信息都统一保存在此堆栈中。堆栈的定位和大小初始化依据指定参数在系统启动时进行配置。对于堆栈的大小,必须足够大,以满足最坏情况下中断嵌套的深度。
1.gif
图1 VxWorks中断处理执行流程
2.1 异常向量表的生成及实现
当异常发生时,程序计数器(PC)会被强制为相应异常处理程序的入口地址.然后进行中断源的识别,根据中断号在中断向量表中找到相应中断服务程序(ISR)的入口地址。VxWorks将异常向量表定位在RAM中,基地址为VEC_BASE_ADRS,在configA11.h中定义.一般为RAM存储器的起始地址。在系统启动初始化时,由intVecBaseSet()函数设置向量表的基地址。向量表地址设定后,需要初始化指定异常的缺省处理函数。VxWorks在映像的代码段建立了一张中断缺省函数表,函数excVecInit()根据这张表来设置向量表的各异常中断向量值。需初始化的向量表范围由LOW_VEC和HIGH_VEC确定,在excArchLib.h中定义。由于不同的处理器异常处理机制不同,有时需根据具体的异常处理来建立自己的异常向量表,具体建立实现过程在下面讨论。
2.2 中断服务程序的连接
VxWorks为中断提供接口函数intConnect(),它将中断服务程序(ISR)和中断向量相关联。在操作系统内核启动后,VxWorks建立与中断号相对应的中断向量表,中断向量表中的每个中断向量包含中断服务程序(ISR)的入口地址。当中断事件发生时.VxWorks内核将调用与其中断向量对应的中断服务程序。intConnect()原型如下:
STATUS intConnect
(
VOIDFUNCPTR * vector, /* 要关联的中断向量 */
VOIDFUNCPTR routine, /*中断发生时调用的函数 */
int parameter /*传递给lsR函数的参数*/
)
但实际上,中断出现时并不是直接调用指定的中断处理函数。而是,intConnect()函数将创建一小段代码,这段代码用以保存必要寄存器、设置堆栈入口、之后调用中断处理函数。相反,当从该函数返回时,这段代码先恢复寄存器和堆栈,然后退出中断。
3 VxWorks基于S3C44B0X的中断处理
3.1 基于S3C44B0X处理器的VxWorks异常向量表的生成S3C44BOX处理器不支持内存重定向操作,也就是每个片选的地址范围是定死的,不能根据需要自己指定。启动flash存储器一直位于0地址,异常人口不能在运行时写入,故必须硬编码将异常入口填写在启动flash的0地址处。romInit.s是系统上电时的初始人口程序.从flash的0地址开始运行。故在其开始出定义异常入口程序实现如下:
_ARM_FUNCTION(romInit)
_romInit:
B cold /* 上电复位后执行的第1条指令,也可看作是复位向量 */
⋯ /* 未定义指令、软件中断等异常入口 */
B .
B _romIRQ /* IRQ中断异常入口 */
B .
在地址Ox00000014处S3C44B0X处理器未使用,保留。另外VxWorks不支持快速中断.地址Ox0000001c保留。
由于VxWorks建立的异常向量表定位在RAM中.那么当中断发生时如何把两者连接起来.从而由VxWorks实现中断管理呢?本BsP根据VxWorks缺省异常向量表,建立自定义的向量表,实现从ROM到RAM异常的连接,总体程序如下:
/* _romIRQ 及其它函数定义 */
_romIRQ;
sub sp,sp,#4
stmfd sq1 , (r0)
ldr r0,L$_promIRQ
ldr r0,[r0] /* 装载IRQ异常地址到R0 */
str r0,[sp,#4]
ldmfd sp!,{r0,pc} /* 跳转到异常服务程序 */
/* _romIRQ指向RAM中的位置 */
L$_promIRQ:
.long S3C_EXC_BASE + 20 /* #define S3C_EXC_BASE 0x0c000100 */
/* 在真正RAM空间建立异常向量表,和VxWorks建立的向量表相同,只是位置不同 */
void s3cExcVecSet(void)
{
UINT32 i:
。..
i=(UINT32)intEnt;
*((UINT32 *)(S3C_EXC_BASE + Ox14))=i;
}
对以上代码分析:当中断发生时.程序跳转到_romIRQ处,然后执行出栈操作,把L$_promIRQ地址(0x0c000114=(s3c_EXC_BASE + 20))的内容赋给程序计数器(PC);而上述vxwofks在RAM空间建立异常向量表时,把异常中断服务程序(intEnt)的地址放在地址0x0c00Oll4(s3C_EXC_BASE + 0x14)中,即PC=(UINT32) intEnt实现从ROM到RAM中断的连接。
3.2 中断驱动中的回调函数
VxWorks中intArchLib库所包含的中断系统函数与具体的处理器体系结构相关.其默认体系结构中不包含ARM处理器,所以此库中的函数都要依赖于具体BsP提供的例程来完成其功能。VxWorks采用Hook的方法来实现,针对本处理器的BSP,在sngkcIntrCtl.c文件中,定义了四个钩子函数:
sysIntLvlVecChkRtn = sngks32cIntLvlVecChk;/* 中断源检测,返回中断号 */
sysIntLvlEnableRtn = sngks32cIntLvlEnable; /* 使能相应中断 */,
svslntLvlDisableRtn = sngks32cIntLvlDisable; /* 禁止相应中断 */,
svsIntLvlvecAckRtn = sngks32cIntLvLAck; /* 清除中断标志位 */,
用来完成中断驱动。当外部中断发生时,程序进入intEnt函数,运行sysIntLvlVecChkRm钩子函数读中断服务挂起寄存器(I_ISPR)来检测中断源,并返回中断号,通过在intConnect函数中建立的中断向量与中断服务函数的连接,从而调用相应的中断服务程序。在中断返回时.执行sysIntLvlvecAckRtn钩子函数通过写IRQ中断挂起清零寄存器(I_ISPC),来清除刚处理完的中断挂起位。完整的VxWorks基于S3C44BOX处理器的中断响应流图如图2所示:
2.gif
图2 VxWorks基于S3C44B0X处理器的中断响应流图
4 实例分析
外部中断EINT4/5/6/7共用一个中断请求线,当其中一个中断发生时,中断挂起寄存器(INTPND)的EINT4/5/6/7位置1.具体是其中哪个发生中断可通过读外部中断挂起寄存器(EXTINTPND)来判断。
中断服务程序连接
intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC(21),
(VOIDFUNCPTR)isr4567,0)
外部中断使能
intEnable(21); /* 触发钩子函数 */
svsIntLvlEnableRtn; /* 清中断屏蔽寄存器(INTMSK)的EINT4/5/6/7位使能中断? */
中断服务程序:
void isr4567(void)
{
int j;
intDisable(21); /* 关中断 */
S3C44B0X_INT_REG_READ (S3C44BOX_EXTINTPND,j);/*读外部中断挂起寄存器 */
switch (j) /* 判断外部中断4/5/6/7具体为哪个 */
{
case 1: /* EINT4触发 */
semGive(semInt4); /* 释放二值信号量,同步EINT服务程序 */
break:
⋯ /* EINT5,EINT6,EINT7触发程序 */
}
⋯ /* 清外部中断挂起位,使能外部中断 */
}
在中断服务程序设计中对处理代码有诸多限制,如处理代码应尽量短,不能调用可能引起阻塞的任务等。针对这种限制,可以采用中断服务程序分步处理法,具体是将原来的中断服务程序分为新的中断服务程序和中断服务任务两部分:新的中断服务程序仅仅执行最基本的中断处理,例如禁止中断、判断中断类型等;而绝大多数的中断处理任务,特别是有可能造成阻塞的任务,都放在中断服务任务中执行。新的中断服务程序和中断服务任务采用二进制信号量进行同步(如上述程序设计所示),但中断服务任务在创建时必须满足在所有创建的任务中具有较高的优先级,以使中断发生时外部事件得到优先处理,否则中断响应就失去其意义。
5 结束语
随着计算机技术和控制技术快速发展,VxWorks实时嵌入式操作系统被广泛应用于各种设备和实时控制系统中,而硬件中断处理在实时操作系统设计中起着十分重要的作用。针对嵌入式系统的硬件设计和软件规划,本文阐述了VxWorks的中断处理机制,分析了VxWorks的中断处理过程,提出了基于S3C44B0X处理器的中断处理实现方法.提高了系统的实时性并满足埘外部突发事件的及时处理.对从事实时系统的开发具有一定的参考和借鉴作用。
引言
硬件中断处理在实时操作系统设计中起着十分重要的作用,它是外部事件通知操作系统的最常用手段。中断的正常运行是操作系统稳定工作的先决条件。VxWorks作为一款优秀的实时嵌入式系统,通常采用中断的方式来满足系统实时性要求。因此,熟悉其中断的处理过程对于VxWorks操作系统的开发至关重要。本文通过基于S3C44B0X处理器VxWorks嵌入式操作系统的BSP移植,详细分析了VxWorks操作系统基于ARM处理器的中断处理方法。
1 ARM异常中断处理
ARM体系结构支持复位(Reset)等7种异常中断类型,各异常中断的向量地址及中断的处理优先级如表1所示。当异常中断发牛时,硬件逻辑根据异常类型给程序计数器(PC)强制赋值,使程序从表1给出的相应的矢量地址开始执行异常处理程序。在异常中断向量表中指定了各异常中断与其处理程序的对应关系,一般来说,矢量地址处将包含一条指向相应程序的转移指令,从而可跳转到相应的中断服务程序。异常中断向量表存放在存储器的0地址处,大小为32字节,每个异常中断占4字节大小,保留了4字节空间。
表1 各异常中断的向量地址以及中断处理优先
b.gif
S3C44BOX的中断控制器町以接收来自26个中断源的30个中断请求,其中有4个外部中断(EINT/4/5/6/7)是逻辑或的关系,它们共用一条中断请求线。当片内外围中断和片外中断模式设定为IRQ时,如有多重中断发生,中断控制器经过优先级判断选择其中一个中断,通过IRQ向ARM7TDMI内核发出IRQ中断请求。另外.在中断服务程序中需特别注意:必须加入对L_ISPC或F_ISPC寄存器相应的中断位写1操作,来清除只读中断挂起寄存器INTPEND的挂起位,以使中断正常运行。
2 VxWorks中断处理机制
VxWorks中断处理主要包括:保存被中断任务的上下文,调用中断服务程序(ISR),中断返回恢复被中断任务的上下文,其具体流程如图1所示。对被中断任务现场信息的保存,在S3C44B0处理器体系结构中,VxWorks采用集中式的保存方式,即在内存中专门设置一个中断保存堆栈.所有中断的现场信息都统一保存在此堆栈中。堆栈的定位和大小初始化依据指定参数在系统启动时进行配置。对于堆栈的大小,必须足够大,以满足最坏情况下中断嵌套的深度。
1.gif
图1 VxWorks中断处理执行流程
2.1 异常向量表的生成及实现
当异常发生时,程序计数器(PC)会被强制为相应异常处理程序的入口地址.然后进行中断源的识别,根据中断号在中断向量表中找到相应中断服务程序(ISR)的入口地址。VxWorks将异常向量表定位在RAM中,基地址为VEC_BASE_ADRS,在configA11.h中定义.一般为RAM存储器的起始地址。在系统启动初始化时,由intVecBaseSet()函数设置向量表的基地址。向量表地址设定后,需要初始化指定异常的缺省处理函数。VxWorks在映像的代码段建立了一张中断缺省函数表,函数excVecInit()根据这张表来设置向量表的各异常中断向量值。需初始化的向量表范围由LOW_VEC和HIGH_VEC确定,在excArchLib.h中定义。由于不同的处理器异常处理机制不同,有时需根据具体的异常处理来建立自己的异常向量表,具体建立实现过程在下面讨论。
2.2 中断服务程序的连接
VxWorks为中断提供接口函数intConnect(),它将中断服务程序(ISR)和中断向量相关联。在操作系统内核启动后,VxWorks建立与中断号相对应的中断向量表,中断向量表中的每个中断向量包含中断服务程序(ISR)的入口地址。当中断事件发生时.VxWorks内核将调用与其中断向量对应的中断服务程序。intConnect()原型如下:
STATUS intConnect
(
VOIDFUNCPTR * vector, /* 要关联的中断向量 */
VOIDFUNCPTR routine, /*中断发生时调用的函数 */
int parameter /*传递给lsR函数的参数*/
)
但实际上,中断出现时并不是直接调用指定的中断处理函数。而是,intConnect()函数将创建一小段代码,这段代码用以保存必要寄存器、设置堆栈入口、之后调用中断处理函数。相反,当从该函数返回时,这段代码先恢复寄存器和堆栈,然后退出中断。
3 VxWorks基于S3C44B0X的中断处理
3.1 基于S3C44B0X处理器的VxWorks异常向量表的生成S3C44BOX处理器不支持内存重定向操作,也就是每个片选的地址范围是定死的,不能根据需要自己指定。启动flash存储器一直位于0地址,异常人口不能在运行时写入,故必须硬编码将异常入口填写在启动flash的0地址处。romInit.s是系统上电时的初始人口程序.从flash的0地址开始运行。故在其开始出定义异常入口程序实现如下:
_ARM_FUNCTION(romInit)
_romInit:
B cold /* 上电复位后执行的第1条指令,也可看作是复位向量 */
⋯ /* 未定义指令、软件中断等异常入口 */
B .
B _romIRQ /* IRQ中断异常入口 */
B .
在地址Ox00000014处S3C44B0X处理器未使用,保留。另外VxWorks不支持快速中断.地址Ox0000001c保留。
由于VxWorks建立的异常向量表定位在RAM中.那么当中断发生时如何把两者连接起来.从而由VxWorks实现中断管理呢?本BsP根据VxWorks缺省异常向量表,建立自定义的向量表,实现从ROM到RAM异常的连接,总体程序如下:
/* _romIRQ 及其它函数定义 */
_romIRQ;
sub sp,sp,#4
stmfd sq1 , (r0)
ldr r0,L$_promIRQ
ldr r0,[r0] /* 装载IRQ异常地址到R0 */
str r0,[sp,#4]
ldmfd sp!,{r0,pc} /* 跳转到异常服务程序 */
/* _romIRQ指向RAM中的位置 */
L$_promIRQ:
.long S3C_EXC_BASE + 20 /* #define S3C_EXC_BASE 0x0c000100 */
/* 在真正RAM空间建立异常向量表,和VxWorks建立的向量表相同,只是位置不同 */
void s3cExcVecSet(void)
{
UINT32 i:
。..
i=(UINT32)intEnt;
*((UINT32 *)(S3C_EXC_BASE + Ox14))=i;
}
对以上代码分析:当中断发生时.程序跳转到_romIRQ处,然后执行出栈操作,把L$_promIRQ地址(0x0c000114=(s3c_EXC_BASE + 20))的内容赋给程序计数器(PC);而上述vxwofks在RAM空间建立异常向量表时,把异常中断服务程序(intEnt)的地址放在地址0x0c00Oll4(s3C_EXC_BASE + 0x14)中,即PC=(UINT32) intEnt实现从ROM到RAM中断的连接。
3.2 中断驱动中的回调函数
VxWorks中intArchLib库所包含的中断系统函数与具体的处理器体系结构相关.其默认体系结构中不包含ARM处理器,所以此库中的函数都要依赖于具体BsP提供的例程来完成其功能。VxWorks采用Hook的方法来实现,针对本处理器的BSP,在sngkcIntrCtl.c文件中,定义了四个钩子函数:
sysIntLvlVecChkRtn = sngks32cIntLvlVecChk;/* 中断源检测,返回中断号 */
sysIntLvlEnableRtn = sngks32cIntLvlEnable; /* 使能相应中断 */,
svslntLvlDisableRtn = sngks32cIntLvlDisable; /* 禁止相应中断 */,
svsIntLvlvecAckRtn = sngks32cIntLvLAck; /* 清除中断标志位 */,
用来完成中断驱动。当外部中断发生时,程序进入intEnt函数,运行sysIntLvlVecChkRm钩子函数读中断服务挂起寄存器(I_ISPR)来检测中断源,并返回中断号,通过在intConnect函数中建立的中断向量与中断服务函数的连接,从而调用相应的中断服务程序。在中断返回时.执行sysIntLvlvecAckRtn钩子函数通过写IRQ中断挂起清零寄存器(I_ISPC),来清除刚处理完的中断挂起位。完整的VxWorks基于S3C44BOX处理器的中断响应流图如图2所示:
2.gif
图2 VxWorks基于S3C44B0X处理器的中断响应流图
4 实例分析
外部中断EINT4/5/6/7共用一个中断请求线,当其中一个中断发生时,中断挂起寄存器(INTPND)的EINT4/5/6/7位置1.具体是其中哪个发生中断可通过读外部中断挂起寄存器(EXTINTPND)来判断。
中断服务程序连接
intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC(21),
(VOIDFUNCPTR)isr4567,0)
外部中断使能
intEnable(21); /* 触发钩子函数 */
svsIntLvlEnableRtn; /* 清中断屏蔽寄存器(INTMSK)的EINT4/5/6/7位使能中断? */
中断服务程序:
void isr4567(void)
{
int j;
intDisable(21); /* 关中断 */
S3C44B0X_INT_REG_READ (S3C44BOX_EXTINTPND,j);/*读外部中断挂起寄存器 */
switch (j) /* 判断外部中断4/5/6/7具体为哪个 */
{
case 1: /* EINT4触发 */
semGive(semInt4); /* 释放二值信号量,同步EINT服务程序 */
break:
⋯ /* EINT5,EINT6,EINT7触发程序 */
}
⋯ /* 清外部中断挂起位,使能外部中断 */
}
在中断服务程序设计中对处理代码有诸多限制,如处理代码应尽量短,不能调用可能引起阻塞的任务等。针对这种限制,可以采用中断服务程序分步处理法,具体是将原来的中断服务程序分为新的中断服务程序和中断服务任务两部分:新的中断服务程序仅仅执行最基本的中断处理,例如禁止中断、判断中断类型等;而绝大多数的中断处理任务,特别是有可能造成阻塞的任务,都放在中断服务任务中执行。新的中断服务程序和中断服务任务采用二进制信号量进行同步(如上述程序设计所示),但中断服务任务在创建时必须满足在所有创建的任务中具有较高的优先级,以使中断发生时外部事件得到优先处理,否则中断响应就失去其意义。
5 结束语
随着计算机技术和控制技术快速发展,VxWorks实时嵌入式操作系统被广泛应用于各种设备和实时控制系统中,而硬件中断处理在实时操作系统设计中起着十分重要的作用。针对嵌入式系统的硬件设计和软件规划,本文阐述了VxWorks的中断处理机制,分析了VxWorks的中断处理过程,提出了基于S3C44B0X处理器的中断处理实现方法.提高了系统的实时性并满足埘外部突发事件的及时处理.对从事实时系统的开发具有一定的参考和借鉴作用。
举报