zynq+linux+ramdisk can調試


由於采用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調用。

有兩點注意就是
1)recv ()的第四個參數需為MSG_WAITALL,在阻塞模式下不等到指定數目的數據不會返回,除非超時時間到。

    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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM