2. 目标板硬件资料研读

BSP 移植的第一步不是写代码,而是把目标板的硬件“读明白”。VxWorks BSP 中大量代码本质上是对硬件事实的翻译:内存控制器怎么配、串口寄存器基址在哪、中断从哪个控制器进来、时钟源是多少、某个引脚当前被复用成什么功能。这些事实全部藏在原理图、芯片数据手册、内存映射表、时钟树图、中断控制器手册、外设清单和引脚复用表这七类资料里。本节讨论的不是“去读手册”这种空话,而是每一类资料里究竟要提取哪些字段、提取到什么粒度、以及这些字段最终会落到 BSP 的哪个文件里。

一、先建立“资料—BSP 文件”的对应关系

研读资料前先明确目标:每一份资料都对应 BSP 中某个具体文件或某个宏定义。原理图主要服务于 sysSerial.c、sysLan.c 等设备初始化和板级连线确认;数据手册服务于寄存器级驱动;内存映射表直接决定 config.h 里的 LOCAL_MEM_LOCAL_ADRS、RAM_LOW_ADRS、ROM_BASE_ADRS 等地址宏;时钟树决定 sysClkRateSet() 的分频参数和串口波特率除数;中断控制器手册决定 intLib.c 与 hwif 层的连接方式;外设清单决定 config.h 中 INCLUDE_xxx 的取舍;引脚复用表决定 sysPinMux.c 或 sysHwInit() 中要写哪些 IOMUX 寄存器。带着这个对应关系去读,效率会完全不同。

硬件资料 → BSP 文件 提取映射图 原理图 连线 / 器件型号 / 上拉 芯片数据手册 寄存器偏移 / 位域 / 复位值 内存映射表 基址 / 大小 / 属性 时钟树 源 / 分频 / 门控 中断控制器手册 向量号 / 优先级 / 触发 外设清单 型号 / 接口 / 地址 引脚复用表 功能 / 方向 / 电气 提取动作 确认器件与网络名 抄录寄存器偏移与位域 整理地址区间表 反推各外设时钟频率 建立向量号映射表 列出使能外设与驱动 逐引脚标注复用功能 交叉核对: 原理图 ↔ 数据手册 映射表 ↔ 时钟树 中断表 ↔ 外设清单 复用表 ↔ 原理图 sysSerial.c / sysLan.c 设备初始化与连线确认 xxxDrv.c / xxx.h 寄存器宏与位域定义 config.h 地址宏 LOCAL_MEM / RAM_LOW / ROM_BASE sysClkRateSet / 波特率除数 定时器与串口分频参数 intLib.c / hwif 层 向量连接与优先级设置 config.h INCLUDE_xxx 组件裁剪与驱动挂载 sysPinMux.c / sysHwInit() IOMUX 寄存器写入

二、原理图:抓“连接关系”而非“画得好看”

原理图研读的核心是回答三个问题:器件是什么型号、它挂在哪个总线上、它的关键控制信号连到 CPU 的哪个引脚。以串口为例,需要确认 UART 控制器的基址由芯片内部固定还是由片选决定;如果是外部 16550 类器件,则要记录片选译码后的基址、中断输出连到中断控制器的哪一路、以及收发引脚是否经过电平转换。这些信息直接决定 sysSerial.c 中 UART_BASE 和中断号的填写。原理图上还要注意上拉/下拉电阻和复位信号极性,它们会影响驱动初始化时是否需要先释放复位、是否需要配置内部上拉。

三、数据手册:把寄存器表变成可用的宏

数据手册的价值在于寄存器偏移、位域定义和复位值。研读时不要只浏览,而应直接整理成 BSP 可用的形式。例如某 UART 的寄存器组基址为 0x4000_1000,则:

#define UART0_BASE      0x40001000
#define UART0_DR        (UART0_BASE + 0x00)   /* 数据寄存器 */
#define UART0_FR        (UART0_BASE + 0x18)   /* 状态寄存器 */
#define UART0_IBRD      (UART0_BASE + 0x24)   /* 整数波特率除数 */
#define UART0_FBRD      (UART0_BASE + 0x28)   /* 小数波特率除数 */
#define UART0_CR        (UART0_BASE + 0x30)   /* 控制寄存器 */
#define UART0_FR_TXFF   (1 << 5)              /* 发送 FIFO 满 */
#define UART0_CR_UARTEN (1 << 0)              /* UART 使能 */
#define UART0_CR_TXE    (1 << 8)              /* 发送使能 */
#define UART0_CR_RXE    (1 << 9)              /* 接收使能 */

注意位域要连同“有效极性”一起记录,例如 TXFF=1 表示 FIFO 满、不可写,这类语义如果记反,驱动会在发送时死等。数据手册中还要提取复位值,用于判断上电后哪些位需要显式清零。

四、内存映射表与时钟树:地址与频率两条主线

内存映射表要整理成“起始地址—结束地址—大小—属性—用途”的区间表。以某 ARM 目标板为例(示例参数,非实测):

起始地址结束地址大小属性用途
0x0000_00000x0007_FFFF512 KB只读/可缓存Boot ROM
0x2000_00000x2FFF_FFFF256 MB读写/可缓存DDR SDRAM
0x4000_00000x400F_FFFF1 MB读写/强序外设寄存器区
0xE000_00000xE00F_FFFF1 MB读写/强序中断控制器/定时器

据此可确定 LOCAL_MEM_LOCAL_ADRS=0x20000000、RAM_LOW_ADRS=0x20010000(为 VxWorks 镜像预留 64 KB 引导区)、ROM_BASE_ADRS=0x00000000。时钟树则要沿“晶振→PLL→分频器→门控”逐级反推,记录每个外设的实际工作频率。例如 24 MHz 晶振经 PLL 倍频到 480 MHz,再经 UART 分频器除以 16 得到 30 MHz 参考时钟,则波特率除数按 div = 30e6 / (16 × baud) 计算,115200 bps 时整数部分为 16、小数部分约为 0.28。这些数值必须来自时钟树而非猜测。

五、中断控制器与外设清单:向量号与使能项

中断控制器手册要提取三样东西:中断源编号与向量号的对应关系、优先级分组方式、触发类型(电平/边沿)。整理成表后,intConnect() 的向量参数才有依据。外设清单则用于决定 config.h 中保留哪些 INCLUDE_ 组件:板上只有一路以太网就只保留一个网络驱动,没有 USB 控制器就删除 USB 相关组件,避免编译出无用的驱动并占用内存。

六、引脚复用:最容易遗漏也最容易出错

引脚复用表要逐引脚记录“引脚号—复用功能编号—方向—电气属性”。例如某引脚默认是 GPIO,要作为 UART0_TXD 使用,则需在 sysHwInit() 中写入 IOMUX 寄存器选择功能 2,并设置驱动能力与上拉。若遗漏这一步,串口会表现为“寄存器配置正确但无输出”,这是 BSP 调试中非常典型的故障。建议把复用配置集中到 sysPinMux.c,按外设分组,便于与原理图逐条核对。

研读资料时同步建立一份“硬件事实表”,每行记录:项目、来源资料页码、提取值、对应 BSP 文件与宏名。后续调试出现地址或频率错误时,可直接回溯到原始资料,避免反复翻手册。
原理图、数据手册与引脚复用表三者可能不一致,尤其是引脚复用表常滞后于最新版原理图。遇到冲突时以原理图实物连接为准,并在硬件事实表中标注冲突点,必要时向硬件工程师确认,不要凭猜测填写寄存器。

把上述七类资料整理成结构化的硬件事实表后,BSP 的地址宏、时钟参数、中断向量和引脚配置就有了唯一、可追溯的来源。这一步做得越扎实,后续 sysHwInit() 编写和板级调试的返工就越少。