Nvidia Jetson Xavier CAN总线配置避坑指南:从GPIO设置到开机自启脚本
在工业自动化、智能驾驶或者机器人控制这些领域里,稳定可靠的通信是项目的生命线。CAN总线,这个诞生于汽车工业的通信协议,以其高可靠性和实时性,早已成为这些苛刻环境下的首选。Nvidia Jetson Xavier,作为边缘计算领域的明星平台,其强大的AI算力与内置的CAN控制器结合,为开发者构建智能边缘节点提供了绝佳的基础。然而,从硬件引脚到软件驱动的完整配置链路,并非一路坦途。许多开发者,包括我自己,都曾在这条路上踩过不少坑——寄存器配置的晦涩、驱动加载的时序、自启动脚本的稳定性,每一个环节都可能让CAN接口“沉默不语”。
这篇文章,正是为了让你绕开这些陷阱而写。我不会仅仅重复官方文档的步骤,而是聚焦于那些文档里没有写明、论坛里需要翻找很久的“实战细节”。我们将从最底层的GPIO引脚功能复用开始,一步步打通到系统启动后CAN接口自动就绪的完整流程。无论你是正在为自动驾驶小车搭建通信模块,还是在为工业质检设备集成控制网络,这篇指南都将帮助你高效、稳定地在Jetson Xavier上激活CAN总线,把时间花在更有价值的应用开发上。
1. 理解Jetson Xavier的CAN硬件基础与配置逻辑
在动手敲命令之前,花几分钟理解Jetson Xavier上CAN控制器的硬件布局和软件配置的底层逻辑,能让你在遇到问题时更快地定位根源。Jetson Xavier AGX开发者套件提供了两路独立的CAN控制器,对应can0和can1。但一个关键点是:这些控制器的信号引脚并没有直接连接到外部接口,而是与40针扩展接头上的GPIO引脚复用。
这意味着,默认情况下,这些引脚被配置为普通的GPIO功能。你的第一个任务,就是通过修改SoC内部的引脚复用控制器(Pinmux)的寄存器,将这些引脚的功能从“通用输入输出”切换为“CAN收发”。这里就引出了第一个常见的困惑点:修改Pinmux的两种途径及其取舍。
- 方法A:通过设备树(Device Tree)或Pinmux配置表刷机。这是最“干净”、最持久的方法,需要修改BSP(板级支持包)的配置文件,然后重新用JetPack刷写系统。对于产品化部署,这是推荐的方式。
- 方法B:在系统运行时直接读写内存映射的寄存器。这种方法无需重刷系统,通过
devmem这样的工具直接修改寄存器值即可生效,但修改会在重启后丢失。
对于大多数正在原型开发或快速验证的开发者,方法B的灵活性和便捷性更具吸引力。本指南也将重点围绕方法B展开,并最终通过系统服务将其“固化”。你需要操作的四个关键寄存器地址和值如下表所示,它们分别对应CAN0和CAN1的收发引脚:
| 寄存器地址 | 引脚功能 | 写入值 | 对应物理引脚 (40针接头) |
|---|---|---|---|
0x0c303000 | CAN0_DIN (接收) | 0x0000C400 | Pin 29 |
0x0c303008 | CAN0_DOUT (发送) | 0x0000C458 | Pin 31 |
0x0c303010 | CAN1_DIN (接收) | 0x0000C400 | Pin 37 |
0x0c303018 | CAN1_DOUT (发送) | 0x0000C458 | Pin 33 |
注意:寄存器地址和值是针对特定JetPack版本和Xavier模块的。虽然目前主流版本通用,但如果未来Nvidia更新了BSP,建议核对最新的技术文档。直接操作寄存器存在风险,务必确保地址和值准确。
理解了“为什么”要写这些寄存器之后,操作本身很简单。首先确保安装了寄存器读写工具(如busybox中的devmem):
sudo apt update
sudo apt install busybox
然后依次执行四条命令完成引脚功能切换:
sudo busybox devmem 0x0c303000 32 0x0000C400
sudo busybox devmem 0x0c303008 32 0x0000C458
sudo busybox devmem 0x0c303010 32 0x0000C400
sudo busybox devmem 0x0c303018 32 0x0000C458
执行后不会有成功提示,但只要没报错,引脚复用配置就已经生效了。这是通往稳定CAN通信的第一步,也是最容易因疏忽而出错的一步。
2. 驱动加载与网络接口配置的实战细节
引脚配置好后,接下来就是让系统内核识别并驱动CAN控制器。Jetson Xavier使用的CAN驱动是mttcan(Multi-Time Triggered CAN),它是Linux内核CAN子系统的一部分。加载驱动听起来就是几条modprobe命令,但这里有几个坑点需要特别注意。
驱动加载的顺序与依赖关系。CAN子系统是模块化设计的,你需要按顺序加载核心模块和具体控制器驱动:
sudo modprobe can # 加载CAN协议核心模块
sudo modprobe can_raw # 加载RAW CAN协议模块,用于原始套接字通信
sudo modprobe mttcan # 加载Jetson Xavier的CAN控制器硬件驱动
如果直接加载mttcan而忽略了前两个,驱动可能会加载失败或出现意想不到的行为。你可以使用lsmod | grep can命令来验证这三个模块是否都已成功加载。
驱动加载成功后,系统会创建出can0和can1两个网络接口,但此时它们还处于“未配置”状态。你需要使用ip link命令来设置CAN总线的参数并启动它。这里就是第二个容易踩坑的地方:参数配置的完整性与兼容性。
很多教程只设置基本的比特率(bitrate),但在实际工业或车载网络中,你可能需要用到CAN FD(灵活数据速率)或者开启错误报告。下面是一个兼顾了经典CAN和CAN FD的配置示例:
# 配置can0,经典CAN模式500Kbps,开启错误报告
sudo ip link set can0 type can bitrate 500000 berr-reporting on
# 配置can0,启用CAN FD,数据段速率2Mbps
sudo ip link set can0 type can bitrate 500000 dbitrate 2000000 berr-reporting on fd on
# 启动can0接口
sudo ip link set up can0
# 对can1进行相同配置
sudo ip link set can1 type can bitrate 500000 dbitrate 2000000 berr-reporting on fd on
sudo ip link set up can1
bitrate: 仲裁阶段的波特率,必须与总线上的其他节点一致。dbitrate: CAN FD数据阶段的波特率,仅当fd on时有效。berr-reporting on: 强烈建议开启,它能让接口在总线上出现错误时生成相应的错误帧,对于调试网络问题至关重要。fd on: 启用CAN FD模式。请注意:只有当总线上的所有节点都支持FD时才能开启,否则会导致通信失败。
配置完成后,使用ifconfig can0或ip -details link show can0命令检查接口状态。如果看到UP,RUNNING的标志,并且有RX packets和TX packets的计数器(可能都是0),说明接口已经成功启动。此时,你已经可以在本机使用candump、cansend等工具(来自can-utils包)进行基本的收发测试了。
3. 构建可靠的开机自启动方案
手动测试成功只是第一步,对于任何嵌入式产品或工业设备,上电后自动完成配置是基本要求。由于我们采用了运行时修改寄存器的方法,所以必须创建一个开机自启动脚本,在每次启动时自动执行前述的所有配置步骤。这里的选择很多,但稳定性和鲁棒性是首要考量。
方案一:使用/etc/rc.local(简单但已过时)
这是最直接的方法。创建一个配置脚本,例如/home/nvidia/enable_can.sh,并确保它有执行权限:
#!/bin/bash
# enable_can.sh - 配置Jetson Xavier CAN总线
# 1. 配置GPIO引脚复用为CAN功能
sudo busybox devmem 0x0c303000 32 0x0000C400
sudo busybox devmem 0x0c303008 32 0x0000C458
sudo busybox devmem 0x0c303010 32 0x0000C400
sudo busybox devmem 0x0c303018 32 0x0000C458
# 2. 加载CAN驱动模块
sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan
# 等待驱动完全初始化,避免竞态条件
sleep 1
# 3. 配置并启动CAN接口
sudo ip link set can0 type can bitrate 500000 dbitrate 2000000 berr-reporting on fd on
sudo ip link set can1 type can bitrate 500000 dbitrate 2000000 berr-reporting on fd on
sudo ip link set up can0
sudo ip link set up can1
exit 0
然后,在/etc/rc.local文件的exit 0之前加入调用该脚本的命令:
/bin/bash /home/nvidia/enable_can.sh &
提示:
&符号让脚本在后台执行,避免阻塞系统启动流程。rc.local本身在大多数现代Linux发行版中已被systemd取代,但在Jetson的L4T系统中通常仍可用。不过,它的执行时机可能偏晚,且对脚本错误的容忍度较低。
方案二:创建systemd服务(推荐的生产环境方案)
systemd提供了更强大、更可控的服务管理能力。我们可以创建一个专用的服务单元文件。
- 创建服务文件
/etc/systemd/system/can-bus.service:[Unit] Description=Configure CAN Bus on Jetson Xavier After=network.target local-fs.target Before=network-online.target Wants=network-online.target [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/local/bin/enable_can.sh StandardOutput=journal [Install] WantedBy=multi-user.target - 将之前的脚本内容放到
/usr/local/bin/enable_can.sh,并赋予执行权限(sudo chmod +x /usr/local/bin/enable_can.sh)。 - 启用并启动服务:
sudo systemctl daemon-reload sudo systemctl enable can-bus.service sudo systemctl start can-bus.service sudo systemctl status can-bus.service # 检查状态
方案三:利用@reboot的cron任务(灵活的用户级方案)
如果你希望以非root用户(如nvidia)的身份来管理这个脚本,或者想更灵活地控制,可以使用cron的@reboot功能。
- 编辑当前用户的cron表:
crontab -e - 在文件末尾添加一行:
这会在每次系统启动时以该用户身份执行脚本,并将输出重定向到日志文件便于排查问题。@reboot /bin/bash /home/nvidia/enable_can.sh > /home/nvidia/can_startup.log 2>&1
无论选择哪种方案,关键是要增加错误处理和状态检查。例如,在脚本中可以先检查/dev/can0设备节点是否存在,或者用ip link show can0检查接口状态,再决定是否执行配置命令,避免重复配置或命令失败导致脚本中止。我自己在项目中更倾向于使用systemd服务,因为它提供了完善的日志(通过journalctl -u can-bus.service查看)和依赖关系管理,更符合工业应用的可靠性要求。
4. 硬件连接、测试与故障排查清单
软件配置妥当后,最后一步是连接物理的CAN收发器模块,并进行端到端的测试。Jetson Xavier的GPIO扩展口引脚排列需要仔细核对,接错线是导致“通信静默”的最常见硬件原因。
硬件连接指南: 你需要一个3.3V供电的CAN收发器模块(如TJA1050、SN65HVD230等)。连接时请参考下表:
| Jetson Xavier 40针引脚 | 引脚编号 | 信号名称 | 连接至收发器 |
|---|---|---|---|
| Pin 29 | 29 | CAN0_DIN (RX) | 收发器的TXD (或CTX) 注意:方向是Xavier收,对应收发器发 |
| Pin 31 | 31 | CAN0_DOUT (TX) | 收发器的RXD (或CRX) |
| Pin 33 | 33 | CAN1_DOUT (TX) | 第二个收发器的RXD (或CRX) |
| Pin 37 | 37 | CAN1_DIN (RX) | 第二个收发器的TXD (或CTX) |
| Pin 1 或 Pin 17 | 1/17 | 3.3V PWR | 收发器的VCC |
| Pin 9 或 Pin 25 | 9/25 | GND | 收发器的GND |
重要提醒:务必确认收发器模块的电压是3.3V,与Jetson GPIO电平匹配。部分模块自带120欧姆终端电阻,如果总线两端已有终端电阻,则需要断开模块上的电阻,避免总线上出现两个并联的终端电阻。
连接好硬件后,可以开始测试。首先安装测试工具:
sudo apt install can-utils
基础回环测试:在单节点上,可以先将can0的TX和RX在收发器端短接(或者使用Linux的虚拟回环模式),进行自发自收测试。
# 设置回环模式并启动(需先down掉接口)
sudo ip link set can0 down
sudo ip link set can0 type can bitrate 500000 loopback on
sudo ip link set up can0
# 在一个终端监听
candump can0
# 在另一个终端发送
cansend can0 123#1122334455667788
如果能在candump终端看到发送的帧,说明软硬件链路基本通畅。
双节点通信测试:将两个Jetson Xavier(或一个Xavier和一个其他CAN设备)通过CAN_H和CAN_L线连接,并确保总线两端各有一个120欧姆终端电阻。在两个设备上分别配置相同的波特率,然后互发数据。
当通信不成功时,可以按照以下清单进行排查:
- 引脚复用确认:
devmem命令是否执行成功且无报错?重启后是否忘了加入自启动? - 驱动加载确认:
lsmod | grep can是否显示了can、can_raw、mttcan? - 接口状态确认:
ip -details link show can0显示的状态是UP吗?state是ERROR-ACTIVE吗? - 硬件连接确认:
- 电源(3.3V和GND)是否接通?用万用表测量。
- TX/RX线是否接反?(最常见硬件错误)
- CAN_H和CAN_L是否接对?是否与总线其他节点连接?
- 终端电阻是否正确?用万用表测量CAN_H与CAN_L之间的电阻,在总线两端各有一个120欧姆电阻时,并联阻值应约为60欧姆。
- 总线错误检查:开启
berr-reporting后,使用candump时可能会看到错误帧。错误帧是定位物理层问题(如短路、开路、干扰)的宝贵线索。 - 系统日志检查:使用
dmesg | grep can或journalctl -f查看内核和系统服务日志,寻找驱动加载错误或配置失败的信息。
配置CAN总线的过程就像解一道多层谜题,软件、硬件、配置、时序环环相扣。遵循上述步骤,并仔细核对每一个环节,你就能在Jetson Xavier上建立起稳定、可靠的CAN通信通道,为你的边缘AI应用铺平道路。
1278



被折叠的 条评论
为什么被折叠?



