ZYNQ7000 petalinux扩展CAN总线
0,CAN总线详解:这里不再赘述
https://blog.****.net/qq_31710263/article/details/97015748
https://blog.****.net/liuligui5200/article/details/79030676
1,vivado工程,勾选EMIO扩展CAN0
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通信是否正常
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
7,ifconfig -a可以查看到如下信息:
设置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收发数据
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;
}