4. 中断向量表配置:中断向量号分配、intConnect()函数详解、intVecSet()与intVecGet()使用
在VxWorks实时系统中,中断向量表是连接硬件中断源与软件ISR的桥梁。正确配置中断向量表,是确保中断响应实时性、可靠性的第一步。本节将深入剖析中断向量号的分配机制,并详细讲解三个核心API:intConnect()、intVecSet()与intVecGet()的使用方法与性能考量。
4.1 中断向量号分配机制
VxWorks将中断向量号分为两个逻辑区域:CPU内部异常向量和外部设备中断向量。向量号的分配直接决定了中断优先级和ISR的查找效率。
关键概念: 向量号(Vector Number)是一个整数标识符,用于在中断向量表中索引对应的ISR入口地址。在PowerPC架构中,向量号通常与硬件中断控制器(如MPIC)的IRQ号一一映射;在ARM架构中,则与GIC的中断ID对应。
| 架构 | 向量号范围 | 典型分配 | 说明 |
|---|---|---|---|
| PowerPC (MPC74xx) | 0 – 255 | 0-15: 异常; 16-255: 外部中断 | 向量号 = 基地址 + IRQ号 |
| ARM (Cortex-A9) | 0 – 1023 | 0-31: 异常; 32-1023: SPI/PPI | GIC中断ID直接作为向量号 |
| x86 (IA-32) | 0 – 255 | 0-31: 异常; 32-255: IRQ | 通过IDT表映射,向量号=中断门索引 |
性能提示: 向量号越小,在中断向量表中的查找路径越短。对于高频中断(如定时器、网络DMA),建议分配较小的向量号,以减少中断延迟抖动。
4.2 intConnect() 函数详解
intConnect() 是VxWorks中最常用的中断连接函数。它将一个中断向量号与一个ISR函数绑定,并允许传递一个参数给ISR。其原型如下:
STATUS intConnect
(
VOIDFUNCPTR *vector, /* 中断向量号指针 */
VOIDFUNCPTR routine, /* ISR函数指针 */
int parameter /* 传递给ISR的参数 */
)
4.2.1 参数说明与使用要点
| 参数 | 类型 | 说明 | 注意事项 |
|---|---|---|---|
vector |
VOIDFUNCPTR * |
指向中断向量号的指针,通常使用 INUM_TO_IVEC(intNum) 宏转换 |
必须确保向量号在有效范围内,且未被其他ISR占用 |
routine |
VOIDFUNCPTR |
ISR函数入口地址 | ISR必须符合VxWorks ISR规范:无返回值、无阻塞、无浮点运算 |
parameter |
int |
传递给ISR的整型参数,通常用于区分同类型设备的不同实例 | 参数在中断上下文中传递,不能传递指针到栈变量 |
常见错误: 直接传递
intNum 而非 INUM_TO_IVEC(intNum) 会导致向量号被错误解释,造成系统崩溃。务必使用宏进行转换。
4.2.2 典型使用示例
/* 定义ISR */
void myIsr(int param)
{
/* 读取中断状态寄存器 */
unsigned int status = *(volatile unsigned int *)(DEV_BASE + INT_STATUS);
/* 处理中断 */
if (status & TX_DONE) {
/* 发送完成处理 */
}
/* 写中断清除寄存器 */
*(volatile unsigned int *)(DEV_BASE + INT_CLEAR) = status;
}
/* 在任务初始化中连接中断 */
STATUS connectStatus;
connectStatus = intConnect(INUM_TO_IVEC(IRQ_ETHERNET),
(VOIDFUNCPTR)myIsr,
DEVICE_ID_0);
if (connectStatus != OK) {
logMsg("intConnect failed for IRQ %d\n", IRQ_ETHERNET, 0,0,0,0,0);
return ERROR;
}
4.3 intVecSet() 与 intVecGet() 使用
intVecSet() 和 intVecGet() 提供了对中断向量表的底层直接访问能力。与 intConnect() 不同,这两个函数不进行任何参数封装或上下文保存,直接读写向量表中的ISR地址。
4.3.1 函数原型与差异对比
| 函数 | 原型 | 功能 | 适用场景 |
|---|---|---|---|
intVecSet() |
STATUS intVecSet(FUNCPTR *vector, FUNCPTR routine) |
直接设置向量号对应的ISR入口地址 | 需要绕过 intConnect() 的封装,实现极低延迟的ISR安装 |
intVecGet() |
FUNCPTR intVecGet(FUNCPTR *vector) |
读取向量号当前绑定的ISR入口地址 | 调试、动态检查中断绑定状态、保存/恢复中断上下文 |
性能差异:
intVecSet() 仅执行一次内存写操作(写入向量表),而 intConnect() 内部会调用 intVecSet() 并额外执行中断栈初始化、参数保存等操作。在启动阶段批量安装ISR时,直接使用 intVecSet() 可减少约 30% 的安装时间。
4.3.2 使用示例:保存与恢复中断向量
/* 保存原中断向量 */
FUNCPTR oldIsr;
oldIsr = intVecGet(INUM_TO_IVEC(IRQ_TIMER));
/* 安装临时ISR */
intVecSet(INUM_TO_IVEC(IRQ_TIMER), (FUNCPTR)temporaryIsr);
/* 执行需要临时屏蔽的操作 */
temporaryOperation();
/* 恢复原中断向量 */
intVecSet(INUM_TO_IVEC(IRQ_TIMER), oldIsr);
4.3.3 底层实现原理
intVecSet() 和 intVecGet() 直接操作中断向量表基地址。在VxWorks中,中断向量表通常位于内存的固定区域(如PowerPC的0x0000-0x0FFF)。这两个函数通过计算 vector 指针与基地址的偏移,直接读写对应的表项。
4.4 中断向量配置最佳实践
- 优先使用 intConnect():对于大多数应用场景,
intConnect()提供了参数传递和上下文保存,代码可读性和可维护性更好。 - 启动阶段批量安装使用 intVecSet():在系统初始化阶段,当需要快速安装大量ISR时,直接使用
intVecSet()可减少函数调用开销。 - 动态切换ISR时保存原向量:使用
intVecGet()保存原ISR地址,在临时操作完成后恢复,避免中断丢失。 - 向量号分配避免冲突:在BSP配置文件中明确记录已使用的向量号,使用
sysIntNumAlloc()等函数进行动态分配。 - 使用 INUM_TO_IVEC 宏:始终使用
INUM_TO_IVEC()和IVEC_TO_INUM()宏进行向量号与向量指针的转换,确保跨平台兼容性。
性能优化要点: 对于延迟敏感的中断(如音频帧中断、控制环路中断),建议在系统启动阶段使用
intVecSet() 直接安装ISR,并配合 intLock()/intUnlock() 进行原子操作,避免 intConnect() 内部的额外锁开销。