NVIDIA Jetson Xavier CAN 开机启动及应用编程

NVIDIA XAVIER CAN 配置及开机启动

在这里插入图片描述

1、CAN配置

1.1、使用modprobe 工具 加载CAN设备

sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan

1.2、配置CAN参数

//①、关闭CAN
sudo ip link set down can0  
sudo ip link set down can1

//②、设备CAN波特率
sudo ip link set can0 type can bitrate 500000
sudo ip link set can1 type can bitrate 500000

//③、打开CAN
sudo ip link set up can0
sudo ip link set up can1

1.3、使用 ifconfig -a 命令查看CAN驱动是否加载成功

2、CAN开机自启

2.1、编写脚本 enable_CAN.sh

touch enable_CAN.sh  // 创建脚本文件
sudo chmod 777 enable_CAN.sh  //给脚本文件赋权限

2.2、编写脚本

sudo vi enable_CAN.sh
#!/bin/sh

sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan

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

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BgOqvFbp-1667201642664)(E:\形深智能工作资料\工作记录\S32K144学习笔记\Linux\88.png)]

2.3、配置开机启动

①、将enable.sh脚本文件拷贝到/usr/locak/ 目录下

sudo cp enable_CAN.sh /usr/local/

②、配置 service 文件

cd /etc/systemd/system   //进入文件目录下
sudo touch enable_CAN.service  //新建 enable_CAN.service
sudo vi enable_CAN.service     //配置文件如下
[Unit]
Description=Can

[Service]
ExecStart=/usr/local/enable_CAN.sh start

[Install]
WantBy=multi-user.target

③、设置服务

sudo systemctl daemon-reload
sudo systemctl enable enable_CAN.service
sudo systemctl start enable_CAN.service

④、重启XAVIER 后 使用 ifconfig -a 查看 CAN设备是否启动成功

在这里插入图片描述

3、SocketCan应用编程基础知识

3.1、创建socket套接字

CAN总线套接字采用标准的网络套接字操作完成,网络套接字在头文件<sys/socket.h>中有定义。创建CAN套接字方式如下:

int s = -1;

/* 创建套接字 */
s = socket(PF_CAN,SOCK_RAW,CAN_RAW);
if(0 > s)
{
	perror("socket error");
	exit(EXIT_FAILURE);
    
}

3.2、将套接字与CAN设备进行绑定

struct ifreq ifr = {0};
struct sockaddr_can can_addr = {0};
int ret;


strcpy(ifr.ifr_name,"can0");//指定名字
//灵活设置CAN口
sprintf(ifr.ifr_name,"can%d",1);

ioctl(s,SIOCGIFINDEX,&ifr);

can_addr.can_family = AF_CAN;
can_addr.can_ifindex = ifr.ifr_ifindex;

/* 将套接字与 can0 进行绑定 */
ret = bind(s,(struct sockaddr *)&can_addr,sizeof(can_addr));
if(0 > ret)
{
	perror("bind error");
	close(s);
	exit(EXIT_FAILURE);
}

3.3、设置过滤规则

struct can_filter rfilter[2]; // 定义一个can_filter 结构体对象

// 填充过滤规则,只接收ID为(can_id&can_mask)的报文
rfilter[0].can_id = 0x60A;
rfilter[0].can_mask = 0x7FF;
rfilter[1].can_id = 0x60B;
rfilter[1].can_mask = 0x7FF;

// 调用 setsockopt 设置过滤规则
setsockopt(s,SOL_CAN_RAW,CAN_RAW_FILTER,&rfilter,sizeof(rfilter));

如果应用程序功能仅是发送数据,则可省去接收队列,setsockopt()函数的第4个参数设为NULL,第五个参数设置为0:

setsockopt(s,SOL_CAN_RAW,CAN_RAW_FILTER,NULL,0);

3.4、数据发送

CAN总线每一次通信使用struct can_frame 结构体将数据封装成帧,struct can_frame定义如下:

struct can_frame {
 canid_t can_id; /* CAN 标识符 */
 __u8 can_dlc; /* 数据长度(最长为 8 个字节) */
 __u8 __pad; /* padding */
 __u8 __res0; /* reserved / padding */
 __u8 __res1; /* reserved / padding */
 __u8 data[8]; /* 数据 */
};

can_id 为帧的标识符,如果是标准帧,就使用 can_id 的低 11 位;如果为扩展帧,就使用 0~28 位。can_id 的第 29、30、31 位是帧的标志位,用来定义帧的类型,定义如下:

#define CAN_EFF_FLAG 0x80000000U /* 扩展帧的标识 */
#define CAN_RTR_FLAG 0x40000000U /* 远程帧的标识 */
#define CAN_ERR_FLAG 0x20000000U /* 错误帧的标识,用于错误检查 */
/* mask */
#define CAN_SFF_MASK 0x000007FFU /* <can_id & CAN_SFF_MASK>获取标准帧 ID */
#define CAN_EFF_MASK 0x1FFFFFFFU /* <can_id & CAN_EFF_MASK>获取标准帧 ID */
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */

数据发送使用write()函数实现,发送报文ID为0x123,数据为:0xA0、0xB0、0xC0;定义如下:

struct can_frame frame; //定义一个 can_frame 变量
int ret;
frame.can_id = 123;//如果为扩展帧,那么 frame.can_id = CAN_EFF_FLAG | 123;
frame.can_dlc = 3; //数据长度为 3
frame.data[0] = 0xA0; //数据内容为 0xA0
frame.data[1] = 0xB0; //数据内容为 0xB0
frame.data[2] = 0xC0; //数据内容为 0xC0
ret = write(sockfd, &frame, sizeof(frame)); //发送数据
if(sizeof(frame) != ret) //如果 ret 不等于帧长度,就说明发送失败
 perror("write error");

要发送远程帧(帧 ID 为 123),可采用如下方法进行发送:

struct can_frame frame;
frame.can_id = CAN_RTR_FLAG | 123;
write(sockfd, &frame, sizeof(frame));

3.5、数据接收

使用read()函数实现:

struct can_frame frame;
int ret = read(sockfd, &frame, sizeof(frame));

4、NVIDIA Jetson Xavier CAN 发送数据

4.1、can_send.cCAN发送数据具体实现如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/fs.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdbool.h>

int s;

int main(int argc, char *argv[])
{
    int cannum = atoi(argv[1]);
    char buf[60];
	sprintf(buf,"ifconfig can%d down",cannum);// 关闭CAN
	system(buf);
	sprintf(buf,"ip link set can%d type can bitrate 500000",cannum);// 设置CAN 波特率500000
	system(buf);
	sprintf(buf,"ifconfig can%d up",cannum);//开启CAN
	system(buf);
    
    struct can_frame frame1[2] = {{0}};
	struct sockaddr_can addr;
	struct ifreq ifr;

    s = socket(PF_CAN, SOCK_RAW, CAN_RAW); //创建套接字
    if(0 > s)
    {
        perror("socket error");
        exit(EXIT_FAILURE);
    }

    sprintf(ifr.ifr_name, "can%d",cannum);
    ioctl(s, SIOCGIFINDEX, &ifr); //指定can设备--can0 can1...
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;

    int ret = bind(s, (struct sockaddr *)&addr, sizeof(addr)); //将套接字与can%d 绑定
    if(0 > ret)
    {
        perror("bind error");
        close(s);
        exit(EXIT_FAILURE);
    }

    //待发送的数据
    struct can_frame frame = {0};
    frame.data[0] = 0xA0;
    frame.data[1] = 0xB0;
    frame.data[2] = 0xC0;
    frame.data[3] = 0xD0;
    frame.data[4] = 0xE0;
    frame.data[5] = 0xF0;
    frame.can_dlc = 6;  // 数据字节数
    frame.can_id = 0x123;  // 报文ID

    //设置过滤规则: 仅发送数据 不接收报文*/
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &frame, sizeof(frame)); 

    for(;;)
    {
        //发送数据
        ret = write(s,&frame,sizeof(frame));
        if(sizeof(frame) != ret) //如果ret不等于报文长度 说明发送失败
        {
            perror("write error");
            goto out;
        }

        sleep(1); //发送时延 1s发一次
    }

out:
    close(s);
    exit(EXIT_SUCCESS);

    return 0;
}

4.2、使用aarch64-linux-gnu-gcc 交叉编译器编译程序

aarch64-linux-gnu-gcc -o can_send can_send.c

如果没有ARM 交叉编译环境,则使用如下命令安装:

sudo apt-get install gcc-9-aarch64-linux-gnu
sudo apt-get install gcc-aarch64-linux-gnu

查看aarch64-linux-gnu-gcc版本号

aarch64-linux-gnu-gcc -v

4.3、将生成的可执行文件can_send 拷贝到/home/root/目录下;使用如下命令运行can_send`

./can_updata 1 // 1是对应的CAN 设备号 Xavier 可以引出两路CAN

4.4、把CANCAN_HMPSOC 5EV CAN4_HCANCAN_LMPSOC 5EV CAN4_L

4.5、设置CAN卡参数,打开对应通道,启用终端电阻;

在这里插入图片描述

CAN卡会收到Xavier 发送过来的如下报文

在这里插入图片描述

4、NVIDIA Jetson Xavier CAN 接收数据

4.1、can_read.cCAN接收数据源码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>


int main(int argc, char *argv[])
{
    int cannum = atoi(argv[1]);
    char buf[60];
	sprintf(buf,"ifconfig can%d down",cannum);// 关闭CAN
	system(buf);
	sprintf(buf,"ip link set can%d type can bitrate 500000",cannum);// 设置CAN 波特率500000
	system(buf);
	sprintf(buf,"ifconfig can%d up",cannum);//开启CAN
	system(buf);
    
    struct ifreq ifr = {0};
    struct sockaddr_can can_addr = {0};
    struct can_frame frame = {0};
    int sockfd = -1;
    int i;
    int ret;

    sockfd = socket(PF_CAN,SOCK_RAW,CAN_RAW);
    if(0 > sockfd)
    {
        perror("socket error");
        exit(EXIT_FAILURE);
    }

    sprintf(ifr.ifr_name, "can%d",cannum);
    //strcpy(ifr.ifr_name, "can4");
    ioctl(sockfd, SIOCGIFINDEX, &ifr); //指定can设备--can0 can1...
    can_addr.can_family = AF_CAN;
    can_addr.can_ifindex = ifr.ifr_ifindex;

    ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr)); //将套接字与can%d 绑定
    if(0 > ret)
    {
        perror("bind error");
        close(sockfd);
        exit(EXIT_FAILURE);
    }


    for(;;)
    {
        if(0 > read(sockfd,&frame,sizeof(struct can_frame)))
        {
            perror("read error");
            break;
        }

        if(frame.can_id & CAN_ERR_FLAG)
        {
            printf("Error frame!\n");
            break;
        }


        if(frame.can_id & CAN_EFF_FLAG)
        {
            printf("扩展帧 <0x%08x>",frame.can_id & CAN_EFF_MASK);
        }
        else
        {
            printf("标准帧 <0x%03x>",frame.can_id & CAN_SFF_MASK);
        }

        if(frame.can_id & CAN_RTR_FLAG)
        {
            printf("remote request\n");
            continue;
        }


        printf("[%d]",frame.can_dlc);

        for(int i = 0; i < frame.can_dlc; i++)
        {
            printf("%02x",frame.data[i]);
        }
        printf("\n");
        
    }
    
    close(sockfd);
    exit(EXIT_SUCCESS);

}

使用aarch64-linux-gnu-gcc 交叉编译器编译程序

aarch64-linux-gnu-gcc -o can_read can_read.c

将生成的可执行文件can_read 拷贝到/home/root/目录下;使用如下命令运行can_read

Welcome to follow my weixingongzhonghao "Kevin的学习站"

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kevin的学习站

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值