canfd
CAN FD (Controller Area Network Flexible Data-rate) 是传统 CAN (Controller Area Network) 的升级版本,旨在满足现代汽车电子系统和工业自动化中对更高数据速率和更大数据负载的需求。以下是对 CAN FD 的详细介绍:
CAN 和 CAN FD 的背景
CAN 是由 Robert Bosch GmbH 在 1980 年代开发的串行通信协议,用于车辆内部各控制器(ECU)之间的通信。由于其鲁棒性、实时性和错误检测能力,CAN 被广泛应用于汽车和工业自动化领域。然而,随着技术进步和系统复杂性的增加,传统 CAN 的数据速率(最高 1 Mbps)和数据帧长度(最多 8 字节)已不能满足新的需求。因此,CAN FD 应运而生。
CAN FD 的特点
-
更高的数据速率
- CAN FD 允许在数据阶段使用高达 8 Mbps 的数据速率,而传统 CAN 的最大数据速率为 1 Mbps。
-
更大的数据帧
- CAN FD 允许数据帧长度扩展到 64 字节,而传统 CAN 仅支持最多 8 字节的数据负载。
-
灵活的数据速率
- 在同一帧中,CAN FD 可以在仲裁阶段使用较低的速率,以确保向下兼容传统 CAN 节点,然后在数据阶段切换到更高的速率。
CAN FD 的帧格式
CAN FD 帧格式与传统 CAN 帧格式类似,但有一些关键区别:
-
控制字段
- 增加了一个 FDF (Flexible Data-rate Format) 位,用于指示这是一个 CAN FD 帧。
- 增加了一个 BRS (Bit Rate Switch) 位,用于指示在数据阶段切换到更高的数据速率。
- 取消了传统 CAN 中的 r0 保留位。
-
数据字段
- 数据字段长度可以是 0 到 64 字节,而传统 CAN 是 0 到 8 字节。
-
CRC 校验
- 增加了一个 CRC 部分,以确保数据完整性。CAN FD 使用更长的 CRC 码(17 或 21 位),以适应更大的数据帧。
CAN FD 的优势
-
更高的数据吞吐量
- 通过提高数据速率和数据帧长度,CAN FD 提供了更高的数据传输效率和吞吐量。
-
兼容性
- CAN FD 节点可以与传统 CAN 节点共存于同一总线系统,确保向下兼容性。
-
鲁棒性
- 保留了 CAN 的所有错误检测和纠正机制,确保通信的可靠性。
-
成本效益
- 与其他高带宽总线系统相比,CAN FD 提供了一种成本效益更高的解决方案,适用于现有 CAN 总线基础设施的升级。
CAN FD 的应用
-
汽车电子
- 由于汽车电子系统变得越来越复杂,CAN FD 能够提供更高的数据速率和更大的数据帧,满足现代汽车对数据通信的需求。
-
工业自动化
- 在工业自动化领域,CAN FD 提供了更高效的数据通信,适用于机器人、自动化设备和传感器网络。
-
其他嵌入式系统
- 适用于任何需要高数据速率和可靠通信的嵌入式系统,如医疗设备、航天器和消费电子。
CAN FD 示例
下面是一个简化的 CAN FD 帧的示例,展示了它与传统 CAN 帧的不同之处:
+--------------------------------------------------------------------+
| 仲裁阶段 (Arbitration Phase) | 控制字段 (Control Field) |
+-------------------------------+------------------------------------+
| 标识符 | FDF | BRS | EDL | 数据长度代码 (DLC) | 数据字段 (0-64 字节) |
+--------+-----+-----+-----+--------------------+--------------------+
| 11/29 | 1 | 1 | 1 | 15 | 0 到 64 字节的有效数据 |
+--------+-----+-----+-----+--------------------+--------------------+
总结
CAN FD 是传统 CAN 的自然进化,它通过提高数据速率和扩展数据帧长度,满足了现代汽车和工业自动化系统的需求。它的向下兼容性、鲁棒性和成本效益使其成为升级现有 CAN 网络的理想选择。
vcanfd
虚拟 CAN FD (vCAN FD) 是一种在没有物理 CAN 硬件的情况下模拟 CAN FD 网络的工具。这对于开发和测试 CAN FD 应用程序非常有用,因为它允许开发者在虚拟环境中验证代码的功能和行为。虚拟 CAN FD 通常由软件实现,可以在 PC 上运行,为开发、调试和测试提供便利。
虚拟 CAN FD 的优势
- 方便开发和测试:在没有物理 CAN 硬件的情况下,可以进行开发和测试,节省成本。
- 提高调试效率:开发人员可以在虚拟环境中快速迭代和调试代码。
- 支持自动化测试:可以轻松集成到自动化测试框架中,以实现大规模的回归测试。
在 Linux 上使用 SocketCAN 实现虚拟 CAN FD
SocketCAN 是 Linux 内核中的 CAN 总线支持,通过 vcan
驱动程序,可以实现虚拟 CAN 网络。下面介绍如何在 Linux 上配置和使用虚拟 CAN FD。
安装必要的软件包
确保系统安装了必要的软件包,例如 can-utils
。
sudo apt-get update
sudo apt-get install can-utils
加载虚拟 CAN 模块
加载 vcan
模块,创建虚拟 CAN 网络接口。
sudo modprobe vcan
创建虚拟 CAN FD 接口
使用 ip
命令创建并配置虚拟 CAN FD 接口。
sudo ip link add dev vcan0 type vcan
sudo ip link set vcan0 mtu 72 # 设置 MTU 以支持 CAN FD
sudo ip link set up vcan0
验证虚拟 CAN FD 接口
使用 ip
命令验证接口是否正确创建。
ip link show vcan0
输出示例:
4: vcan0: <NOARP,UP,LOWER_UP> mtu 72 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000link/can
发送和接收 CAN FD 消息
可以使用 cangen
和 candump
工具发送和接收 CAN FD 消息。
- 发送 CAN FD 消息
cangen vcan0 -g 10 -I 123 -D i -n 5
此命令每隔 10 毫秒在 vcan0
接口上发送 5 条带有 ID 123
的随机数据帧。
cangen
是 can-utils
工具包中的一个工具,用于在 CAN 网络上生成随机的 CAN 帧。下面解释一下 cangen vcan0 -g 10 -I 123 -D i -n 5
命令中每个参数的含义:
-
vcan0
:指定要在其上发送 CAN 帧的网络接口。在这个例子中,vcan0
是一个虚拟 CAN 接口。 -
-g 10
:设置生成帧之间的间隔时间。10
表示间隔时间为 10 毫秒。这意味着每发送一帧后,会等待 10 毫秒再发送下一帧。 -
-I 123
:设置 CAN 帧的标识符(ID)。123
是十六进制的 CAN ID。在这个例子中,CAN 帧的标识符被设置为0x123
。 -
-D i
:设置数据帧的数据部分。 -
i
表示数据字段将包含随机字节。每个生成的帧将具有随机内容。 -
-n 5
:设置要生成和发送的帧数。5
表示将生成和发送 5 个 CAN 帧。详细解释
-
接口 (vcan0):指定命令运行在哪个 CAN 接口上。在这里,使用的是虚拟 CAN 接口
vcan0
。你可以替换成你实际使用的物理 CAN 接口名称。 -
间隔 (-g 10):指定两帧之间的生成间隔时间。单位是毫秒。这在测试 CAN 总线负载时很有用,因为它允许你控制帧生成的速率。
-
标识符 (-I 123):设置帧的 CAN ID。这个 ID 用于在 CAN 网络中识别消息的发送者和消息的类型。CAN ID 可以是标准的(11 位)或扩展的(29 位),取决于具体应用。
-
数据 (-D i):数据选项用于指定帧的数据字段。
i
表示数据字段将被随机填充。如果没有指定数据,默认情况下会生成空帧。这个选项允许你生成各种类型的数据内容以测试不同的场景。 -
帧数 (-n 5):指定要生成的帧数。在这个例子中,命令将生成 5 个帧。你可以根据需要调整这个数字以生成更多或更少的帧。
示例
cangen vcan0 -g 10 -I 123 -D i -n 5
此命令将:
- 在虚拟 CAN 接口
vcan0
上发送帧。 - 每隔 10 毫秒发送一帧。
- 每个帧的 CAN ID 为
0x123
。 - 每个帧的数据字段包含随机字节。
- 总共发送 5 个帧。
补充
你可以使用其他参数来自定义生成的帧,例如指定帧的数据长度、使用扩展 ID 等。详细的参数说明可以参考
cangen
的手册页:man cangen
或使用
cangen --help
查看帮助信息。以下是
cangen
工具的使用说明和示例翻译:cangen
: 生成 CAN 帧用法
cangen [选项] <CAN 接口>
选项
-g <ms>
:帧间隔时间(以毫秒为单位,默认:200 毫秒)-e
:生成扩展帧格式(EFF)的 CAN 帧-f
:生成 CAN FD 帧-R
:发送 RTR 帧-m
:混合生成-e
、-f
、-R
帧-I <模式>
:CAN ID 生成模式 - 见下文-L <模式>
:CAN 数据长度码(dlc)生成模式 - 见下文-D <模式>
:CAN 数据(有效载荷)生成模式 - 见下文-p <超时>
:在-ENOBUFS
上轮询以<timeout>
毫秒间隔发送帧-n <数量>
:在发送<count>
个 CAN 帧后终止 - 默认无限-i
:忽略write()
系统调用中的-ENOBUFS
返回值-x
:禁用生成的 CAN 帧的本地环回-v
:增加打印已发送 CAN 帧的详细程度
生成模式
'r'
:随机值(默认)'i'
:递增值<hexvalue>
:使用<hexvalue>
固定值
在递增 CAN 数据时,数据长度码最小值设为 1。CAN ID 和数据内容使用十六进制值。
示例
-
cangen vcan0 -g 4 -I 42A -L 1 -D i -v -v
(固定 CAN ID 和长度,递增数据) -
cangen vcan0 -e -L i -v -v -v
(生成 EFF 帧,递增长度) -
cangen vcan0 -D 11223344DEADBEEF -L 8
(固定 CAN 数据有效载荷和长度) -
cangen vcan0 -g 0 -i -x
(忽略-ENOBUFS
的全负载测试) -
cangen vcan0 -g 0 -p 10 -x
(具有轮询功能的全负载测试,10 毫秒超时) -
cangen vcan0
(我最喜欢的默认设置 😃)
-
- 接收 CAN FD 消息
candump vcan0
此命令在 vcan0
接口上接收并打印 CAN FD 消息。
发送和接收
发送
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>#define CAN_INTERFACE "vcan0"void send_canfd_frames() {int s;struct sockaddr_can addr;struct canfd_frame frame;struct ifreq ifr;int enable_canfd = 1;s = socket(PF_CAN, SOCK_RAW, CAN_RAW);if (s < 0) {perror("Socket");exit(EXIT_FAILURE);}if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd)) < 0) {perror("setsockopt CAN_RAW_FD_FRAMES");close(s);exit(EXIT_FAILURE);}strcpy(ifr.ifr_name, CAN_INTERFACE);ioctl(s, SIOCGIFINDEX, &ifr);addr.can_family = AF_CAN;addr.can_ifindex = ifr.ifr_ifindex;if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {perror("Bind");close(s);exit(EXIT_FAILURE);}frame.can_id = 0x123 | CAN_EFF_FLAG; // Extended frame formatframe.len = 64; // CAN FD payload lengthfor (int i = 0; i < 64; i++) {frame.data[i] = i;}while (1) {if (write(s, &frame, sizeof(struct canfd_frame)) != sizeof(struct canfd_frame)) {perror("Write");}printf("Sent CAN FD frame: ID=0x%X LEN=%d\n", frame.can_id, frame.len);sleep(1); // Wait 1 second before sending the next frame}close(s);
}int main() {send_canfd_frames();return 0;
}
接收
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>#define CAN_INTERFACE "vcan0"void receive_canfd_frames() {int s;struct sockaddr_can addr;struct canfd_frame frame;struct ifreq ifr;int enable_canfd = 1;s = socket(PF_CAN, SOCK_RAW, CAN_RAW);if (s < 0) {perror("Socket");exit(EXIT_FAILURE);}if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd)) < 0) {perror("setsockopt CAN_RAW_FD_FRAMES");close(s);exit(EXIT_FAILURE);}strcpy(ifr.ifr_name, CAN_INTERFACE);ioctl(s, SIOCGIFINDEX, &ifr);addr.can_family = AF_CAN;addr.can_ifindex = ifr.ifr_ifindex;if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {perror("Bind");close(s);exit(EXIT_FAILURE);}while (1) {int nbytes = read(s, &frame, sizeof(struct canfd_frame));if (nbytes < 0) {perror("Read");} else if (nbytes == sizeof(struct canfd_frame)) {printf("Received CAN FD frame: ID=0x%X LEN=%d\n", frame.can_id, frame.len);for (int i = 0; i < frame.len; i++) {printf("%02X ", frame.data[i]);}printf("\n");}}close(s);
}int main() {receive_canfd_frames();return 0;
}
注:
canfd和can的发送和接收程序的区别
1.使用的结构体不同
- struct canfd_frame frame;
- struct can_frame frame;
2.canfd发送和接收需要使能Socket的canfd功能
int enable_canfd = 1;
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd)) < 0) {perror("setsockopt CAN_RAW_FD_FRAMES");close(s);exit(EXIT_FAILURE);
}
启用 CAN FD 模式是必须的,因为默认情况下,套接字配置为只支持经典 CAN 帧。如果不启用 CAN FD 模式,发送 CAN FD 帧时会出现 “Invalid argument” 错误。
CAN_RAW_FD_FRAMES
选项允许套接字发送和接收 CAN FD 帧。如果没有启用这个选项,套接字将仅支持经典 CAN 帧,并且会拒绝长度超过 8 字节的帧,这也是你之前遇到错误的原因。
如果你希望发送和接收 CAN FD 帧,必须包含这段代码。如果你不需要 CAN FD 支持并且仅使用经典 CAN 帧,可以省略它,但在这种情况下,数据帧长度会被限制在 8 字节以内。
对比
CAN(Controller Area Network)和 CAN FD(Controller Area Network Flexible Data-rate)是用于汽车和工业系统通信的两种协议。CAN 是传统的标准,而 CAN FD 是对 CAN 的改进版本。下面是它们之间的详细对比:
基本概念
- CAN(Controller Area Network):一种标准的多主总线协议,广泛应用于汽车和工业自动化领域,提供高可靠性和实时性。
- CAN FD(Flexible Data-rate CAN):是对 CAN 协议的扩展,旨在提高数据传输速率和增加数据帧容量。
数据速率
- CAN:
- 最高数据速率为 1 Mbps。
- CAN FD:
- 在仲裁阶段与传统 CAN 一样,最高为 1 Mbps。
- 在数据阶段,最高数据速率可达 8 Mbps。
数据帧长度
- CAN:
- 最大数据帧长度为 8 字节。
- CAN FD:
- 最大数据帧长度为 64 字节。
帧结构
- CAN:
- 标准帧格式包括 11 位标识符和扩展帧格式包括 29 位标识符。
- 数据长度码(DLC)表示数据字段的长度(0 到 8 字节)。
- CAN FD:
- 保留了标准和扩展帧格式。
- DLC 扩展到支持 0 到 64 字节的数据字段。
- 增加了 FDF(Flexible Data-rate Format)位以区分 CAN 和 CAN FD 帧。
- 增加了 BRS(Bit Rate Switch)位以指示数据阶段的速率切换。
- 增加了 EDL(Extended Data Length)位。
误码检测
- CAN:
- 使用 15 位或 17 位的 CRC 校验。
- CAN FD:
- 使用 17 位或 21 位的 CRC 校验,以支持更大的数据负载。
兼容性
- CAN:
- CAN 控制器只能处理 CAN 帧。
- CAN FD:
- CAN FD 控制器能够处理传统的 CAN 帧和 CAN FD 帧。
- 在一个网络中,CAN 节点和 CAN FD 节点可以共存,但需要确保仲裁阶段的兼容性。
实时性和可靠性
- CAN:
- 提供确定性和高实时性,适用于实时控制系统。
- CAN FD:
- 提供更高的数据吞吐量,同时保留 CAN 的实时性和可靠性特性。
应用场景
- CAN:
- 广泛应用于汽车电子(如发动机控制单元、传感器、空调系统等)和工业自动化系统。
- CAN FD:
- 应用于需要更高数据速率和更大数据负载的新一代汽车电子系统(如高级驾驶辅助系统、信息娱乐系统等)和工业自动化系统。
实例比较
CAN 帧结构
-
标准 CAN 帧:
+------+--------+------+-------+------+---------+------+ | SOF | 标识符 | RTR | 控制 | 数据 | CRC | ACK | +------+--------+------+-------+------+---------+------+ | 1 位 | 11 位 | 1 位 | 6 位 | 0-8 字节 | 15/17 位 | 2 位 | +------+--------+------+-------+------+---------+------+
-
扩展 CAN 帧:
+------+--------+--------+------+-------+------+---------+------+ | SOF | 标识符 (前 11 位) | SRR | IDE | 标识符 (后 18 位) | RTR | 控制 | 数据 | CRC | ACK | +------+--------+--------+------+-------+------+---------+------+ | 1 位 | 11 位 | 1 位 | 1 位 | 18 位 | 1 位 | 6 位 | 0-8 字节 | 15/17 位 | 2 位 | +------+--------+--------+------+-------+------+---------+------+
CAN FD 帧结构
- CAN FD 帧:
+------+--------+------+-------+-------+------+----------+-------+------+---------+------+ | SOF | 标识符 | FDF | 控制 | 数据长度代码 (DLC) | 数据 | CRC | ACK | +------+--------+------+-------+-------+------+----------+-------+------+---------+------+ | 1 位 | 11/29 位 | 1 位 | 1 位 | 4 位 | 0-64 字节 | 17/21 位 | 2 位 | +------+--------+------+-------+-------+------+----------+-------+------+---------+------+
总结
CAN 和 CAN FD 都是高可靠性、实时性强的总线通信协议。CAN 适用于大多数常规汽车和工业应用,而 CAN FD 则为需要更高数据速率和更大数据负载的现代应用提供了解决方案。通过对 CAN 的改进,CAN FD 保留了 CAN 的许多优点,同时增强了其性能和适用范围。在选择使用 CAN 还是 CAN FD 时,应根据具体应用的需求进行评估。