7. CAN总线

CAN总线协议(Controller Area Network), 控制器局域网总线,是德国BOSCH(博世)公司研发的一种串行通讯协议总线, 它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。

支持CAN总线的鲁班猫板卡如下:

  • LubanCat-1HS

  • LubanCat-2、LubanCat-2(V1-V2)

  • LubanCat-2N、LubanCat-2N-V2

  • LubanCat-2IO

注意

野火2024.01.25修复can/canfd概率扩展帧变成标准帧以及填充位错误的问题,如果是旧镜像使用can/canfd请在线更新内核或者安装以下内核deb,或者刷比此日期更新的镜像。

1
2
3
#在线更新内核
sudo apt update
sudo apt install linux-headers-4.19.232 linux-image-4.19.232

离线更新内核deb包:

将以上两个deb包传到板卡,使用命令 sudo dpkg -i linux*.deb 进行安装。

在线或者离线选其一即可。

7.1. CAN硬件连接

7.1.1. 板卡款

支持的板卡:

  • LubanCat-2、LubanCat-2(V1-V2)

  • LubanCat-2N、LubanCat-2N-V2

板卡款从40pin排针中引出CAN接口,查看 40pin引脚对照图 章节, 确认CAN具体的引脚。

注意

由于板卡款的CAN信号是从主控内部CAN控制器直接引出的信号,如果要外接CAN设备还需要先连接CAN收发器模块。

以板卡连接CAN分析仪为例,其中:

板卡连接CAN分析仪接线如下:

1
2
3
4
5
6
板卡         对接        CAN收发器   CAN收发器     对接    USB CAN分析仪
CAN_TX      ------        CAN_TX      H         ------        H
CAN_RX      ------        CAN_RX      L         ------        L
5V          ------           5V
GND         ------           GND
3.3V        ------           EN

提示

如果是板卡自收发测试可不连接CAN收发器模块。

板卡自收发测试接线如下:

1
2
3
板卡         对接        板卡
CAN_TX      ------      CAN_TX
CAN_RX      ------      CAN_RX

7.1.2. 广告机款

支持的板卡:

  • LubanCat-1HS

广告机款底板已经板载CAN收发器,无需再接CAN收发器模块,板卡自收发测试以及和CAN设备通信接线如下:

1
2
3
4
5
6
7
8
9
#板卡自收发测试
板卡         对接        板卡
CAN0_H      ------      CAN1_H
CAN0_L      ------      CAN1_L

#板卡接CAN设备
板卡         对接        设备
CANx_H      ------       H
CANx_L      ------       L

LubanCat-1HS对应的接口示意图如下:

未找到图片

7.1.3. 核心板底板款

支持的板卡:

  • LubanCat-2IO

核心板底板款底板已经板载CAN收发器,无需再接CAN收发器模块,板卡自收发测试以及和CAN设备通信接线如下:

1
2
3
4
5
6
7
8
9
#板卡自收发测试
板卡         对接        板卡
CAN0_H      ------      CAN1_H
CAN0_L      ------      CAN1_L

#板卡接CAN设备
板卡         对接        设备
CANx_H      ------       H
CANx_L      ------       L

LubanCat-2IO对应的接口示意图如下:

未找到图片

7.2. CAN

7.2.1. can配置

  • 开启和关闭can fd都需要重启才能生效

  1. 修改设备树插件上的时钟频率, kernel/arch/arm64/boot/dts/rockchip/overlay/rk3568-lubancat-canX-mY-overlay.dts (X,Y是各自的数字)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/dts-v1/;
/plugin/;

#include <dt-bindings/clock/rk3568-cru.h>

/ {
    compatible = "rockchip,rk3568";

    fragment@0 {
        target = <&can1>;

        __overlay__ {
            status = "okay";
            compatible = "rockchip,rk3568-can-2.0";
            assigned-clocks = <&cru CLK_CAN1>;
            assigned-clock-rates = <200000000>;
            pinctrl-names = "default";
            pinctrl-0 = <&can1m0_pins>;
        };
    };
};
  • assigned-clock-rates时钟频率可以修改,如果CAN的比特率1M建议修改CAN时钟到300M,信号更稳定。低于1M比特率的,时钟设置200M就可以,默认使用的是200M

修改设备树插件及替换请参考: 设备树插件

  1. 开启设备树插件(这里以打开CAN1为例)

1
2
#修改配置文件
vi /boot/uEnv/uEnv.txt
  • #dtoverlay=/dtb/overlay/rk3568-lubancat-can1-m1-overlay.dtbo 前面的#删除,如下图

未找到图片

注意

can1和canfd1不能同时开启

  1. 关闭设备树插件(这里以打开CAN1为例)

  • dtoverlay=/dtb/overlay/rk3568-lubancat-can1-m1-overlay.dtbo 前面添加#,如下图

未找到图片

7.2.2. can通信测试

安装测试工具

1
2
sudo apt update
sudo apt install  can-utils

通信测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
查询当前网络设备:
ifconfig -a

CAN启动:
    关闭CAN:
    ip link set can0 down

    设置比特率500KHz:
    ip link set can0 type can bitrate 500000

    打印can0信息:
    ip -details link show can0

    启动CAN:
    ip link set can0 up

CAN发送:
    发送(标准帧,数据帧,ID:123,date:DEADBEEF):
    cansend can0 123#DEADBEEF

    发送(标准帧,远程帧,ID:123):
    cansend can0 123#R

    发送(扩展帧,数据帧,ID:00000123,date:DEADBEEF):
    cansend can0 00000123#12345678

    发送(扩展帧,远程帧,ID:00000123):
    cansend can0 00000123#R

CAN接收:
    开启打印,等待接收:
    candump can0

7.2.3. 更多指令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
关闭can设备
ip link set canX down

开启can设备
ip link set canX up

显示can设备详细信息
ip -details link show canX

接收can总线发来数据
candump canX

关闭can设备,以便配置
ifconfig canX down

设置can波特率
ip link set canX up type can bitrate 250000

发送数据
cansend canX --identifier=ID+数据

使用滤波器接收ID匹配的数据
candump canX --filter=ID:mask

7.2.4. 简单的自收发脚本

将can1和can2对接起来,配置好波特率,然后执行以下脚本,收发日志保存在/home/cat/log.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash

#监控can0数据
candump can0 >> /home/cat/log.txt &

counter=0
while true; do
    #can0发送can0 123#00000000~123#99999999数据
    data=$(printf "%08d" $counter)
    command="cansend can0 123#$data"
    echo $command
    $command

    #can1发送can0 321#00000000~321#99999999数据
    command2="cansend can1 321#$data"
    echo $command2
    $command2

    if [ $counter -eq 99999999 ]; then
        counter=0
    else
        counter=$((counter+1))
    fi
    sleep 0.01
done

7.2.5. C程序测试

代码较长复制粘贴容易乱序,可以下载我们提供的源码 can_send.c

以下使用system设置波特率,可自行修改,for循环中的延时影响帧率,如果需要更快速率可减小延时。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>

int main(int argc, char *argv[])
{
    struct ifreq ifr = {0};
    struct sockaddr_can can_addr = {0};
    struct can_frame frame = {0};
    unsigned char buffer[4] = {0};
    int sockfd = -1;
    unsigned int cnt = 0;
    int ret;

    // 设置CAN波特率为500000
    system("ip link set can0 down");
    system("ip link set can0 type can bitrate 500000");
    system("ip link set can0 up");

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

    /* 指定 can0 设备 */
    strcpy(ifr.ifr_name, "can0");
    ioctl(sockfd, SIOCGIFINDEX, &ifr);
    can_addr.can_family = AF_CAN;
    can_addr.can_ifindex = ifr.ifr_ifindex;

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

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

    memcpy(frame.data, buffer, sizeof(buffer));
    frame.can_dlc = sizeof(buffer);
    frame.can_id = 0x123;

    for (;;) {
        frame.data[0] = (cnt >> 24) & 0xff;
        frame.data[1] = (cnt >> 16) & 0xff;
        frame.data[2] = (cnt >> 8) & 0xff;
        frame.data[3] = cnt & 0xff;

        cnt++;
        ret = write(sockfd, &frame, sizeof(frame));
        if (sizeof(frame) != ret) {
            perror("write error");
            break;
        }
        usleep(10 * 1000);
    }

    close(sockfd);
    exit(EXIT_SUCCESS);
}

编译并运行:

1
2
3
4
5
#编译程序
gcc can_send.c -o can_send

#运行
sudo ./can_send

测试效果如下,大概每秒发送100帧数据,数据ID号为0x0123,数据每帧递增。

../../_images/can_0.jpg

7.3. CAN FD

7.3.1. can fd配置

  • 开启和关闭can fd都需要重启才能生效

  1. 修改设备树插件上的时钟频率, kernel/arch/arm64/boot/dts/rockchip/overlay/rk3568-lubancat-canfdX-mY-overlay.dts (X,Y是各自的数字)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/dts-v1/;
/plugin/;

#include <dt-bindings/clock/rk3568-cru.h>

/ {
    compatible = "rockchip,rk3568";

    fragment@0 {
        target = <&can1>;

        __overlay__ {
            status = "okay";
            compatible = "rockchip,canfd-1.0";
            pinctrl-names = "default";
            assigned-clocks = <&cru CLK_CAN1>;
            assigned-clock-rates = <100000000>;
            pinctrl-0 = <&can1m0_pins>;
        };
    };
};
  • assigned-clock-rates时钟频率可以修改,如果CAN的比特率低于等于3M建议修改CAN时钟到100M,信号更稳定。高于3M比特率的,时钟设置200M就可以,默认为100M

修改设备树插件及替换请参考: 设备树插件

  1. 开启设备树插件(这里以打开CAN1 FD为例)

1
2
#修改配置文件
vi /boot/uEnv/uEnv.txt
  • #dtoverlay=/dtb/overlay/rk3568-lubancat-canfd1-m1-overlay.dtbo 前面的#删除,如下图

未找到图片

注意

can1和canfd1不能同时开启

  1. 关闭设备树插件(这里以打开CANFD1为例)

  • dtoverlay=/dtb/overlay/rk3568-lubancat-canfd1-m1-overlay.dtbo 前面添加#,如下图

未找到图片

7.3.2. can fd通信测试

安装测试工具

1
2
sudo apt update
sudo apt install  can-utils

通信测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
查询当前网络设备:
ifconfig -a

CAN FD启动:
    关闭CAN:
    ip link set can0 down

    设置仲裁段1M波特率,数据段3M波特率:
    ip link set can0 type can bitrate 1000000 dbitrate 3000000 fd on

    打印can0信息:
    ip -details link show can0

    启动CAN:
    ip link set can0 up

CAN FD发送:
    发送(标准帧,数据帧,ID:123,date:DEADBEEF):
    cansend can0 123##1DEADBEEF

    发送(扩展帧,数据帧,ID:00000123,date:DEADBEEF):
    cansend can0 00000123##1DEADBEEF


CAN接收:
    开启打印,等待接收:
    candump can0

7.3.3. 更多指令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
关闭can设备
ip link set canX down

开启can设备
ip link set canX up

显示can设备详细信息
ip -details link show canX

接收can总线发来数据
candump canX

关闭can设备,以便配置
ifconfig canX down

设置仲裁段1M波特率,数据段3M波特率:
ip link set can0 type can bitrate 1000000 dbitrate 3000000 fd on

发送数据
cansend canX --identifier=ID+数据

使用滤波器接收ID匹配的数据
candump canX --filter=ID:mask

7.4. 修改CAN缓冲区

执行下面命令可以查看CAN缓冲区大小:

1
cat  /sys/class/net/can0/tx_queue_len

默认缓冲区大小只有10,每秒最多发4000帧,如果帧率再高缓冲区将没有多余的空间,提示No buffer space available

修改缓冲区大小可以增加发送速率上限,执行以下命令:

1
echo 4096 > /sys/class/net/can0/tx_queue_len

效果如下:

../../_images/can_1.jpg