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

2023-05-16

概述

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_xavier 和 https://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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result

    文章目录 背景解决 背景 mybaitsPlus this baseMapper selectOne wrapper 查出多个结果 xff0c 抛出了异常 解决 getOne wrapper false ServiceImpl getOne
  • RARP的使用

    大家好呀 xff0c 我是请假君 xff0c 今天又来和大家一起学习数通了 xff0c 今天要分享的知识是RARP的使用 主机只知道自己的硬件地址时 xff0c 可以通过RARP Reverse Address Resolution Pro
  • 5 . 如何用c语言封装寄存器

    前面我们介绍了存储器映射 寄存器和寄存器映射 xff0c 这些都是为使用 C语言封装寄存器做铺垫 我们通过一个实例来对 C 语言封装寄存器进行介绍 实例 xff1a 控制 GPIOC 端口的第 0 管脚输出一个低电平 首先我们需要知道GPI
  • 干货收藏:68道C语言与C++常见面试题

    1 变量的声明和定义有什么区别 变量的定义为变量分配地址和存储空间 变量的声明不分配地址 一个变量可以在多个地方声明 但是只在一个地方定义 加入extern 修饰的是变量的声明 说明此变量将在文件以外或在文件后面部分定义 神级编程网站 堪称
  • 推荐几款好用的手机编程APP!

    各位 很多人现在喜欢用手机写代码 今天小编就带大家盘点几款手机端编程软件 程序员相关的海量资料 点击免费获取 1 C4droid 适用编程语言 C C 适用平台 Android 2 2 软件介绍 付费软件 国内免费 c4droid是款And
  • 精心为学弟学妹整理了60个适合练手的C语言/C++项目,值得收藏!

    前几天写这篇文章 精心为学弟学妹准备的C语言与C 学习路线 书籍 视频推荐和资料 值得收藏 阅读和收藏都挺多 也让我一周涨了3000多粉丝 在这里感谢大家关注支持我 最近很多粉丝朋友私信问一些学习路线的问题以及一些学习资源 一个一个回复有点
  • 如果编程语言是一门武功绝学

    nbsp 学习编程与武功绝学 武侠小说中 各路侠客绿林好汉都是从基本功开始一招一式学起 掌握了足够多的招式后 加之勤学苦练 量变引起质变 会有一天打开任督二脉顿悟出这些招式背后的哲学逻辑 成为一代宗师 在编程的学习过程中 我们何尝不是从一招
  • CSDN粉丝冲3万粉福利放送!C++、Python、数据结构与算法、计算机基础、数据库教程汇总!

    最近有粉丝问我要一些C Python 数据结构与算法 计算机基础 数据库的学习资料 一个一个回复有些慢 索性就写一篇文章吧 声明 此文章中涉及到的内容均来自网络 我看到比较好的才分享给大家 你们可以根据情况选择 程序员必备资源 值得收藏 点
  • C/C++框架和第三方库汇总

    根据读者反馈 xff0c 发现此篇汇总获赞率异常的高 xff0c 为了照顾一下新加入的粉丝 xff0c 故重新发一遍 xff0c 供粉丝查阅温习 值得学习的C语言开源项目 1 Webbench Webbench是一个在linux下使用的非常
  • C/C++动态检测内存错误利器 - ASan

    来自公众号 xff1a 大胖聊编程 作者 xff1a 大胖 ASan xff0c 即Address Sanitizer xff0c 是一个适用于c c 43 43 程序的动态内存错误检测器 xff0c 它由一个编译器检测模块 xff08 L
  • C++之虚函数和虚函数表

    哈喽大家好 最近开始学习计算机基础相关的面试内容 xff0c 比如C 43 43 算法与数据结构 计算机网络 操作系统 设计模式 数据库等 因此把学习时记的笔记分享给大家 xff0c 希望对大家有所帮助 今天分享的是C 43 43 中虚函数
  • 计算机大一新生,想卷却找不到方向,恳请前辈指指路?

    其实 xff0c 大学里面的课程就告诉你应该学什么 xff1f 先推荐三个非常不错的计算机科学学习的 Github 仓库 xff01 希望对大家有帮助 xff01 哭了哭了 xff01 如果我当时上大学的时候有人告诉我这些开源项目就好了 x
  • http cache-control 指令的设置以及意义

    转载地址 https developer mozilla org zh CN docs Web HTTP Headers Cache Control http www cnblogs com yuyii archive 2008 10 16
  • 精心整理的给简历加分的C++项目。值得收藏

    无论做什么项目 xff0c 在写简历时 xff0c 最好要整理出项目中的技术点 xff0c 思考如何跟面试官介绍你的项目 xff0c 要经得起面试官的提问 项目的话 xff0c 可以考虑做下面的这几个 xff1a 神级编程网站 xff0c
  • 77%的本科毕业生起薪超过1万元,程序员的薪资到底有多高?

    都说互联网行业进入了寒冬 xff0c 可实际上 xff0c 程序员的薪资还是非常可观的啊 xff01 最近拉勾招聘数据研究院发布一则报告 2022程序员群体职场洞察报告 针对程序员群体展开调研 xff0c 呈现出当下程序员的职场生存状态 薪
  • C++入坑指南

    如果要入坑C 43 43 xff0c 那么你需要阅读一下这篇文章 本文目录 xff1a 什么是C 43 43 xff1f C 43 43 的历史 xff1f C 43 43 为什么经久不衰 xff1f C 43 43 有什么优势 xff1f
  • 保姆级零基础 C 语言学习路线,万字总结!

    从大学接触 C 语言编程 xff0c 工作之后一直从事互联网 C C 43 43 后台开发工作 xff0c 粗略算下来有 10 多年经验了 xff08 但是年限也并不能代表什么 xff09 xff0c 只能说对 C 语言学习有一些经验可以分
  • SpringBoot整合redis——redisTemplate的使用

    加入redis相关依赖 span class token generics function span class token punctuation lt span dependency span class token punctuat
  • Exception encountered during context initialization - cancelling refresh attempt:

    以个人经验 xff0c 报这个错一般有三个原因 xff1a 原因一 xff1a 配置文件写错了 检查最新写过的xml文件 xff0c 比如mapper xml里面格式 id等是否写对了 原因二 xff1a 依赖冲突 检查最新添加过的依赖包
  • vue前端关于Jquery中的$没定义的问题

    1 在项目中安装jquery npm install jquery save dev 2 在项目根目录下的build webpack base conf js文件中 xff1a 先写以下代码 var webpack 61 require 3

随机推荐