4. 嵌入式操作系统与驱动开发环境
航电计算平台上的串行总线驱动,最终都要落到某个具体的嵌入式操作系统上运行。VxWorks、Linux、RTEMS 是航电领域最常见的三类选择:VxWorks 以强实时和成熟认证生态见长,Linux 以生态丰富和开发效率见长,RTEMS 以开源、可裁剪和确定性调度见长。三者的驱动模型差异,直接决定了同一份总线驱动代码需要怎样改写、怎样编译、怎样调试。理解这些差异,是驱动集成能否顺利推进的前提。
一、三种 OS 的驱动模型差异
VxWorks 采用分层驱动模型。最底层是 BSP(板级支持包),负责 CPU 初始化、中断控制器、时钟和内存映射;中间层是 VxBus 设备驱动框架,驱动以 struct vxbDriver 注册,通过 vxbDevMethod 提供 probe、attach、start 等方法;上层是 I/O 系统,字符设备通过 iosLib 挂接 open/read/write/ioctl。串行总线驱动通常实现为一个 VxBus 驱动,在 attach 阶段完成寄存器映射、中断连接和收发队列初始化,在 start 阶段使能控制器。VxWorks 的中断服务程序运行在独立的中断栈上,ISR 中只能调用 *_from_isr 系列函数,耗时处理必须交给 workQueue 或任务完成。
Linux 采用总线—设备—驱动匹配模型。串行总线控制器一般挂在平台总线(platform bus)或 PCI 总线上,驱动用 platform_driver 注册,通过设备树(Device Tree)中的 compatible 属性与设备匹配。驱动的 probe 函数完成 ioremap、request_irq、DMA 通道申请和字符设备注册。中断处理分为上半部(硬中断)和下半部(tasklet、工作队列或线程化中断),这与 VxWorks 的 ISR + workQueue 思路一致,但 API 完全不同。Linux 还提供 tty 子系统和 serial_core 框架,若总线控制器被抽象为 UART 类设备,可直接复用该框架。
RTEMS 采用经典 RTEMS 驱动框架。驱动通过 rtems_driver_address_table 注册入口点,包括 initialization_entry、open_entry、close_entry、read_entry、write_entry、control_entry。中断通过 rtems_interrupt_handler_install 安装,ISR 中通过 rtems_event_send 或 rtems_message_queue_send 唤醒任务。RTEMS 没有 VxBus 那样的自动枚举框架,设备与驱动的绑定通常在 BSP 的 bsp_predriver_hook 或应用初始化阶段手工完成,配置更直接,但也更依赖开发者对硬件拓扑的掌握。
二、交叉编译工具链的搭建要点
航电计算平台通常采用 ARM、PowerPC 或 MIPS 架构,开发主机是 x86_64 Linux,因此必须使用交叉编译工具链。VxWorks 使用 Wind River 提供的 Diab 或 GCC 工具链,通过 Workbench 工程管理编译选项,生成 .o 或 .out 后由 wrbuild 链接进镜像。Linux 使用 aarch64-linux-gnu-gcc 或厂商提供的 SDK 工具链,驱动以模块形式编译时需准备内核源码树和 .config,通过 Kbuild 的 make M=drivers/xxx modules 生成 .ko。RTEMS 使用 arm-rtems6-gcc,配合 waf 构建系统,驱动源码放入 BSP 或应用目录后由 waf configure && waf build 完成编译。
工具链搭建中最容易出问题的是头文件与库的版本匹配。例如 Linux 驱动编译时,内核源码树版本必须与目标板运行的内核版本一致,否则 insmod 会报 version magic 不匹配。VxWorks 的 BSP 与工具链版本也需对应,混用不同版本的 vxWorks.h 可能导致结构体布局差异。RTEMS 的 BSP 配置(--enable-rtemsbsp=xxx)必须与目标板一致,否则中断向量表和内存映射会出错。
三、调试环境搭建与典型手段
VxWorks 的调试通常通过 Workbench 的 WDB 协议,经网口或串口连接目标板,支持任务级断点、变量查看和系统查看器(System Viewer)。对于驱动早期阶段,串口打印 printf 仍是最可靠的手段,但要注意 ISR 中不能直接调用 printf,应使用 logMsg。Linux 驱动调试可用 printk 配合 dmesg,也可用 ftrace 跟踪函数调用,或用 KGDB 进行源码级调试。RTEMS 常用 GDB + JTAG(如 OpenOCD)进行硬件断点调试,串口输出则通过 printf 重定向到 UART。
下面给出一份 Linux 平台下串行总线驱动模块编译与加载的示例命令序列,用于说明工具链与调试环境的实际衔接方式。示例假设目标板为 aarch64,内核源码树位于 /opt/kernel,驱动目录为 drivers/avionics_bus。
# 1. 设置交叉编译环境
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
export KERNEL_DIR=/opt/kernel
# 2. 编译驱动模块
make -C $KERNEL_DIR M=$PWD/drivers/avionics_bus modules
# 3. 查看生成的模块信息
modinfo drivers/avionics_bus/avionics_bus.ko
# 4. 拷贝到目标板并加载
scp drivers/avionics_bus/avionics_bus.ko root@192.168.1.100:/tmp/
ssh root@192.168.1.100 "insmod /tmp/avionics_bus.ko && dmesg | tail -20"
# 5. 查看设备节点与中断统计
ssh root@192.168.1.100 "ls /dev/avbus* && cat /proc/interrupts | grep avbus"
执行后应重点观察 dmesg 中驱动 probe 是否成功、/proc/interrupts 中中断号是否出现且计数随总线活动增长、/dev 下设备节点是否创建。若 probe 未触发,优先检查设备树 compatible 与驱动 of_match_table 是否一致;若中断计数不增长,检查 request_irq 返回值与触发方式配置。
version magic、VxWorks 的 BSP 版本、RTEMS 的 BSP 配置,任一不匹配都可能导致驱动加载失败或运行异常,且现象往往不直观。