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;
}
编译与集成
- 将上述代码合并到BSP的
sysLib.c中,替换原有的空sysHwInit实现。 - 确认
config.h中定义了正确的内存大小和外部总线频率。 - 在BSP的
Makefile中无需额外修改,sysLib.c默认参与编译。
验证方法
完成集成后,按以下步骤验证初始化是否成功:
- 编译BSP并生成VxWorks镜像:
make(在BSP目录下)。 - 通过JTAG或网络加载镜像到目标板,启动VxWorks。
- 在shell中执行
i命令查看系统信息,确认系统正常启动且无异常复位。 - 执行
intShow命令,观察中断控制器是否已使能(应显示GIC状态为enabled)。 - 执行
memShow命令,确认内存大小识别正确且可正常读写。
通过条件:系统能稳定启动至shell提示符,intShow显示中断控制器已使能,memShow显示的内存容量与硬件实际配置一致,且无总线错误或异常日志输出。
常见问题
- 启动后立即复位:检查SLCR解锁值是否正确(Zynq为0xDF0D),以及DDR控制器配置是否与板载内存颗粒匹配。
- 中断不响应:确认GIC基地址与硬件手册一致,且
intVecBaseSet设置的向量表地址在内存映射范围内。 - 编译报未定义寄存器:确认
vxArmRegGet/Set函数在当前BSP的sysArmLib.c中已实现,或改用内联汇编访问CP15寄存器。