由於采用ramdisk文件系統,自帶的ip工具版本太舊無法配置can,需要自行編譯ip,具體參見參考文獻2
1.vivado配置ps
2.設備樹增加can0,一般開發板均已提供此配置
can@e0008000 { compatible = "xlnx,zynq-can-1.0"; status = "okay"; clocks = <0x1 0x13 0x1 0x24>; clock-names = "can_clk", "pclk"; reg = <0xe0008000 0x1000>; interrupts = <0x0 0x1c 0x4>; interrupt-parent = <0x3>; tx-fifo-depth = <0x40>; rx-fifo-depth = <0x40>; };
3.kernel配置,一般已配好,具體參見參考文獻1
4.測試
# ifconfig -a can0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 NOARP MTU:16 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:10 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) Interrupt:22 eth0 Link encap:Ethernet HWaddr 00:0A:35:00:01:22 inet addr:192.168.0.120 Bcast:192.168.0.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:397 errors:0 dropped:0 overruns:0 frame:0 TX packets:242 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:476490 (465.3 KiB) TX bytes:18536 (18.1 KiB) Interrupt:148 Base address:0xb000 lo Link encap:Local Loopback LOOPBACK MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
設置can0的波特率,這里設置的是100k, ip程序一般需要自己編譯生成,參見2
#./ip link set can0 up type can bitrate 100000
顯示can0狀態信息
#./ip -d -s link show can0
Z-turn# ./ip link set can0 type can bitrate 100000 xilinx_can e0008000.can can0: bitrate error 0.0% Z-turn#./ip link set can0 up Z-turn#./ip -d -s link show can0 2: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 10 link/can promiscuity 0 can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 0 bitrate 99999 sample-point 0.750 tq 2500 prop-seg 1 phase-seg1 1 phase-seg2 1 sjw 1 xilinx_can: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..256 brp-inc 1 clock 99999999 re-started bus-errors arbit-lost error-warn error-pass bus-off 0 0 0 0 0 0 numtxqueues 1 numrxqueues 1 RX: bytes packets errors dropped overrun mcast 0 0 0 0 0 0 TX: bytes packets errors dropped carrier collsns 0 0 0 0 0 0
5.下面程序為收發測試,也可參見參考文獻3
/***************************************************************************** * Copyright (c) 2014-2017 MYIR Tech Ltd. * File: can-test.c * Date: 2014/11/3 * Author: Kevin Su * Description: A demo program to show how to transmit/receive data with * socket can interface on CAN bus. * Please note that, this demo needs two boards to run as * transmitter and receiver. * Before run "can-test", we need to config the bitrate with * "ip" command: * # ip link set can0 up type can bitrate 100000 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <net/if.h> #include <linux/can.h> #include <linux/can/raw.h> #define DEBUG 1 #define ERR_MSG(fmt, args...) fprintf(stderr, fmt, ##args) #ifdef DEBUG #define DBG_MSG(fmt, args...) fprintf(stdout, fmt, ##args) #else #define DBG_MSG(fmt, args...) #endif #ifndef PF_CAN #define PF_CAN 29 #endif #ifndef AF_CAN #define AF_CAN PF_CAN #endif int main(int argc, char *argv[]) { int fd, ret, flag, len; char senddata[32] = "test"; struct sockaddr_can addr; struct ifreq ifr; struct can_frame frame; socklen_t socket_len = sizeof(struct sockaddr_can); /* Create a socket with PF_CAN family, SOCK_RAW and CAN_RAW protocol */ fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (fd < 0) { ERR_MSG("Open socket failed!\n"); return fd; } /* Use can0 */ strcpy((char *)(ifr.ifr_name), "can0"); /* Get information */ ret = ioctl(fd, SIOCGIFINDEX, &ifr); if (ret != 0) { ERR_MSG("SIOCGIFINDEX failed! ret:%d\n", ret); close(fd); return ret; } DBG_MSG("can0 can_ifindex = %x\n",ifr.ifr_ifindex); /* Disable loopback */ flag = 0; ret = setsockopt(fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &flag, sizeof(flag)); if (ret != 0) { ERR_MSG("Set loopback disable failed! ret:%d\n", ret); close(fd); return ret; } DBG_MSG("Set can0 loopback disable\n"); /* Disable receiving own message */ flag = 0; ret = setsockopt(fd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &flag, sizeof(flag)); if (ret != 0) { ERR_MSG("Disable receiving own message failed! ret:%d\n", ret); close(fd); return ret; } DBG_MSG("Disable receiving own message\n"); /* Use AF_CAN protocol family */ addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; /* Binding socket */ ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); if (ret != 0) { ERR_MSG("Bind socket failed! ret:%d\n", ret); close(fd); return ret; } DBG_MSG("Bind can0 socket\n"); frame.can_id = 0x123; len = strlen(senddata); while (1) { strncpy((char *)frame.data, senddata, len); frame.can_dlc = len; ret = sendto(fd, &frame, sizeof(struct can_frame), 0, (struct sockaddr*)&addr, sizeof(addr)); if (ret > 0) { DBG_MSG("Send success: [%s], ret=%d\n", senddata, ret); ret = recvfrom(fd, &frame, sizeof(struct can_frame), 0, (struct sockaddr *)&addr, &socket_len); if (ret > 0) { DBG_MSG("Recv message: [%s], ret=%d\n", frame.data, ret); } } usleep(500000); } return 0; }
超時設置(參考文獻4):
struct timeval timeout = {1,0}; //1.0s //設置發送超時 setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(struct timeval)); //設置接收超時 setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));
對於offline節點處理:
如果該控制器沒有連接到can網絡上,調用send會返回成功,但只是發送至kernel的緩沖區,並非發送至can網絡。kernel會一直嘗試重發,即使關閉socket或結束進程都不會取消重 發操作,此時如果將控制器連接到can網絡上則會一次性將緩沖區內所有內容發出,有時這並非所要結果。如果想要清空發送和接收緩沖區,只能重啟can接口
ifconfig can0 down ifconfig can0 up
在程序中可使用system調用。
2)即使等待超時時間值未到,但對方已經關閉了socket, 則此時recv()會立即返回,並收到多少數據返回多少數據。
參考文獻:
1.http://xilinx.eetrend.com/blog/12062
2.http://www.cnblogs.com/hujianhua/p/8446291.html
3.https://wenku.baidu.com/view/65baea51bb68a98271fefaa7.html
4.https://blog.csdn.net/newger/article/details/2459113