主机:Ubuntu 16.04
目标板:zynq + Linux内核4.4
一 硬件设计
采用zynq的CAN接口,外面用物理芯片SN65HVD23x,挂载到CAN总线。开始感觉不用物理芯片也可以向串口一样进行回环测试,发现是不可能,查看CAN的协议可以发现原因。
vivado生成相关文件,不在累述。
二 向内核中添加xilinx的can的驱动模块
[*] Networking support --->
<*> CAN bus subsystem support --->
CAN Device Drivers --->
<*> Xilinx CAN
三 修改设备树文件
zynq-7000.dtsi文件中,已经包含CAN的设备树文件,只是status设置为了disabled
can0: can@e0008000 {
compatible = "xlnx,zynq-can-1.0";
status = "disabled";
clocks = <&clkc 19>, <&clkc 36>;
clock-names = "can_clk", "pclk";
reg = <0xe0008000 0x1000>;
interrupts = <0 28 4>;
interrupt-parent = <&intc>;
tx-fifo-depth = <0x40>;
rx-fifo-depth = <0x40>;
};
can1: can@e0009000 {
compatible = "xlnx,zynq-can-1.0";
status = "disabled";
clocks = <&clkc 20>, <&clkc 37>;
clock-names = "can_clk", "pclk";
reg = <0xe0009000 0x1000>;
interrupts = <0 51 4>;
interrupt-parent = <&intc>;
tx-fifo-depth = <0x40>;
rx-fifo-depth = <0x40>;
};
为了保持一致性,在system.dts文件中修改can的状态设置
&can0 {
status = "okay";
};
&can1 {
status = "okay";
};
三 通过cantest.c程序测试
可以通过ipconfig -a查看can接口状态
配置can0和can1
ip link set can0 down
ip link set can1 down
ip link set can0 type can bitrate 500000
ip link set can1 type can bitrate 500000
ip link set can0 up
ip link set can1 up
can0和can1都挂载在can总线上
./cantest -r can0
./cantest -s can1
附cantest.c代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int s, nbytes;
int i;
char *array[2] = {"-r", "-s"};
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
struct can_filter rfilter[1];
/* handle (optional) flags first */
if(argc != 3) {
fprintf(stderr, "Usage: %s <-r> for receiving\nor <-s> for sending\n", argv[0]);
exit(1);
}
/* create socket */
if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
{
perror("Create socket failed");
exit(-1);
}
/* set up can interface */
strcpy(ifr.ifr_name, argv[2]);
printf("can port is %s\n",ifr.ifr_name);
/* assign can device */
ioctl(s, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
/* bind can device */
if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("Bind can device failed\n");
close(s);
exit(-2);
}
/* configure receiving */
if(!strcmp(argv[1],array[0]))
{
/* set filter for only receiving packet with can id 0x1F */
rfilter[0].can_id = 0x1F;
rfilter[0].can_mask = CAN_SFF_MASK;
if(setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)) < 0)
{
perror("set receiving filter error\n");
close(s);
exit(-3);
}
/* keep reading */
while(1){
nbytes = read(s, &frame, sizeof(frame));
if(nbytes > 0)
{
printf("%s ID=%#x data length=%d\n", ifr.ifr_name, frame.can_id, frame.can_dlc);
for (i=0; i < frame.can_dlc; i++)
printf("%#x ", frame.data[i]);
printf("\n");
}
}
}
/* configure sending */
else if(!strcmp(argv[1],array[1]))
{
/* configure can_id and can data length */
frame.can_id = 0x1F;
frame.can_dlc = 8;
printf("%s ID=%#x data length=%d\n", ifr.ifr_name, frame.can_id, frame.can_dlc);
/* prepare data for sending: 0x11,0x22...0x88 */
for (i=0; i<8; i++)
{
frame.data[i] = ((i+1)<<4) | (i+1);
printf("%#x ", frame.data[i]);
}
printf("Sent out\n");
/* Sending data */
if(write(s, &frame, sizeof(frame)) < 0)
{
perror("Send failed");
close(s);
exit(-4);
}
}
/* wrong parameter input situation */
else
{
printf("wrong parameter input\n");
}
close(s);
return 0;
}