1. 课程导入与BSP工程全景

在嵌入式系统开发中,VxWorks 以其高实时性、可裁剪性和稳定性,长期占据工业控制、通信设备、航空航天等关键领域。而 BSP(Board Support Package,板级支持包)正是 VxWorks 从“通用内核”落到“具体硬件”的桥梁。没有 BSP,VxWorks 内核只是一段无法在目标板上运行的代码;有了 BSP,内核才能完成上电初始化、驱动外设、挂载文件系统,最终把控制权交给应用。本课程围绕 BSP 移植与板级适配展开,本章先建立全局视角:VxWorks 如何启动、BSP 在系统中处于什么位置、移植到底要改什么、工程阶段如何划分。

一、VxWorks 启动流程:从复位向量到应用入口

理解 BSP,首先要理解 VxWorks 的启动链条。以常见的 ARM 架构为例,上电后 CPU 从复位向量取指,执行 BSP 中的 romInit.s。这段汇编代码运行在物理地址、MMU 关闭、Cache 未使能的环境中,主要完成:屏蔽中断、初始化时钟与内存控制器、设置栈指针、清零 BSS 段,然后跳转到 romStart()。

romStart() 通常由 C 语言实现,负责把 ROM 中的代码段和数据段搬运到 RAM 中的链接地址,并跳转到 sysInit()。进入 sysInit() 后,系统开始建立 C 运行环境,初始化异常向量表、串口、定时器等最基础资源,随后调用 usrInit()。在 usrInit() 中,VxWorks 完成内核初始化:创建根任务 tRootTask、初始化 Wind 内核、挂载系统时钟,最后进入 usrRoot()。此时用户可以在 usrRoot() 中挂载文件系统、初始化网络、创建设备节点,并启动第一个应用任务。

这条链路中,romInit.s、romStart()、sysInit()、usrInit() 的前半段几乎全部由 BSP 提供或深度参与。换句话说,BSP 决定了“内核能不能跑起来”,而应用决定了“跑起来之后做什么”。

VxWorks 启动流程与 BSP 参与边界 BSP 主导阶段(硬件相关) romInit.s → romStart() → sysInit() → usrInit() 前半段 内核与系统阶段(BSP 提供配置) usrInit() 后半段 → usrRoot() → 系统时钟 / 文件系统 / 网络 应用阶段(与 BSP 解耦) 应用任务创建 → 业务逻辑运行 复位向量 CPU 取指 romInit.s 时钟 / 内存 / 栈 romStart() 代码搬运到 RAM sysInit() 异常向量 / 串口 usrInit() 内核初始化 关键判断:若串口无输出,优先检查 romInit.s 中的时钟与内存控制器配置;若内核启动后挂起,检查 sysInit() 中的中断控制器与定时器初始化。 BSP 边界:romInit.s 到 usrInit() 前半段由 BSP 直接提供;usrRoot() 之后的系统服务由内核组件与 BSP 配置共同决定。

二、BSP 在系统中的位置

从软件层次看,VxWorks 系统自下而上可分为:硬件层、BSP 层、内核层、系统服务层和应用层。BSP 层夹在硬件与内核之间,向上提供统一的 sysLib、intLib、timerLib、cacheLib 等接口,向下直接操作寄存器、中断控制器、定时器、串口、以太网 PHY 等硬件资源。

BSP 的组成通常包括:启动汇编 romInit.s、C 语言初始化 sysLib.c、中断处理 intLib.c、定时器 timerLib.c、串口驱动 ttyDrv 相关配置、网络驱动 endLib 相关配置、配置文件 config.h 与 Makefile,以及内存布局描述 sysPhysMemDesc[]。这些文件共同回答三个问题:硬件怎么初始化、内核怎么访问硬件、系统资源怎么分配。

三、移植与板级适配的核心任务

BSP 移植不是“从零写代码”,而是“以参考 BSP 为起点,针对目标板做差异化适配”。核心任务可以归纳为四条主线。

  • 启动适配:修改 romInit.s 中的时钟、内存控制器、栈指针、复位类型判断,确保 CPU 能正确进入 C 环境。
  • 内存映射:在 sysPhysMemDesc[] 中描述物理地址到虚拟地址的映射关系,配置 MMU 页表,区分可缓存与不可缓存区域。
  • 驱动适配:根据目标板外设型号,调整串口、网口、Flash、I2C、SPI 等驱动中的基地址、中断号、时钟频率和引脚复用。
  • 配置裁剪:在 config.h 中使能或关闭组件,调整 Makefile 中的编译选项、链接地址和镜像格式。

以串口为例,参考 BSP 中 sysSerialHwInit() 通常使用 16550 兼容 UART,基地址为 0x10000000,中断号为 5,输入时钟 24MHz。若目标板改用 16C550 且基地址变为 0x20000000,则需要同步修改基地址、中断号,并重新计算波特率分频值。若忽略时钟差异,串口会输出乱码,这是移植初期最常见的现象之一。

四、典型工程阶段划分

一个完整的 BSP 移植项目通常经历五个阶段:准备与评估、最小系统启动、基础驱动打通、系统服务集成、稳定性验证。准备阶段需要收集目标板原理图、芯片手册、参考 BSP 和工具链;最小系统阶段以“串口能打印”为里程碑;基础驱动阶段打通网口、Flash 和中断;系统服务阶段挂载文件系统、配置网络协议栈;稳定性阶段进行长时间运行、异常注入和边界测试。

建议在最小系统阶段就建立“串口输出 + 点灯”双通道验证。串口用于打印启动日志,GPIO 用于在无串口时判断代码是否执行到某一点。两者互为备份,能显著缩短定位时间。

五、工程视角下的常见误区

初学者容易把 BSP 移植等同于“改几个地址”。实际上,BSP 的质量取决于对硬件时序、中断优先级、Cache 一致性和内存属性的理解。例如,DMA 缓冲区必须映射为不可缓存,否则会出现数据看似写入却未被外设读取的问题;中断嵌套需要正确配置优先级和屏蔽字,否则高优先级中断可能被低优先级中断阻塞。这些细节不会在“能启动”阶段暴露,却会在压力测试中集中出现。