9. CAN总线#
CAN总线协议(Controller Area Network), 控制器局域网总线,是德国BOSCH(博世)公司研发的一种串行通讯协议总线, 它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。
9.1. CAN硬件连接#
鲁班猫3板卡40pin上的can为芯片原生接口,没有通过can收发器,使用的时候需要外接can收发器模块。
CAN收发器购买参考链接: 野火CAN收发器模块
核心板加底板形式的板卡,比如鲁班猫3IO,在底板上已经有CAN收发器,可以直接使用。
一体板款板卡和外部设备CAN接线如下:
1板卡 对接 CAN收发器 CAN收发器 对接 USB CAN分析仪
2CAN_TX ------ CAN_TX H ------ H
3CAN_RX ------ CAN_RX L ------ L
45V ------ 5V
5GND ------ GND
63.3V ------ EN
核心板加底板款板卡和外部设备CAN接线如下:
1板卡 连接 USB CAN分析仪
2CAN_L ------- CAN_L
3CAN_H ------- CAN_H
9.2. CAN#
9.2.1. 使能CAN接口#
开启和关闭can都需要重启才能生效
开启设备树插件(这里以打开CAN0为例)
1#修改配置文件
2vi /boot/uEnv/uEnv.txt
把
#dtoverlay=/dtb/overlay/rk3576-lubancat-can0-m2-overlay.dtbo前面的#删除,如下图
关闭设备树插件(这里以打开CAN0为例)
在
dtoverlay=/dtb/overlay/rk3588-lubancat-can1-m1-overlay.dtbo前面添加#,如下图
9.2.2. CAN通信测试#
默认配置为CANFD,如果要使用CAN,需要进行切换:
1#设置can0为500Kbps的比特率,并关闭CAN FD模式
2sudo ip link set can0 type can bitrate 500000 fd off
CAN常用指令如下:
1查询当前网络设备:
2ifconfig -a
3
4CAN启动:
5 关闭CAN:
6 ip link set can0 down
7
8 设置比特率500KHz:
9 ip link set can0 type can bitrate 500000 fd off
10
11 打印can0信息:
12 ip -details link show can0
13
14 启动CAN:
15 ip link set can0 up
16
17CAN发送:
18 发送(标准帧,数据帧,ID:123,date:DEADBEEF):
19 cansend can0 123#DEADBEEF
20
21 发送(标准帧,远程帧,ID:123):
22 cansend can0 123#R
23
24 发送(扩展帧,数据帧,ID:00000123,date:DEADBEEF):
25 cansend can0 00000123#12345678
26
27 发送(扩展帧,远程帧,ID:00000123):
28 cansend can0 00000123#R
29
30CAN接收:
31 开启打印,等待接收:
32 candump can0
9.2.3. 更多指令#
1关闭can设备
2ip link set canX down
3
4开启can设备
5ip link set canX up
6
7显示can设备详细信息
8ip -details link show canX
9
10接收can总线发来数据
11candump canX
12
13关闭can设备,以便配置
14ifconfig canX down
15
16设置can波特率
17ip link set canX up type can bitrate 250000 fd off
18
19发送数据
20cansend canX --identifier=ID+数据
21
22使用滤波器接收ID匹配的数据
23candump canX --filter=ID:mask
9.3. CANFD#
9.3.1. CANFD通信测试#
1查询当前网络设备:
2ifconfig -a
3
4CAN FD启动:
5 关闭CAN:
6 ip link set can0 down
7
8 设置仲裁段1M波特率,数据段3M波特率:
9 ip link set can0 type can bitrate 1000000 dbitrate 3000000 fd on
10
11 打印can0信息:
12 ip -details link show can0
13
14 启动CAN:
15 ip link set can0 up
16
17 CAN FD发送:
18 发送(标准帧,数据帧,ID:123,date:DEADBEEF):
19 cansend can0 123##1DEADBEEF
20
21 CAN FD接收:
22 开启打印,等待接收:
23 candump can0
9.3.2. 更多指令#
1关闭can设备
2ip link set canX down
3
4开启can设备
5ip link set canX up
6
7显示can设备详细信息
8ip -details link show canX
9
10接收can总线发来数据
11candump canX
12
13关闭can设备,以便配置
14ifconfig canX down
15
16设置仲裁段1M波特率,数据段3M波特率:
17ip link set can0 type can bitrate 1000000 dbitrate 3000000 fd on
18
19发送数据
20cansend canX --identifier=ID+数据
21
22使用滤波器接收ID匹配的数据
23candump canX --filter=ID:mask
9.4. CAN时钟频率修改#
修改设备树插件上的时钟频率,
kernel/arch/arm64/boot/dts/rockchip/overlay/rk3576-lubancat-canX-mY-overlay.dts(X,Y是各自的数字)
1/dts-v1/;
2/plugin/;
3
4#include <dt-bindings/clock/rk3588-cru.h>
5
6/ {
7 fragment@0 {
8 target = <&can0>;
9
10 __overlay__ {
11 status = "okay";
12 assigned-clocks = <&cru CLK_CAN0>;
13 assigned-clock-rates = <100000000>;
14 pinctrl-names = "default";
15 pinctrl-0 = <&can0m2_pins>;
16 };
17 };
18};
assigned-clock-rates可以修改。如果小于等于3Mbps,建议将can clock修改为100M,这样信号更稳定。如果高于3Mbps,则可以将时钟设置为200M。
9.5. 简单的自收发脚本#
将can1和can2对接起来,然后执行以下脚本,收发日志保存在/home/cat/log_canx.txt
1#!/bin/bash
2
3ip link set can0 down
4ip link set can1 down
5ip link set can0 type can bitrate 1000000 dbitrate 3000000 fd on
6ip link set can1 type can bitrate 1000000 dbitrate 3000000 fd on
7ip link set can0 up
8ip link set can1 up
9
10#监控can数据
11candump can0 >> /home/cat/log_can0.txt &
12candump can1 >> /home/cat/log_can1.txt &
13
14counter=0
15while true; do
16 #can0发送can0 123#00000000~123#99999999数据
17 data=$(printf "%08d" $counter)
18 command="cansend can0 123##0$data"
19 echo $command
20 $command
21
22 #can1发送can0 321#00000000~321#99999999数据
23 command2="cansend can1 321##0$data"
24 echo $command2
25 $command2
26
27 if [ $counter -eq 99999999 ]; then
28 counter=0
29 else
30 counter=$((counter+1))
31 fi
32 sleep 0.01
33done
9.6. 与CAN分析仪通信测试#
以LubanCat-RK3576板卡的CAN0为例,根据前面介绍的方法将CAN0接口使能,然后连接CAN收发器和CAN分析仪。
CAN收发器模块以 野火小智【CAN收发器】模块 为例,
USB CAN分析仪使用: CAN分析仪
9.6.1. 硬件接线#
1 板卡 对接 CAN收发器 CAN收发器 对接 USB CAN分析仪
2CAN0_TX(11) ------ CAN_TX H ------ H
3CAN0_RX(7) ------ CAN_RX L ------ L
4 5V ------ 5V
5 GND ------ GND
6 3.3V ------ EN
9.6.2. shell命令测试#
配置can接口:
1ip link set can0 down
2ip link set can0 type can bitrate 500000 fd off
3ip link set can0 up
发送消息:
1#发送(标准帧,数据帧,ID:123,date:DEADBEEF)
2cansend can0 123#DEADBEEF
接收信息:
1#开启打印,等待接收
2candump can0
测试效果如图:
9.6.3. C程序测试#
1quick_start/can/can_send.c
代码较长复制粘贴容易乱序,可以下载我们提供的源码 can_send.c
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <sys/ioctl.h>
6#include <sys/socket.h>
7#include <linux/can.h>
8#include <linux/can/raw.h>
9#include <net/if.h>
10
11int main(int argc, char *argv[])
12{
13 struct ifreq ifr = {0};
14 struct sockaddr_can can_addr = {0};
15 struct can_frame frame = {0};
16 unsigned char buffer[4] = {0};
17 int sockfd = -1;
18 unsigned int cnt = 0;
19 int ret;
20
21 // 设置CAN波特率为500000
22 system("ip link set can0 down");
23 system("ip link set can0 type can bitrate 500000 fd off");
24 system("ip link set can0 up");
25
26 sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
27 if(0 > sockfd) {
28 perror("socket error");
29 exit(EXIT_FAILURE);
30 }
31
32 /* 指定 can0 设备 */
33 strcpy(ifr.ifr_name, "can0");
34 ioctl(sockfd, SIOCGIFINDEX, &ifr);
35 can_addr.can_family = AF_CAN;
36 can_addr.can_ifindex = ifr.ifr_ifindex;
37
38 /* 将 can0 与套接字进行绑定 */
39 ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
40 if (0 > ret) {
41 perror("bind error");
42 close(sockfd);
43 exit(EXIT_FAILURE);
44 }
45
46 setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
47
48 memcpy(frame.data, buffer, sizeof(buffer));
49 frame.can_dlc = sizeof(buffer);
50 frame.can_id = 0x123;
51
52 for (;;) {
53 frame.data[0] = (cnt >> 24) & 0xff;
54 frame.data[1] = (cnt >> 16) & 0xff;
55 frame.data[2] = (cnt >> 8) & 0xff;
56 frame.data[3] = cnt & 0xff;
57
58 cnt++;
59 ret = write(sockfd, &frame, sizeof(frame));
60 if (sizeof(frame) != ret) {
61 perror("write error");
62 break;
63 }
64 usleep(10 * 1000);
65 }
66
67 close(sockfd);
68 exit(EXIT_SUCCESS);
69}
编译并运行:
1#编译程序
2gcc can_send.c -o can_send
3
4#运行
5sudo ./can_send
测试效果如下,大概每秒发送100帧数据,数据ID号为0x0123,数据每帧递增。