3. 编写BSP初始化代码

任务说明

本案例面向VxWorks BSP开发,目标是在BSP的sysLib.c中实现板级初始化函数sysHwInit,完成CPU工作模式配置、内存控制器基础设置以及中断控制器的使能。该函数是VxWorks启动流程中硬件初始化的核心入口,在usrInit之后、usrKernelInit之前由内核调用。

环境与依赖

  • VxWorks 7 或 VxWorks 6.9+,目标板为ARM Cortex-A9(以Zynq-7000为例)
  • 需要目标板的硬件手册(寄存器地址与位域定义)
  • BSP源码包中已有的头文件:config.h、bspname.h、sysLib.h

关键完整代码

以下代码位于BSP的sysLib.c文件中,实现sysHwInit及其调用的三个底层配置函数。寄存器地址基于Zynq-7000 TRM定义。

/* sysLib.c - 板级初始化实现(节选) */

#include "vxWorks.h"
#include "config.h"
#include "sysLib.h"
#include "intLib.h"

/* Zynq-7000 寄存器地址定义 */
#define SLCR_BASE_ADDR       0xF8000000
#define SLCR_UNLOCK_OFFSET   0x08
#define SLCR_UNLOCK_VAL      0xDF0D
#define SLCR_LOCK_OFFSET     0x04
#define ARM_PLL_CTRL_OFFSET  0x100
#define DDRC_CTRL_OFFSET     0xF8006000
#define DDRC_CTRL_REG        0x0
#define DDRC_CTRL_DDR2_EN    (1 << 0)
#define GIC_DIST_BASE        0xF8F01000
#define GIC_CPU_BASE         0xF8F00100
#define GICD_CTLR_OFFSET     0x000
#define GICC_CTLR_OFFSET     0x000
#define GICD_CTLR_ENABLE     0x1
#define GICC_CTLR_ENABLE     0x1

/* 本地函数声明 */
static void cpuInit(void);
static void memInit(void);
static void intCtrlInit(void);

/******************************************************************************
* sysHwInit - 板级硬件初始化入口
* 由VxWorks内核在启动早期调用,完成CPU、内存、中断控制器基本配置。
******************************************************************************/
void sysHwInit(void)
{
    /* 解锁SLCR(System Level Control Registers) */
    *(volatile UINT32 *)(SLCR_BASE_ADDR + SLCR_UNLOCK_OFFSET) = SLCR_UNLOCK_VAL;

    cpuInit();
    memInit();
    intCtrlInit();

    /* 重新锁定SLCR */
    *(volatile UINT32 *)(SLCR_BASE_ADDR + SLCR_LOCK_OFFSET) = 0x1;

    /* 中断向量表基地址设置(ARM模式) */
    intVecBaseSet((void *)0x80000000);
}

/******************************************************************************
* cpuInit - CPU基本配置
* 设置ARM Cortex-A9处理器为SVC模式,关闭MMU(由VxWorks后续管理)。
******************************************************************************/
static void cpuInit(void)
{
    UINT32 cpsr;

    /* 读取当前程序状态寄存器 */
    cpsr = vxArmRegGet(ARM_REG_CPSR);

    /* 清除模式位并设置为SVC模式(0b10011) */
    cpsr &= ~0x1F;
    cpsr |= 0x13;

    /* 关闭IRQ和FIQ(I位和F位置1) */
    cpsr |= 0xC0;

    vxArmRegSet(ARM_REG_CPSR, cpsr);

    /* 关闭MMU和D-Cache(若尚未关闭) */
    UINT32 sctlr;
    sctlr = vxArmRegGet(ARM_REG_SCTLR);
    sctlr &= ~(0x1 | 0x4);   /* 清除M位(MMU)和C位(D-Cache) */
    vxArmRegSet(ARM_REG_SCTLR, sctlr);
}

/******************************************************************************
* memInit - 内存控制器初始化
* 配置DDR控制器为DDR2模式(示例),使能DDRC。
******************************************************************************/
static void memInit(void)
{
    volatile UINT32 *ddrcCtrl = (volatile UINT32 *)(DDRC_CTRL_OFFSET + DDRC_CTRL_REG);

    /* 设置DDR控制器为DDR2模式并使能 */
    *ddrcCtrl = DDRC_CTRL_DDR2_EN;

    /* 等待DDR控制器就绪(轮询状态寄存器bit0) */
    volatile UINT32 *ddrcStat = (volatile UINT32 *)(DDRC_CTRL_OFFSET + 0x4);
    while ((*ddrcStat & 0x1) == 0)
        ;
}

/******************************************************************************
* intCtrlInit - 中断控制器初始化
* 使能GIC(Generic Interrupt Controller)分发器和CPU接口。
******************************************************************************/
static void intCtrlInit(void)
{
    volatile UINT32 *gicdCtlr = (volatile UINT32 *)(GIC_DIST_BASE + GICD_CTLR_OFFSET);
    volatile UINT32 *giccCtlr = (volatile UINT32 *)(GIC_CPU_BASE + GICC_CTLR_OFFSET);

    /* 使能GIC分发器 */
    *gicdCtlr = GICD_CTLR_ENABLE;

    /* 使能GIC CPU接口 */
    *giccCtlr = GICC_CTLR_ENABLE;
}

编译与集成

  1. 将上述代码合并到BSP的sysLib.c中,替换原有的空sysHwInit实现。
  2. 确认config.h中定义了正确的内存大小和外部总线频率。
  3. 在BSP的Makefile中无需额外修改,sysLib.c默认参与编译。

验证方法

完成集成后,按以下步骤验证初始化是否成功:

  1. 编译BSP并生成VxWorks镜像:make(在BSP目录下)。
  2. 通过JTAG或网络加载镜像到目标板,启动VxWorks。
  3. 在shell中执行i命令查看系统信息,确认系统正常启动且无异常复位。
  4. 执行intShow命令,观察中断控制器是否已使能(应显示GIC状态为enabled)。
  5. 执行memShow命令,确认内存大小识别正确且可正常读写。

通过条件:系统能稳定启动至shell提示符,intShow显示中断控制器已使能,memShow显示的内存容量与硬件实际配置一致,且无总线错误或异常日志输出。

常见问题

  • 启动后立即复位:检查SLCR解锁值是否正确(Zynq为0xDF0D),以及DDR控制器配置是否与板载内存颗粒匹配。
  • 中断不响应:确认GIC基地址与硬件手册一致,且intVecBaseSet设置的向量表地址在内存映射范围内。
  • 编译报未定义寄存器:确认vxArmRegGet/Set函数在当前BSP的sysArmLib.c中已实现,或改用内联汇编访问CP15寄存器。