随着现在工控领域技术的发展,传输的数据量越来越多, CAN总线在传输速率和带宽渐渐不能满足现场的需求。为了解决这个问题,BOSCH公司推出了CAN FD(CAN with Flexible Data rate)协议,该协议可以支持更高的波特率和更长的数据位,最高波特率可达8Mbit/s,支持最长数据位为64byte,并且可以兼容传统的CAN 2.0B协议。为了在英创Linux工控主板上支持CAN FD,满足客户的需求,英创公司基于SBC8XX系列工控应用底板,设计了扩展模块ETA703。
ETA703模块
ETA703通过SPI总线扩展出一路支持CAN FD的CAN总线,同时将主板的串口隔离后分别转换为RS232和RS485,并将主板带有的2路CAN总线也经过隔离后引出,因此模块上一共包含3路can、3路RS485和1路RS232:
ETA703工控通讯接口 | 接口数量 | 简要说明 |
CAN-FD高速现场总线 | 1 | 8Mbps最高波特率,与CAN2.0B兼容 |
CAN-2.0B总线 | 2 | 波特率: 50kbps - 1Mbps |
RS485 | 3 | 自动方向切换 |
RS232 | 1 | 3线制 |
英创公司已经调试好了ETA703的驱动,用户在使用时调用modprobe eta703命令就能够加载对应的驱动文件。目前能够支持ETA703扩展模块的主板为ESM6800H/E,ESM6802和ESM7000,因为CAN FD是比较新的功能,需要这几款主板使用的较高版本的交叉工具链才能够支持。
驱动加载成功后系统会生成新的CAN设备,因为ESMARC系列主板都板载了2路CAN总线(can0和can1),所以加载驱动后生成的设备为can2,可以使用命令ifconfig –a来查看。
关于ETA703更加具体的参数说明可以参考ETA703的数据手册。这里主要介绍关于CAN FD的相关概念和程序接口。CAN FD的全称为CAN with Flexible Data rate,相对于传统的CAN总线协议,主要有两点变化:
第一点从字面上就能够看出来,即传输速率是可变的,最高可达8Mbit/s。
第二点是相比传统CAN总线的8byte数据位,CAN FD协议最长可以支持64byte数据位。
我们可以将CAN FD看作是传统CAN 2.0B协议的升级版本,并且是向下兼容的,即能够同时支持CAN 2.0B协议。所以使用原来英创公司提供的CAN总线例程(test_socketcan)就能够在ETA703上进行正常的通讯,只是没有启用CAN FD的功能而已,关于CAN FD协议更加详细的介绍可以参考网站:https://www.can-cia.org/can-knowledge/can/can-fd/。
接下来我们介绍如何通过程序启用CAN FD协议进行通讯。其实Linux系统使用的socketcan接口已经很好的支持了CAN FD,并且同时能够兼容CAN 2.0B协议。首先来看在<linux/can.h>头文件中对于CAN和CANFD数据帧的结构体定义:
struct can_frame { canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ __u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */ __u8 __pad; /* padding */ __u8 __res0; /* reserved / padding */ __u8 __res1; /* reserved / padding */ __u8 data[CAN_MAX_DLEN] __attribute__((aligned(8))); };
上面是对CAN数据帧的定义,和下面CAN FD数据帧的定义对比,可以发现是兼容的,区别只在于数据位的长度上面:
struct canfd_frame { canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ __u8 len; /* frame payload length in byte */ __u8 flags; /* additional flags for CAN FD */ __u8 __res0; /* reserved / padding */ __u8 __res1; /* reserved / padding */ __u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8))); };
关于数据位的长度,根据前面的介绍应该能够了解到CAN FD最长支持64byte的数据位,在头文件中有如下定义:
/* CAN payload length and DLC definitions according to ISO 11898-1 */ #define CAN_MAX_DLC 8 #define CAN_MAX_DLEN 8 /* CAN FD payload length and DLC definitions according to ISO 11898-7 */ #define CANFD_MAX_DLC 15 #define CANFD_MAX_DLEN 64
启用CAN FD具体命令为ip link set can2 up type can bitrate 1000000 dbitrate 2000000 fd on restart-ms 100,可以看到是在原来使能CAN总线命令的基础上增加了CAN FD的波特率的设置。同时在程序中也需要调用ioctl来使能CAN FD,具体代码如下:
/* try to switch the socket into CAN FD mode */ canfd_on = 1; setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
在使能了CAN FD协议后,数据通讯的部分使用的函数和标准的CAN通讯是相同的,都是使用write和recv函数,驱动会根据传输的帧的长度,自动判断是否为CAN FD数据帧。所以客户在编写程序的时候,只需要注意一下填入的传输数据长度即可,这里可以利用头文件中的宏定义:
#define CAN_MTU (sizeof(struct can_frame)) #define CANFD_MTU (sizeof(struct canfd_frame))
发送CAN FD数据的具体代码如下:
struct canfd_frame frame; frame.len = 64; nbytes = write(s, &frame, CANFD_MTU);
如果将frame.len的值改为8,write函数中的长度改为CAN_MTU,驱动就自动切换成CAN 2.0B协议进行发送。同样的在接收数据的时候,可以通过recv函数的返回值来判断,具体代码如下:
nbytes = recv(can_sock, &frame, CANFD_MTU, 0 ); if (nbytes < 0) { perror("can raw socket read"); break; } if ((size_t)nbytes == CAN_MTU) { maxdlen = CAN_MAX_DLEN; } else if ((size_t)nbytes == CANFD_MTU) { maxdlen = CANFD_MAX_DLEN; } else { fprintf(stderr, "read: incomplete CAN frame\n"); return 1; }
从上面的代码可以看出CAN FD的编程十分简单,socketcan提供的接口完美的兼容了CAN 2.0B和CAN FD,只需要在原来标准CAN总线的例程中增加对CAN FD的使能就可以了,在数据传输时候,根据数据帧长度就能判断出类型,然后做出对应的处理。
感兴趣的客户可以和英创的工程师联系,索取完整的例程代码。
成都英创信息技术有限公司 028-8618 0660