在 JETSON 上配置 CAN 总线收发并基于Node.js编写应用DEMO

本文介绍如何在Nvidia Jetson TX2/AGX Xavier开发板上配置CAN总线,并使用Node.js实现基本的CAN通信应用。通过修改系统寄存器、设置总线参数及编写应用示例,详细展示了从硬件配置到软件实现的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

CAN 总线 是汽车电子行业常用的通信协议. Nvidia 推出的边缘 AI 推理设备 JETSON TX2 / AGX Xavier 两款开发板支持 CAN 总线通信. 这里以 AGX Xavier 开发者套件 为例, 介绍如何配置实现基本的 CAN 总线数据收发, 并使用 Node.js 编写了基本的 CAN 通信应用 示例.

在 JETSON 上实现 CAN 通信应用的步骤大致是:

  1. 安装依赖项
  2. 配置寄存器
  3. 设置 CAN 总线参数
  4. 打开 CAN 总线端口
  5. 建立 Socket 连接
  6. 收发数据

其中步骤 1 是先决条件, 步骤 2-4 可以用系统命令脚本实现, 步骤 5-6 可以使用我们喜欢的语言实现.

下面的内容也基本按照这一思路展开介绍.

配置寄存器

由于 JETSON 系列开发板参照了树莓派(RaspberryPi)的 40 针引脚设计, 所以开发板上预留的 CAN0/CAN1 两组引脚默认映射到为通用输入输出端口(GPIO)上. 这就需要我们更新系统寄存器配置, 来将这些引脚重映射到 CAN0/CAN1 上. 一些教程博客给出了修改 Pinmux 配置文件的实现方法. 这些方法由于需要刷机, 可能需要涉及 Linux 系统底层原理的知识, 也伴随着一些风险. 这里参考https://github.com/hmxf/can_xavierhttps://blog.csdn.net/weifengdq/article/details/103093111 中给出的方法, 使用 busyboxdevmem 工具来修改系统配置.

需要将下面默认寄存器配置修改为应用 CAN 总线的寄存器配置.

# 默认寄存器配置
# 寄存器              寄存器装载值
pinmux.0x0c303000 = 0x0000c055; # can1_dout_paa0: rsvd1, pull-down, tristate-enable, input-enable
pinmux.0x0c303008 = 0x0000c055; # can1_din_paa1: rsvd1, pull-down, tristate-enable, input-enable
pinmux.0x0c303010 = 0x0000c059; # can0_dout_paa2: rsvd1, pull-up, tristate-enable, input-enable
pinmux.0x0c303018 = 0x0000c059; # can0_din_paa3: rsvd1, pull-up, tristate-enable, input-enable

# 应用 CAN 总线的寄存器配置
# 寄存器              寄存器装载值
pinmux.0x0c303000 = 0x0000c400; # can1_dout_paa0: rsvd1, pull-down, tristate-enable, input-enable
pinmux.0x0c303008 = 0x0000c458; # can1_din_paa1: rsvd1, pull-down, tristate-enable, input-enable
pinmux.0x0c303010 = 0x0000c400; # can0_dout_paa2: rsvd1, pull-up, tristate-enable, input-enable
pinmux.0x0c303018 = 0x0000c458; # can0_din_paa3: rsvd1, pull-up, tristate-enable, input-enable

在开始修改前, 首先需要安装 busybox,

sudo apt install busybox

可以先检查一下当前寄存器装在的值.

sudo busybox devmem 0x0c303000  # 0x0000C055
sudo busybox devmem 0x0c303008  # 0x0000C055
sudo busybox devmem 0x0c303010  # 0x0000C059
sudo busybox devmem 0x0c303018  # 0x0000C059

接下来修改寄存器配置.

sudo busybox devmem 0x0c303000 32 0x0000C400
sudo busybox devmem 0x0c303008 32 0x0000C458
sudo busybox devmem 0x0c303010 32 0x0000C400
sudo busybox devmem 0x0c303018 32 0x0000C458

可以再检查一下寄存器的值是否修改正确.

sudo busybox devmem 0x0c303000	# 0x0000C400
sudo busybox devmem 0x0c303008	# 0x0000C458
sudo busybox devmem 0x0c303010	# 0x0000C400
sudo busybox devmem 0x0c303018	# 0x0000C458

如果终端输出与 # 后面的值相同, 那么就证明完成了寄存器的配置.

设置 CAN 总线参数

我们使用 mttcan 管理系统的 CAN 总线, 这样就可以在应用中使用 Socket 打通处理 CAN 总线数据的环节.

首先需要在操作系统上挂载 mttcan 和相关组件.

sudo modprobe can
sudo modprobe can_raw
sudo modprobe can_dev
sudo modprobe mttcan

使用 lsmod 命令检查 mttcan 是否成功挂载.

$ lsmod
Module                  Size  Used by
mttcan                 66187  0
can_dev                13306  1 mttcan
can_raw                10388  0
can                    46600  1 can_raw
bnep                   16562  2
fuse                  103841  5
zram                   26166  8
overlay                48691  0
nvgpu                1569917  33
bluedroid_pm           13912  0
ip_tables              19441  0
x_tables               28951  1 ip_tables

在设置参数之前, 最好确保 ip link 未打开 can0 / can1 两个端口, 所以先手动关闭can0 / can1.

sudo ip link set down can0
sudo ip link set down can1

接下来配置 CAN 总线的参数. 其中最重要的参数是 bitrate 也就是波特率, 除此以外的配置可以输入 ip link help can 来查看. 这里我们设置 bitrate 为 1Mb/s.

sudo ip link set can0 type can bitrate 1000000
sudo ip link set can1 type can bitrate 1000000

打开 CAN 总线端口

配置好参数后就可以打开 can0 / can1 了.

sudo ip link set up can0
sudo ip link set up can1

可以使用 ifconfig 来检查输出中是否包含了 can0 / can1, 如果有, 那么我们已经成功打开这两个端口.

$ ifconfig
can0: flags=193<UP,RUNNING,NOARP>  mtu 16
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 10  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 66

can1: flags=193<UP,RUNNING,NOARP>  mtu 16
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 10  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 67

一段简单的测试

在编写应用实现 CAN 总线数据收发之前, 可以先在终端进行简单测试, 检查软硬件是否正确配置. 测试分为两步: 1) 软件层面是否可以正常收发数据; 2) 两个端口 can0can1 之间是否可以通过硬件线路完成数据收发.

我们使用 can-utils 进行测试, 首先需要安装这个工具.

sudo apt install can-utils

进行第 1) 步测试, 将 can0 端口设置为 loopback 模式, 自发自收.

sudo ip link set down can0
sudo ip link set can0 type can bitrate 1000000 loopback on
sudo ip link set up can0

然后打开两个终端, 用终端 1 监听 can0 端口接收的数据, 用终端 2 发送数据到 can0.

# 终端1
candump can0

# 终端2  <can_id>#{data}, 用.隔开,每一位是一个16进制数
cansend can0 123#99.95.42.07.2B.96.66.6E

发送数据后, 终端 1 输出:

  can0  123   [8]  99 95 42 07 2B 96 66 6E
  can0  123   [8]  99 95 42 07 2B 96 66 6E

接下来进行第 2) 步测试, 使用 can0can1 发送数据. 首先要连好硬件电路. 然后打开两个终端, 终端 1 监听 can1 接收的数据, 终端 2 通过 can0 发送数据.

# 终端1
candump can1

# 终端2
cansend can0 123#99.95.42.07.2B.96.66.6E

发送数据后, 终端 1 输出:

  can1  123   [8]  99 95 42 07 2B 96 66 6E

如此, 则测试通过.

自动化脚本

上述的配置在 JETSON 重启之后会丢失, 为了快速实现上述配置步骤, 可以用 shell 脚本实现.

将下面的命令写入 set_can.sh 文件里.


# 检查寄存器配置
sudo busybox devmem 0x0c303000 && sudo busybox devmem 0x0c303008 && sudo busybox devmem 0x0c303010 && sudo busybox devmem 0x0c303018

# 修改寄存器配置
sudo busybox devmem 0x0c303000 32 0x0000C400 && sudo busybox devmem 0x0c303008 32 0x0000C458 && sudo busybox devmem 0x0c303010 32 0x0000C400 && sudo busybox devmem 0x0c303018 32 0x0000C458
# 检查一下寄存器的值是否修改正确
# 0x0000C400
# 0x0000C458
# 0x0000C400
# 0x0000C458
sudo busybox devmem 0x0c303000
sudo busybox devmem 0x0c303008
sudo busybox devmem 0x0c303010
sudo busybox devmem 0x0c303018

# 在操作系统上挂载 `mttcan` 和相关组件
sudo modprobe can
sudo modprobe can_raw
sudo modprobe can_dev
sudo modprobe mttcan

# 使用 `lsmod` 命令检查 `mttcan` 是否成功挂载
lsmod

# 接下来配置 CAN 总线的参数. 我们设置 `bitrate` 为 1Mb/s.
sudo ip link set down can0
sudo ip link set down can1
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can1 type can bitrate 1000000
sudo ip link set up can0
sudo ip link set up can1

# 可以使用 `ifconfig` 来检查输出中是否包含了 `can0` / `can1`, 如果有, 那么我们已经成功打开这两个端口.
ifconfig can0
ifconfig can1

这样, 在重启机器后可以使用在set_can.sh 文件夹下运行 bash set_can.sh 完成配置.

使用基于 Node.js 封装的 SocketCAN 收发 CAN 总线数据

SocketCAN 是一个 Linux 系统下使用 C 语言 编写的 CAN 协议实现方法, 实现了各种 CAN 总线数据收发功能. rawcan 则提供了基于 Node.js 的封装, 使得我们可以使用 JavaScript 来编写自己的应用. 这个库符合 Node.js 事件驱动的理念, 对于 can 通信的接口也简单直接.

我们使用 can0can1 发送数据. 首先要连好硬件电路. 然后打开两个终端, 终端 1 运行 can1.js, 监听 can1 接收的数据; 终端 2 运行 can0.js, 通过 can0 发送数据.

首先应该在 JETSON 上安装 Node.js, 然后新建一个文件夹, 在该文件夹下, 用 npm / cnpm 安装 rawcan.

npm install --save rawcan

接下来, 写入 can0.jscan1.js 两个文件.

/********* can0.js *********/
const can = require('rawcan') // 引用 rawcan
const socket = can.createSocket('can0') // 创建一个新的 Socket, 绑定到 can0 端口
// 设置定时中断
setInterval(() => {
  // 中断回调函数
  // 定时通过 can0 发送数据, socket.send(id: number, buffer: Buffer | string | number[])
  socket.send(can.EFF_FLAG | 0x23c89f, 'hello')
}, 1000) // 定时间隔 1000ms

/********* can1.js *********/
const can = require('rawcan') // 引用 rawcan
const socket = can.createSocket('can1') // 创建一个新的 Socket, 绑定到 can1 端口
// 如果 Socket 提交了 'error' 事件, 则在控制台打印这一错误
socket.on('error', (err) => {
  console.log('socket error: ' + err)
})
socket.on('message', (id, buffer) => {
  // 如果 Socket 接收到了新的 'message', 则
  // 将 message 的 id 和 buffer 转为16进制编码的字符串并打印
  console.log(
    'received frame [' + id.toString(16) + '] ' + buffer.toString('hex')
  )
})

在终端 1 和终端 2 分别依次运行这两个文件.

# 终端1
node can1.js

# 终端2
node can0.js

终端 1 每间隔 1s 输出一帧接收到的消息.

#终端1
received frame [8023c89f] 68656c6c6f

如此, 则可以在此基础上实现自己的应用.

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值