ZYNQ7000 petalinux扩展CAN总线

0,CAN总线详解:这里不再赘述

https://blog.csdn.net/qq_31710263/article/details/97015748

https://blog.csdn.net/liuligui5200/article/details/79030676

1,vivado工程,勾选EMIO扩展CAN0

ZYNQ7000 petalinux扩展CAN总线

ZYNQ7000 petalinux扩展CAN总线

2,添加约束

set_property PACKAGE_PIN L15 [get_ports can_rx]
set_property IOSTANDARD LVCMOS33 [get_ports can_rx]
set_property PACKAGE_PIN L14 [get_ports can_tx]
set_property IOSTANDARD LVCMOS33 [get_ports can_tx]

3,导入sdk,新建empty空文件,新建can_zynq.h和can_zynq.c,代码如下:

#ifndef SRC_CAN_ZYNQ_H_
#define SRC_CAN_ZYNQ_H_
#include "xparameters.h"
#include "xcanps.h"
#include "xscugic.h"
#define XCANPS_MAX_FRAME_SIZE_IN_WORDS (XCANPS_MAX_FRAME_SIZE / sizeof(u32))
#define CAN_DEVICE_ID    XPAR_XCANPS_0_DEVICE_ID
#define CAN_INTR_VEC_ID        XPAR_XCANPS_0_INTR
#define TEST_BTR_SYNCJUMPWIDTH        3
#define TEST_BTR_SECOND_TIMESEGMENT    7
#define TEST_BTR_FIRST_TIMESEGMENT    15
#define TEST_BRPR_BAUD_PRESCALAR    4      //100M/(4+1) = 20M; 20/(1+1+2+1+15) = 1Mbps
//#define TEST_BRPR_BAUD_PRESCALAR    9      //100M/(9+1) = 10M; 10/(1+1+2+1+15) = 500Kbps
XCanPs Can;
u32 RxFrame[XCANPS_MAX_FRAME_SIZE_IN_WORDS];
enum can_baud_rate
{
    rate_1000kbps,
    rate_800kbps,
    rate_500kbps,
    rate_250kbps,
    rate_125kbps,
    rate_100kbps,
    rate_50kbps,
    rate_20kbps
};
typedef struct
{
  u16 id;    /**< frame's ID */
  u8 rtr;        /**< remote transmission request. (0 if not rtr frame, 1 if rtr frame) */
  u8 len;        /**< frame's length (0 to 8) */
  u8 data[8]; /**< frame's data */
} can_frame;
typedef struct
{
  u8 BaudRate;
  u8 BaudRatePrescaler;
  u8 TimeSegment1;
  u8 TimeSegment2;
  u8 SyncJumpWidth;
} can_bit_timing;
int can_init(XCanPs *CanInstPtr, u16 DeviceId, u8 BaudRate);
int Can_send(XCanPs *InstancePtr, can_frame *msg);
int CanSetupIntrSystem(XScuGic *IntcInstancePtr, XCanPs *CanInstancePtr, u16 CanIntrId);
void SendHandler(void *CallBackRef);
void RecvHandler(void *CallBackRef);
void ErrorHandler(void *CallBackRef, u32 ErrorMask);
void EventHandler(void *CallBackRef, u32 Mask);
#endif /* SRC_CAN_ZYNQ_H_ */

 

can_zynq.c

#include "can_zynq.h"
#include "sys_intr.h"
can_bit_timing can_bit_timing_config[]=
{
    {rate_1000kbps, 1,  15, 2, 2},
    {rate_800kbps,  4,  6, 1, 1},
    {rate_500kbps,  4,  12, 1, 0},
    {rate_250kbps,  9, 12, 1, 0},
    {rate_125kbps,  19, 12, 1, 0},
    {rate_100kbps,  24, 12, 1, 0},
    {rate_50kbps,   49, 12, 1, 0},
    {rate_20kbps,   124, 12, 1, 0}
};
static int Config(XCanPs *InstancePtr ,u8 BaudRate)
{
    int i;
    XCanPs_EnterMode(InstancePtr, XCANPS_MODE_CONFIG);
    while(XCanPs_GetMode(InstancePtr) != XCANPS_MODE_CONFIG);
    for(i=0; i<(sizeof(can_bit_timing_config)/sizeof(can_bit_timing)); i++)
    {
        if(can_bit_timing_config[i].BaudRate == BaudRate)
        {
            XCanPs_SetBaudRatePrescaler(InstancePtr, can_bit_timing_config[i].BaudRatePrescaler);
            XCanPs_SetBitTiming(InstancePtr,  can_bit_timing_config[i].SyncJumpWidth,
                    can_bit_timing_config[i].TimeSegment2,can_bit_timing_config[i].TimeSegment1);
            break;
        }
        if(i == ((sizeof(can_bit_timing_config)/sizeof(can_bit_timing)) - 1))
        {
            xil_printf("Baud rate not found!\r\n");
            return XST_FAILURE;
        }
    }

}
int can_init(XCanPs *CanInstPtr, u16 DeviceId, u8 BaudRate)
{

    XCanPs_Config *ConfigPtr;
    int Status;
    int i;
    ConfigPtr = XCanPs_LookupConfig(DeviceId);
    if (CanInstPtr == NULL)
        {
        return XST_FAILURE;
     }
    Status = XCanPs_CfgInitialize(CanInstPtr,ConfigPtr,ConfigPtr->BaseAddr);
    if (Status != XST_SUCCESS)
    {
        return XST_FAILURE;
    }
    Status = XCanPs_SelfTest(CanInstPtr);
    if (Status != XST_SUCCESS)
       {
        return XST_FAILURE;
    }
    Config(CanInstPtr,BaudRate);
    XCanPs_SetHandler(CanInstPtr, XCANPS_HANDLER_SEND,(void *)SendHandler, (void *)CanInstPtr);
    XCanPs_SetHandler(CanInstPtr, XCANPS_HANDLER_RECV,(void *)RecvHandler, (void *)CanInstPtr);
    XCanPs_SetHandler(CanInstPtr, XCANPS_HANDLER_ERROR,(void *)ErrorHandler, (void *)CanInstPtr);
    XCanPs_SetHandler(CanInstPtr, XCANPS_HANDLER_EVENT,(void *)EventHandler, (void *)CanInstPtr);
    Status =  CanSetupIntrSystem(&Intc, CanInstPtr, CAN_INTR_VEC_ID);
    if (Status != XST_SUCCESS)
       {
        return XST_FAILURE;
    }
    XCanPs_EnterMode(CanInstPtr, XCANPS_MODE_NORMAL);
    while(XCanPs_GetMode(CanInstPtr) != XCANPS_MODE_NORMAL);
    return XST_SUCCESS;
}

int Can_send(XCanPs *InstancePtr, can_frame *msg)
{
    int Status;
    u32 TxFrame[XCANPS_MAX_FRAME_SIZE_IN_WORDS] = {0};
    TxFrame[0] = (u32)XCanPs_CreateIdValue((u32)msg->id, (u32)msg->rtr, 0, 0, 0);
    TxFrame[1] = (u32)XCanPs_CreateDlcValue((u32)msg->len);
    TxFrame[2] = (u32)(((u32)msg->data[3] << 24) | ((u32)msg->data[2] << 16) | ((u32)msg->data[1] << 8) | ((u32)msg->data[0]));
    TxFrame[3] = (u32)(((u32)msg->data[7] << 24) | ((u32)msg->data[6] << 16) | ((u32)msg->data[5] << 8) | ((u32)msg->data[4]));
    while (XCanPs_IsTxFifoFull(InstancePtr) == TRUE);
    Status = XCanPs_Send(InstancePtr, TxFrame);
    if (Status != XST_SUCCESS)
        {
        xil_printf("Can send failed\r\n");
    }
    return Status;
}

int CanSetupIntrSystem(XScuGic *IntcInstancePtr,XCanPs *CanInstancePtr,u16 CanIntrId)
{
    int Status;
    Status = XScuGic_Connect(IntcInstancePtr, CanIntrId,(Xil_InterruptHandler)XCanPs_IntrHandler,(void *)CanInstancePtr);
    if (Status != XST_SUCCESS)
    {
        return Status;
     }
    XScuGic_Enable(IntcInstancePtr, CanIntrId);
    XCanPs_IntrEnable(CanInstancePtr, XCANPS_IXR_ALL);
    return XST_SUCCESS;
}
void SendHandler(void *CallBackRef)
{
    xil_printf("Can send done\r\n");
}

void RecvHandler(void *CallBackRef)
{
    XCanPs *CanPtr = (XCanPs *)CallBackRef;
    int Status;
    int i;
    can_frame msg = {0};
    u8 *FramePtr;

    xil_printf("Can receive done\r\n");

    Status = XCanPs_Recv(CanPtr, RxFrame);

    if (Status != XST_SUCCESS) {
        xil_printf("Can receive failed\r\n");
        return;
    }
    msg.id = (u16)((RxFrame[0] & XCANPS_IDR_ID1_MASK )>> XCANPS_IDR_ID1_SHIFT);
    msg.rtr = (u8)((RxFrame[0] & XCANPS_IDR_SRR_MASK) >> XCANPS_IDR_SRR_SHIFT);
    msg.len = (u8)((RxFrame[1] & XCANPS_DLCR_DLC_MASK) >> XCANPS_DLCR_DLC_SHIFT);
    FramePtr = (u8 *)(&RxFrame[2]);
    for(i=0; i<8; i++)
    {
        msg.data[i] = *FramePtr++;
    }
    xil_printf("frame ID: %d\r\n", msg.id);
    xil_printf("frame type: %s\r\n", msg.rtr ? "remote request frame" : "data frame");
    xil_printf("frame length: %d\r\n", msg.len);
    if(!msg.rtr)
    {
        for(i=0; i<msg.len; i++)
        {
            xil_printf("data %d is: 0x%02x\r\n", i+1, msg.data[i]);
        }
    }
}
void ErrorHandler(void *CallBackRef, u32 ErrorMask)
{
    xil_printf("Can error happen\r\n");

}
void EventHandler(void *CallBackRef, u32 IntrMask)
{
    XCanPs *CanPtr = (XCanPs *)CallBackRef;
    xil_printf("Can event happen\r\n");
    if (IntrMask & XCANPS_IXR_BSOFF_MASK)
    {
        XCanPs_Reset(CanPtr);
        Config(CanPtr,rate_500kbps);
        return;
     }
}

主函数main.c

#include "can_zynq.h"
#include "sys_intr.h"
#include "sleep.h"
int main(void)
{
    can_frame msg;
    int i;
    xil_printf("Can start\r\n");

    Init_Intr_System(&Intc);
    can_init(&Can, CAN_DEVICE_ID, rate_500kbps);
    Setup_Intr_Exception(&Intc);

    msg.id = 1;
    msg.rtr = 0;
    msg.len = 8;
    for(i=0; i<msg.len; i++)
     {
        msg.data[i] = i;
     }
    while(1)
    {
        Can_send(&Can, &msg);
        msg.data[0]++;
        sleep(5);
    }
}

可以外接如下模块和can分析仪下载运行,打开canpro查看数据:先测试一下CAN通信是否正常

ZYNQ7000 petalinux扩展CAN总线

ZYNQ7000 petalinux扩展CAN总线

4,将*.hdf硬件复制到虚拟机

petalinux-create --type project --template zynq --name can_test

petalinux-config --get-hw-description ../linux_base.sdk

5,在devicetree中需要增加can的配置信息,如下:

[email protected] {
                            compatible= "xlnx,zynq-can-1.0";
                            status= "okay";
                            clocks= <0x1 0x13 0x1 0x24>;
                            clock-names= "ref_clk", "aper_clk";
                            reg = <0xe00080000x1000>;
                            interrupts= <0x0 0x1c 0x4>;
                            interrupt-parent= <0x3>;
                            tx-fifo-depth= <0x40>;
                            rx-fifo-depth= <0x40>;
};

6,添加CAN总线驱动,在kernel中需要增加can驱动的支持:petalinux-config -c kernel

ZYNQ7000 petalinux扩展CAN总线

ZYNQ7000 petalinux扩展CAN总线

ZYNQ7000 petalinux扩展CAN总线

ZYNQ7000 petalinux扩展CAN总线

7,ifconfig  -a可以查看到如下信息:

ZYNQ7000 petalinux扩展CAN总线

设置can0的波特率,这里设置的是100k:ip link set can0 type can bitrate100000

启用can0:ip link set can0 up

显示can0状态信息:ip -d -s link show can0

8,按sdk时候的连接,测试can收发数据

ZYNQ7000 petalinux扩展CAN总线

ZYNQ7000 petalinux扩展CAN总线

9,linux下的can总线应用程序示范:test_can.c

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <linux/if.h>
#include <pthread.h>
#include "can.h"
#define PF_CAN 29
#define AF_CAN PF_CAN
#define SIOCSCANBAUDRATE        (SIOCDEVPRIVATE+0)
#define SIOCGCANBAUDRATE        (SIOCDEVPRIVATE+1)
#define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW)
#define CAN_RAW_FILTER  1
#define CAN_RAW_RECV_OWN_MSGS 0x4
typedef __u32 can_baudrate_t;
struct ifreq ifr;
int init_can(char* can)
{
    int sock;
    struct sockaddr_can addr;
    sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if(sock < 0)
    {
        printf("error\n");
        return -1;
    }
    addr.can_family = AF_CAN;
    strcpy(ifr.ifr_name, can );
    int ret;
    ret = ioctl(sock, SIOCGIFINDEX, &ifr);  //get index
    if(ret && ifr.ifr_ifindex == 0)
    {
        printf("Can't get interface index for can0, code= %d, can0 ifr_ifindex value: %d, name: %s\n", ret, ifr.ifr_ifindex, ifr.ifr_name);
        close(sock);
        return -1;
    }

    printf("%s can_ifindex = %x\n",ifr.ifr_name,ifr.ifr_ifindex);
    addr.can_ifindex = ifr.ifr_ifindex;    
    int recv_own_msgs = 0;//set loop back:  1 enable 0 disable
    setsockopt(sock, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,&recv_own_msgs, sizeof(recv_own_msgs));
    if (bind(sock,(struct sockaddr*)&addr,sizeof(addr))<0)
    {
        printf("bind error\n");
        close(sock);
        return -1;
    }
    return sock;
}

void Can_Read_thread(void* psock)
{
    int sock = *(int *)psock;
    int i = 0;
    struct can_frame frame;
    while(1)
    {
        memset(&frame,0,sizeof(struct can_frame));
        read(sock,&frame,sizeof(struct can_frame));
        if(frame.can_dlc)
        {
            printf("\n%s DLC:%d Data:", ifr.ifr_name, frame.can_dlc);        
            for(i = 0; i < frame.can_dlc; i++)
            {
                printf("%#x ",frame.data[i]);
            }
            printf("\n");
        }
    }    
}

int Write_Can_Data(int sock,char* str,int len)
{
    struct can_frame frame;
    int i;
    int nbytes = 0;
    frame.can_id = 0x0; //can device id
    while(len)
    {
        if(len > sizeof(frame.data))
        {
            memset(&frame.data,0,sizeof(frame.data));
            memcpy(&frame.data,str,sizeof(frame.data));
            //printf("%d,(%s)\r\n",sizeof(frame.data),frame.data);
            frame.can_dlc = sizeof(frame.data);
            str += sizeof(frame.data);
            len -= sizeof(frame.data);
        }
        else {
            memset(&frame.data,0,sizeof(frame.data));
            memcpy(&frame.data,str,len);
            //printf("%d,(%s)\r\n",len,frame.data);
            frame.can_dlc = len;
            str = NULL;
            len = 0;
        }
        write(sock, &frame, sizeof(struct can_frame));
        usleep(100);
    }
}

int main(int argc ,char** argv)
{
    int sock;
    int nbytes;
    pthread_t canthreadid;
    int ret;
    char str[4096];
    if(argc < 2)
    {
        printf("Usage: %s <device>(can0/can1)\n", argv[0]);
        return 0;
    }
    sock = init_can(argv[1]);
    if(sock < 0)
    {
        return 0;
    }
    ret=pthread_create(&canthreadid,NULL,(void*)Can_Read_thread,&sock);
    while(1)
    {
        printf("Please Input string to send to %s\n:",argv[1]);
        scanf("%s", str);
        if(strlen(str)>0)
            Write_Can_Data(sock,str,strlen(str));
    }
//    struct can_frame frame;
//    char    buf[20];
//    frame.can_id = 0x0; //can device id
//    int i;
//    for(i=0;i<20;i++)
//    {
        //nbytes = sendto(sock,&frame,sizeof(struct can_frame),0,(struct sockaddr*)&addr,sizeof(addr));
//        memset(&buf,0,sizeof(buf));    
//        sprintf(buf,"%s%d","hello",i);
//        strcpy((char *)frame.data,buf);
//        frame.can_dlc = strlen(frame.data);
//        nbytes = write(sock, &frame, sizeof(struct can_frame));
//        printf("%d. %ld bytes has been sent\n", i, nbytes);
//        sleep(1);
//    }
    close(sock);
    printf("ok\n");    
    return 0;
}