VxWorks BSP移植实战:AT91RM9200串口与网络驱动调试

发布时间:2026/9/12 13:29:30
VxWorks BSP移植实战:AT91RM9200串口与网络驱动调试 简介这是一份面向VxWorks嵌入式开发者的AT91RM9200板级支持包BSP与驱动资源基于ARM920T内核覆盖网卡、串口、Flash存储等关键外设适用于工业控制、通信设备等需要实时操作系统的嵌入式场景。压缩包约800KB共86个文件27个C源码、15个头文件、12个编译生成的.o目标文件另有4个调试脚本、3个汇编文件、Makefile及引导镜像二进制等从启动初始化、板级配置到网卡驱动和串口驱动均有代码可参考。目前已有136人学习下载适合需要快速在AT91RM9200平台上搭建VxWorks系统、移植驱动或排查启动问题的中高级嵌入式工程师。资源保留大量备份文件便于对比不同版本修改、定位编译与运行错误配合Flash编程脚本与TFFS相关源码可用于调试NAND Flash存储与引导加载流程。无论是学习BSP框架、理解驱动实现还是基于该平台二次开发都能从中找到可复用的起点。1. 一块 2003 年的 MCU一份乱糟糟的 BSP为什么还要手工调at91rm9200加vxworks这两个词凑在一起想表达的往往不是炫技而是救火。一块基于 ARM920T 内核、主频 180MHz 的微控制器在电力、轨交、工控的板卡上稳定跑了十几年系统是 VxWorks而维护方手里往往只有一份从老工程师电脑里翻出来的at91rm9200.rar压缩包里面是 vxworks_bsp 的全部工程、几个没头没尾的驱动源码以及一个改得面目全非的config.h。真正头疼的是这份 BSP 在新主机、新闪存、新串口芯片上经常起不来。这篇文章顺着 BSP 从压缩包到能跑通串口 console、再到网络和驱动验证的路径把 AT91RM9200 上 VxWorks BSP 的骨架、最小改动和排错顺序讲清楚。适合手里有存量设备、又绕不开 vxworks 驱动移植的现场工程师。2. 拆解 BSP从地址映射到 config.h 与 sysLib.c一个 VxWorks BSP 的本质是替操作系统做三件事把 CPU 的存储控制器和外设时钟配到能跑把内核的内存布局落在板级地址上把板载外设接进 VxWorks 的 I/O 系统。拿到at91rm9200.rar后先别急着编译先把地址映射和 BSP 文件的对应关系理顺。2.1 AT91RM9200 的存储映射决定了 BSP 里一半的宏AT91RM9200 的地址空间和常见 ARM Linux 板卡不太一样。它的 16KB 内部 SRAM、外部 SDRAM 以及 APB 总线上的外设分布在不同的地址区间VxWorks 的RAM_LOW_ADRS、RAM_HIGH_ADRS、外设基地址宏全部从这张表来。我常用的参考值如下对象参考地址说明内部 SRAM0x00100000 附近bootrom 早期的栈和少量数据重映射后位置会变外部 SDRAM0x20000000 起VxWorks 内核和任务的主要运行区DBGU 调试串口0xFFFFF200 附近调试输出首选console 常挂在这里USART0/USART1/USART20xFFFC0000 起每 16KB 一个业务串口驱动编写时用AIC 中断控制器0xFFFFF000所有中断的汇集与分发这张表不是死的具体数值以 AT91RM9200 数据手册为准不同版本的 BSP 也会把这些地址封装成AT91C_BASE_DBGU、AT91C_BASE_US0这类宏。排错第一步就是打开config.h和board.h确认这些宏没有被上一任工程师改成别的板卡的值。2.2 config.h 里三个必调参数RAM_LOW_ADRS、RAM_HIGH_ADRS、CLK_RATE_SYSVxWorks 启动后会把内核镜像拷到RAM_LOW_ADRS系统可用的物理内存顶是RAM_HIGH_ADRS这两个宏写错最典型的后果是bootrom 能起来但vxWorks镜像加载后异常复位。SDRAM 从 0x20000000 起步128MB 内存的 BSP 里应该有类似配置#define RAM_LOW_ADRS 0x20000000 #define RAM_HIGH_ADRS 0x28000000 #define USER_RESERVED_MEM 0x00000000 #undef LOCAL_MEM_AUTOSIZE代码里的LOCAL_MEM_AUTOSIZE值得单独说。老 BSP 里常开着自动探测内存大小但 AT91RM9200 的 EBI 时序如果没配好探测结果会偏小一半。我一般直接关掉自动探测把RAM_HIGH_ADRS写成根据实际内存颗粒计算后的值省得每次冷启动都要碰运气。CLK_RATE_SYS和CLK_RATE_TIMER是另一组高频出错点。AT91RM9200 的时钟树经过主振荡器、PLL、PMC 分频BSP 里写 1 秒假定的时钟源是外部晶振直通还是 PLL 输出直接决定串口波特率和系统 tick 是否准确。核对 PMC 配置时别只看数值要确认写进寄存器的分频链最终得到的是 180MHz 还是 90MHz。2.3 用 make 把 bootrom 和 vxWorks 镜像一次拉起来在 Tornado 或 Workbench 的 shell 里进到 BSP 目录编译命令通常是这样cd /work/bsp/at91rm9200 make clean make bootrom make vxWorksmake clean清掉上一次的产物和中间文件make bootrom生成引导镜像烧进 NOR Flash 或由加载器拉进 SRAMmake vxWorks生成完整内核镜像。很多现场问题是老 Makefile 里编译器路径写死导致的打开 Makefile 看TOOL、CC、LD两行把arm-elf-gcc这类命令改成当前主机实际存在的交叉工具链路径即可。3. 让 console 先响USART 串口驱动接进 VxWorks 的 tty 层BSP 移植的第一关永远是串口。console 不响后面所有调试都像盲飞。VxWorks 下的串口驱动是两层结构底层用SIO_DRV_FUNCS描述硬件操作上层通过ttyDevCreate挂进 I/O 系统应用层直接用open/read/write访问/tyCo/0。3.1 console 挂 DBGU 还是 USART0AT91RM9200 的 DBGU 调试口初始化最简单引脚固定、不需要复用配置很多参考 BSP 默认把 console 放在 DBGU。但 DBGU 在板子上未必引出了 RS232 电平转换器这时就要改到 USART0。改 console 串口核心是确认三个宏CONSOLE_TTY、CONSOLE_BAUD_RATE、CONSOLE_DEV。比如把 console 切到 USART0#define CONSOLE_TTY 0 #define CONSOLE_BAUD_RATE 115200 #define CONSOLE_DEV /tyCo/0其中CONSOLE_TTY对应 sysSerial.c 里创建的 tty 设备序号CONSOLE_BAUD_RATE要和终端软件一致CONSOLE_DEV是应用层打开的设备名。改完这三个宏后把第二块串口板卡的收发短接用串口工具发一帧数据就能验证底层SIO_DRV_FUNCS的ioctl和收发回调是否工作。3.2 sysSerial.c 初始化顺序与中断注册sysSerial.c里有三个关键函数sysSerialHwInit、sysSerialHwInit2、sysSerialIoctl。第一个做寄存器级初始化第二个在中断向量表就绪后挂中断服务例程。初始化顺序不能反因为intConnect依赖中断向量表已经建立。典型代码骨架如下void sysSerialHwInit (void) { /* 第一步关串口中断配波特率、8 位数据位、1 停止位 */ bspUartInit (AT91C_BASE_US0, CONSOLE_BAUD_RATE, 8, 1, NOPARITY); } void sysSerialHwInit2 (void) { /* 第二步中断向量表已就绪挂 USART0 接收中断 */ (void) intConnect (INUM_TO_IVEC (AT91C_ID_US0), (VOIDFUNCPTR) usrUartInt, 0); (void) intEnable (AT91C_INT_US0); }代码逻辑说明bspUartInit负责把 USART0 的波特率发生器和数据格式写入寄存器intConnect把usrUartInt挂到 AIC 的 USART0 中断源上intEnable打开中断。参数里值得调整的是波特率计算AT91RM9200 的 USART 波特率由 MCK 分频而来如果 PMC 里 MCK 不是预期值115200 会被算成 120200 甚至完全乱码。查这个问题不要盯着串口寄存器先查 PMC 和 PLL 配置。3.3 中断没进时的三个排查动作串口能发不能收多半是中断链路断了。第一看 AIC 对应位有没有被屏蔽在 WindSh 里执行- sysIntShow(AT91C_ID_US0)没有这个命令就用- intShow()或直接读 AIC 的IPR寄存器确认挂起位有没有置 1。第二确认usrUartInt里真的调用了接收缓冲区唤醒逻辑而不是只做了logMsg打印。第三用示波器或逻辑分析仪量 MCK 引脚排除时钟压根没跑的情况。中断链路查到intConnect返回值不是OK时多半是中断号映射错误回去对照数据手册检查INUM_TO_IVEC的换算。4. EMAC 网络驱动让 BSP 能跑 TFTP 加载内核串口通了之后下一步是把网络打通。AT91RM9200 内置 10/100M EMAC 控制器VxWorks 里的网络设备以 ENDEnhanced Network Driver形式挂接。网络通了的直接收益是bootrom 里配置好 IP就能用 TFTP 把vxWorks镜像拉到 SDRAM不用每次改动都烧 Flash。4.1 configNet.h 挂 END 设备表VxWorks 的 END 驱动需要向网络协议栈注册一个加载函数。在configNet.h里常见写法是定义END_TBL_ENTRY#define INCLUDE_END IMPORT END_OBJ * at91rm9200EndLoad (char * pInitString, void * pEndDev); END_TBL_ENTRY endDevTbl [] { { 0, at91rm9200EndLoad, smc0, at91rm9200 }, { 0, END_TBL_END, NULL, NULL } };代码逻辑说明at91rm9200EndLoad是 EMAC 驱动的入口协议栈初始化时会调用它创建设备对象smc0是网络接口名at91rm9200是传给驱动的参数串。如果 BSP 目录里只有一个网络驱动文件endDevTbl基本就是这么短的数组。驱动内部需要处理三块MAC 寄存器初始化、描述符环BD ring建立、PHY 状态轮询。描述符环的地址要特别注意 cache 一致性驱动里对 BD 和 DMA 缓冲做完写操作后必须调CACHE_TEXT_UPDATE或sysCacheFlush的等价接口否则网络收发包在启用了 MMU cache 的 vxWorks 镜像下会丢包。4.2 PHY 地址和 MII 模式是翻车重灾区AT91RM9200 的 EMAC 支持 MII 和 RMII 两种接口具体取决于板上 PHY 芯片的配置引脚。PHY 地址通过phyAddr参数传给驱动常见 PHY 芯片的默认地址如下PHY 芯片默认地址常见速率DM91610x0110/100MKSZ80410x01 或 0x0210/100MIP101A0x0010/100MRTL82010x0010/100MphyAddr配置错误时驱动读 PHY 的 BMSR 寄存器会一直返回 0xFFFF 或 0x0000现象是 ifShow 能看到接口但链路永远是 down。排查方式是在驱动初始化时打印 PHY ID 寄存器int phyId 0; phyRead (AT91C_BASE_EMAC, phyAddr, 0x02, phyId); logMsg (PHY ID1 0x%x\n, phyId, 0, 0, 0, 0, 0);若读回全 F先看 PHY 的地址拨码再看 MII/MDIO 引脚是否被 PIO 复用配置抢走了。4.3 网络加载链路不通时的排查顺序bootrom 里配好bootDevice、bootFile、hostIP、targetIP后TFTP 加载不起来按这个顺序查终端里执行- pingInet(192.168.1.10)先确认链路层有没有通不通就回到 PHY 寄存器读 BMSR 确认 ANEG 是否完成用- ifShow(smc0, 0)看 MTU、MAC、IP 是否生效若 MAC 地址全 0驱动里要显式从配置区读取或写死EMAC 没有内置 MAC 存储MAC 地址全 0 是最容易被忽略的AT91RM9200 不像后来的 SAM 系列有出厂唯一标识区很多 BSP 默认值就是0:0:0:0:0:0协议栈初始化时会拒绝启用接口。5. 验证与收尾用串口回环和 cache 检查把驱动边界测干净BSP 基本跑通后不要急着交给应用组。最后用两个低成本的验证手段把驱动边界测清楚。5.1 串口回环验证收发链路把 DBGU 或 USART0 的 TX 和 RX 短接在 VxWorks shell 里执行一段循环写读int fd; char ch A; char buf 0; fd open (/tyCo/0, O_RDWR, 0); for (int i 0; i 100; i) { write (fd, ch, 1); read (fd, buf, 1); if (buf ! ch) { printf (loopback fail at %d\n, i); break; } } close (fd);逻辑说明TX 发出数据经短接线直接回到 RX如果驱动收发路径中的 FIFO 管理、中断开关有任何一处不对read就会超时或读到错值。100 次连续成功说明底层SIO_DRV_FUNCS的收发方向没有隐患。若中间失败把波特率降到 9600 重测排除高速下时钟误差掩盖的问题。5.2 cache 一致性DMA 缓冲区的隐藏雷网络驱动和未来的 DMA 外设驱动都要过这一关。现象很经典数据在第一次读时是对的第二次读全变 0xFF或者收到旧数据。AT91RM9200 的 EMAC 描述符和缓冲区都在 DDR写 DMA 描述符后必须 flush读 DMA 数据前必须 invalidate。在驱动里收紧的写法是每次收发都做一次显式操作CACHE_FLUSH_DMA (pBuf, len); /* 启动 DMA 发送 */ CACHE_INVALIDATE_DMA (pBuf, len); /* 读取 DMA 收到的数据 */参数pBuf是 DMA 缓冲区指针len是长度。注意这两个宏针对的是虚拟地址如果 BSP 开了 MMU 而物理地址与虚拟地址不同要先用VX_PHYS_TO_VIRT换算。检查整个工程里是不是还有裸用memcpy访问 DMA 区的代码那是 cache 问题最常见的漏网点。验证 cache 配置是否正确的速成法在configAll.h里把INCLUDE_CACHE_SUPPORT临时关掉编译一版跑同样的收发测试。如果关掉 cache 后问题消失说明 BSP 主体没问题回去修驱动的 flush/invalidate 位置即可如果关掉后依然出错就得回头查 END 驱动流程或者 DMA 描述符的地址对齐。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询