4. BSP初始化流程:从sysHwInit到usrRoot的中断与定时器初始化链路

VxWorks 的 BSP 初始化流程是一条从底层硬件抽象到上层系统服务的清晰链路。中断控制器与时钟定时器的初始化贯穿其中,是系统能够响应外部事件、实现任务调度与时间管理的基石。本章节将详细拆解从 sysHwInit 到 usrRoot 的完整初始化路径,聚焦中断与定时器相关的关键节点。

核心链路概览: sysHwInit() → sysIntInit() → sysTimerInit() → usrKernelInit() → usrRoot() → sysClkConnect() / sysAuxClkConnect() → sysClkEnable() / sysAuxClkEnable()
BSP 初始化主链路:中断与定时器 BSP 初始化主链路:中断与定时器 sysHwInit() sysIntInit() sysTimerInit() usrKernelInit() usrRoot() sysClkConnect() sysClkEnable() sysAuxClkConnect() sysAuxClkEnable() 硬件抽象层初始化 中断控制器初始化 定时器硬件初始化 内核基础服务初始化

4.1 第一阶段:sysHwInit — 硬件抽象层入口

sysHwInit() 是 BSP 初始化流程的起点,由 usrInit() 在系统启动早期调用。此阶段运行在单任务、无缓存、无 MMU 的原始环境中,主要职责是完成 CPU 核心之外的基础外设初始化。

初始化项 典型实现 与中断/定时器的关系
CPU 寄存器与模式 设置异常向量表基址、CPU 工作模式 为中断向量表重定位做准备
内存控制器 配置 SDRAM/DDR 时序与地址映射 确保中断向量表与栈空间可访问
中断控制器基础复位 屏蔽所有中断源、设置默认优先级 防止未初始化的外设产生误中断
定时器外设时钟使能 使能定时器模块的 IP 时钟与总线时钟 为后续定时器寄存器访问提供时钟
实战要点: 在 sysHwInit() 中,中断控制器应处于“全部屏蔽”状态。任何未连接 ISR 的中断源在此时触发,都会导致系统崩溃。建议在函数入口处执行一次全局中断屏蔽操作。

4.2 第二阶段:sysIntInit — 中断控制器初始化

sysIntInit() 是中断子系统的核心初始化函数,通常在 sysHwInit() 内部被调用。其目标是将中断控制器配置为已知的、可工作的初始状态。

4.2.1 标准初始化步骤

  1. 复位中断控制器: 将控制器恢复到硬件默认状态,清除所有挂起的中断。
  2. 配置中断分发模式: 对于 GIC(通用中断控制器),需设置 CPU 接口、中断分组(Group 0/1)以及安全状态。
  3. 设置中断优先级与掩码: 为所有中断源分配默认优先级,并确保所有中断处于屏蔽状态。
  4. 配置中断向量表基址: 将 CPU 的异常向量表指向 VxWorks 的中断向量表(通常位于 RAM 中)。
  5. 使能 CPU 中断接口: 最后使能 CPU 与中断控制器之间的接口信号。
中断控制器初始化状态机 中断控制器初始化状态机 复位态 配置态 就绪态 运行态 硬件复位 配置参数 使能接口 响应中断

4.2.2 关键数据结构

/* VxWorks 中断描述符表结构示例 */
typedef struct {
    VOIDFUNCPTR   isr;          /* 中断服务函数指针 */
    int           parameter;    /* 传递给 ISR 的参数 */
    UINT8         priority;     /* 中断优先级 */
    UINT8         vector;       /* 中断向量号 */
} INT_DESC;

/* 全局中断描述符表,由 sysIntInit 初始化 */
LOCAL INT_DESC intDescTable[NUM_INT_VECTORS];

4.3 第三阶段:sysTimerInit — 定时器硬件初始化

sysTimerInit() 负责初始化板级上的定时器硬件资源,包括系统时钟定时器(System Clock Timer)和辅助时钟定时器(Auxiliary Clock Timer)。此函数通常在 sysHwInit() 中被调用。

4.3.1 定时器初始化清单

定时器类型 硬件资源 初始化动作 后续用途
系统时钟定时器 SoC 内部通用定时器 / PIT 设置初始计数值、分频系数、工作模式(周期/单次) 生成系统 Tick 中断,驱动任务调度
辅助时钟定时器 独立的定时器通道 / 看门狗定时器 配置时钟源、预分频器、比较值 提供高精度时间测量或辅助 Tick
时间戳定时器 CPU 内部 Cycle Counter / 全局定时器 使能计数器、设置初始值 提供 timestamp() 高精度时间戳
常见陷阱: 定时器的时钟源选择至关重要。如果使用了错误的时钟源(如选择了门控时钟或低频时钟),会导致系统 Tick 频率异常,进而引发任务调度超时或时间片轮转失效。务必查阅芯片参考手册,确认定时器模块的输入时钟频率。

4.4 第四阶段:usrKernelInit — 内核基础服务初始化

在 sysHwInit() 返回后,VxWorks 内核启动流程进入 usrKernelInit()。此阶段初始化内核对象(如任务控制块、信号量、消息队列)所需的内存池和数据结构。虽然不直接操作中断控制器寄存器,但会建立内核中断管理框架。

  • 中断栈初始化: 为中断服务例程分配独立的栈空间,防止中断嵌套导致栈溢出。
  • 中断锁机制建立: 初始化 intLock() / intUnlock() 所需的全局状态变量。
  • 异常处理挂钩注册: 注册默认的异常处理函数,用于捕获未连接 ISR 的中断。

4.5 第五阶段:usrRoot — 系统时钟与辅助时钟的最终连接与使能

usrRoot() 是 VxWorks 启动后的第一个根任务。在此任务中,中断与定时器初始化进入最终阶段:将定时器硬件中断连接到具体的 ISR,并启动定时器计数。

4.5.1 系统时钟连接与使能

/* usrRoot 中系统时钟初始化典型代码片段 */
STATUS sysClkConnect(
    FUNCPTR routine,    /* 系统时钟中断服务函数,通常为 tickAnnounce */
    int     arg         /* 传递给 ISR 的参数 */
)
{
    /* 1. 通过 intConnect() 将定时器中断向量连接到 routine */
    if (intConnect(INUM_TO_IVEC(SYS_CLK_INT_VEC), routine, arg) == ERROR)
        return ERROR;

    /* 2. 保存 ISR 信息到全局变量 */
    sysClkRoutine = routine;
    sysClkArg = arg;

    return OK;
}

STATUS sysClkEnable(void)
{
    /* 1. 设置定时器重装载值,计算方式:时钟频率 / 系统 Tick 频率 */
    UINT32 reloadVal = sysClkRateGet() / sysClkFreqGet();

    /* 2. 使能定时器中断 */
    sysIntEnablePIC(SYS_CLK_INT_VEC);

    /* 3. 启动定时器计数器 */
    TIMER_REG_WRITE(SYS_TIMER_LOAD_REG, reloadVal);
    TIMER_REG_WRITE(SYS_TIMER_CTRL_REG, TIMER_ENABLE | TIMER_PERIODIC);

    return OK;
}

4.5.2 辅助时钟连接与使能

辅助时钟的初始化流程与系统时钟类似,但通常用于不同的目的,如性能分析或高精度延时。

/* 辅助时钟初始化示例 */
STATUS sysAuxClkConnect(FUNCPTR routine, int arg)
{
    /* 连接到不同的中断向量 */
    return intConnect(INUM_TO_IVEC(SYS_AUX_CLK_INT_VEC), routine, arg);
}

STATUS sysAuxClkEnable(void)
{
    /* 配置为单次模式,用于精确延时 */
    TIMER_REG_WRITE(AUX_TIMER_CTRL_REG, TIMER_ENABLE | TIMER_ONE_SHOT);
    return OK;
}
中断与定时器初始化完整链路 中断与定时器初始化完整链路 中断控制器初始化 屏蔽所有中断源 配置优先级与分组 设置向量表基址 使能 CPU 接口 定时器硬件初始化 配置时钟源与分频 设置初始计数值 选择工作模式 定时器停止状态 usrRoot: 连接 ISR + 使能定时器 intConnect() → sysClkEnable() / sysAuxClkEnable() 至此,中断与定时器初始化链路完成,系统可响应 Tick 中断

4.6 初始化链路总结

阶段 函数 中断控制器状态 定时器状态 执行环境
1 sysHwInit 复位、全部屏蔽 时钟使能、寄存器未配置 单任务、无缓存
2 sysIntInit 配置完成、接口使能 未启动 单任务、无缓存
3 sysTimerInit 已就绪 参数配置完成、停止状态 单任务、无缓存
4 usrKernelInit 内核框架建立 未启动 内核初始化
5 usrRoot ISR 连接完成 启动计数、产生中断 多任务环境
链路关键原则:
  • 先屏蔽,后配置: 在中断控制器初始化完成前,确保所有中断源处于屏蔽状态。
  • 先配置,后使能: 定时器必须在所有参数(时钟源、分频、模式)配置完成后,最后才使能启动。
  • 连接在使能之前: sysClkConnect() 必须在 sysClkEnable() 之前调用,否则定时器中断触发时找不到 ISR。