赞
踩
官网: CAN with Flexible Data Rate (CAN FD) (xilinx.com)
特征:
参考:
C:\Xilinx\Vitis\2023.2\data\embeddedsw\XilinxProcessorIPLib\drivers\canfd_v2_8
本文仅作学习交流使用.
硬件:
如图:
时钟:
调试串口:
时钟的配置截图
CANFD的配置, 收发FIFO Depth都是32, 接收使用顺序模式, 不用FIFO1
可适当减少RX FIFO-0 Depth以减少RAM消耗. 含MicroBlaze 64K, 一路CANFD, 没有使用任何外部RAM的消耗如下(xc7a35tfgg484-2):
初始化:
error: invalid conversion from 'void (*)(void*)' to 'void*' [-fpermissive]
参考代码如下:
int bsp_canfd_init(XCanFd *InstancePtr, uint32_t BaseAddress, uint32_t BaudRate, float SamplePoint, uint32_t FastBaudRate, float FastSamplePoint) { XCanFd_Config *ConfigPtr = XCanFd_LookupConfig(BaseAddress); if (ConfigPtr == NULL) { bsp_canfd_debug_printf("Error: XCanFd_LookupConfig returned NULL\n"); return -1; } else { bsp_canfd_debug_printf("XCanFd_Config:\n"); bsp_canfd_debug_printf(" BaseAddress: 0x%08X\n", ConfigPtr->BaseAddress); bsp_canfd_debug_printf(" Rx_Mode: %s\n", ConfigPtr->Rx_Mode ? "Mailbox" : "Sequential"); bsp_canfd_debug_printf(" NumofRxMbBuf: %d\n", ConfigPtr->NumofRxMbBuf); bsp_canfd_debug_printf(" NumofTxBuf: %d\n", ConfigPtr->NumofTxBuf); bsp_canfd_debug_printf(" IntrId: %d\n", ConfigPtr->IntrId); bsp_canfd_debug_printf(" IntrParent: 0x%08X\n", ConfigPtr->IntrParent); } int Status = XCanFd_CfgInitialize(InstancePtr, ConfigPtr, ConfigPtr->BaseAddress); if (Status != XST_SUCCESS) { bsp_canfd_debug_printf("Error: XCanFd_CfgInitialize returned %d\n", Status); return -2; } else { bsp_canfd_debug_printf("XCanFd_CfgInitialize: Success\n"); } // config mode XCanFd_EnterMode(InstancePtr, XCANFD_MODE_CONFIG); while (XCanFd_GetMode(InstancePtr) != XCANFD_MODE_CONFIG) ; bsp_canfd_debug_printf("XCanFd_EnterMode: XCANFD_MODE_CONFIG\n"); // 80MHz / (3 + 1) = 20MHz, 20MHz / (1 + (30 + 1) + (7 + 1)) = 500KHz // XCanFd_SetBitTiming(InstancePtr, 8, 7, 30); XCanFd_SetBaudRatePrescaler(InstancePtr, 0x3); u16 total_tq = 20000000 / BaudRate; u16 tseg1 = (u16)(SamplePoint * total_tq) - 2; u8 tseg2 = (u8)(total_tq - tseg1 - 3); u8 sjw = tseg2 + 1; XCanFd_SetBitTiming(InstancePtr, sjw, tseg2, tseg1); // 80MHz, 80 / (1 + (30 + 1) + (7 + 1)) = 2MHz // XCanFd_SetFBitTiming(InstancePtr, 8, 7, 30); XCanFd_SetFBaudRatePrescaler(InstancePtr, 0x0); u16 ftotal_tq = 80000000 / FastBaudRate; u8 ftseg1 = (u8)(FastSamplePoint * ftotal_tq) - 2; u8 ftseg2 = (u8)(ftotal_tq - ftseg1 - 3); u8 fsjw = ftseg2 + 1; XCanFd_SetFBitTiming(InstancePtr, fsjw, ftseg2, ftseg1); // TDC, 0~31 // XCanFd_Set_Tranceiver_Delay_Compensation(InstancePtr, 0x3); XCanFd_SetBitRateSwitch_DisableNominal(InstancePtr); bsp_canfd_debug_printf("XCanFd: %d@0.%d, %d@0.%d\n", BaudRate, (int)(SamplePoint * 1000), FastBaudRate, (int)(FastSamplePoint * 1000)); if (XCANFD_GET_RX_MODE(InstancePtr) == 0) { bsp_canfd_debug_printf( "RX_MODE Sequential Filter: XCANFD_AFR_UAF_ALL_MASK\n"); XCanFd_AcceptFilterDisable(InstancePtr, XCANFD_AFR_UAF_ALL_MASK); XCanFd_AcceptFilterEnable(InstancePtr, XCANFD_AFR_UAF_ALL_MASK); } else { bsp_canfd_debug_printf("RX_MODE Mailbox Filter: Need to be implemented\n"); } XCanFd_SetHandler(InstancePtr, XCANFD_HANDLER_SEND, (void *)SendHandler, (void *)InstancePtr); XCanFd_SetHandler(InstancePtr, XCANFD_HANDLER_RECV, (void *)RecvHandler, (void *)InstancePtr); XCanFd_SetHandler(InstancePtr, XCANFD_HANDLER_ERROR, (void *)ErrorHandler, (void *)InstancePtr); XCanFd_SetHandler(InstancePtr, XCANFD_HANDLER_EVENT, (void *)EventHandler, (void *)InstancePtr); Status = XSetupInterruptSystem(InstancePtr, &XCanFd_IntrHandler, ConfigPtr->IntrId, ConfigPtr->IntrParent, XINTERRUPT_DEFAULT_PRIORITY); if (Status != XST_SUCCESS) { bsp_canfd_debug_printf("Error: XSetupInterruptSystem returned %d\n", Status); return 1; } else { bsp_canfd_debug_printf("XSetupInterruptSystem: Success\n"); } XCanFd_InterruptEnable(InstancePtr, XCANFD_IXR_ALL); XCanFd_EnterMode(InstancePtr, XCANFD_MODE_NORMAL); while (XCanFd_GetMode(InstancePtr) != XCANFD_MODE_NORMAL) ; bsp_canfd_debug_printf("XCanFd_EnterMode: XCANFD_MODE_NORMAL\n"); return 0; }
发送套用Linux SocketCAN
接口, 毕竟这个用的人多, 易于理解. 因为发送FIFO深度为32, 所以, 正常情况下连发32帧无需插入延时, 也无需自己处理发送队列, 这已经够大部分情况使用了.
int bsp_canfd_send(XCanFd *InstancePtr, struct canfd_frame *frame) { bool is_extended = frame->can_id & CAN_EFF_FLAG ? true : false; bool is_remote = frame->can_id & CAN_RTR_FLAG ? true : false; bool is_fd = frame->flags & CANFD_FDF ? true : false; bool is_brs = frame->flags & CANFD_BRS ? true : false; bool is_esi = frame->flags & CANFD_ESI ? true : false; u32 TxFrame[CANFD_MTU]; TxFrame[0] = XCanFd_CreateIdValue( CAN_SFF_MASK & (is_extended ? ((frame->can_id & CAN_EFF_MASK) >> 18) : frame->can_id), is_extended ? 1 : (u32)is_remote, (u32)is_extended, (u32)is_extended ? (frame->can_id & 0x3FFFF) : 0, is_extended ? (u32)is_remote : 0); if ((!is_fd) && (!is_brs)) { TxFrame[1] = XCanFd_CreateDlcValue(frame->len); } else { if (is_brs) { TxFrame[1] = XCanFd_Create_CanFD_Dlc_BrsValue(XCanFd_GetLen2Dlc(frame->len)); } else { TxFrame[1] = XCanFd_Create_CanFD_DlcValue(XCanFd_GetLen2Dlc(frame->len)); } } u8 *FramePtr = (u8 *)(&TxFrame[2]); for (int i = 0; i < frame->len; i++) { FramePtr[i] = frame->data[i]; } u32 TxBufferNumber; int status = XCanFd_Send(InstancePtr, TxFrame, &TxBufferNumber); if (status == XST_FIFO_NO_ROOM) { bsp_canfd_debug_printf("Error: XCanFd_Send returned XST_FIFO_NO_ROOM\n"); return -1; } if (status != XST_SUCCESS) { bsp_canfd_debug_printf("Error: XCanFd_Send returned %d\n", status); return -2; } return 0; }
接收的示例, 类似 candump:
%03X
打印, 扩展帧是%08X
打印.R
, 数据帧打D
F
且长度为[%02d]
, Classic CAN打-
且数据长度为[%d]
B
, 否则打-
static void RecvHandler(void *CallBackRef) { XCanFd *CanPtr = (XCanFd *)CallBackRef; int Status; u32 RxFrame[CANFD_MTU]; /* Check for the design 1 - MailBox 0 - Sequential */ if (XCANFD_GET_RX_MODE(CanPtr) == 1) { Status = XCanFd_Recv_Mailbox(CanPtr, RxFrame); } else { Status = XCanFd_Recv_Sequential(CanPtr, RxFrame); } u32 id1 = (RxFrame[0] >> (u32)XCANFD_IDR_ID1_SHIFT) & (u32)0x7FF; u32 is_extended = (RxFrame[0] >> (u32)XCANFD_IDR_IDE_SHIFT) & (u32)0x1; u32 id2 = (RxFrame[0] >> (u32)XCANFD_IDR_ID2_SHIFT) & (u32)0x3FFFF; u32 is_remote = is_extended ? (RxFrame[0] & 0x01) : ((RxFrame[0] >> (u32)XCANFD_IDR_SRR_SHIFT) & (u32)0x1); /* Get the Dlc inthe form of bytes */ u32 len = XCanFd_GetDlc2len(RxFrame[1] & XCANFD_DLCR_DLC_MASK, EDL_CANFD); if (Status != XST_SUCCESS) { bsp_canfd_debug_printf("Error: XCanFd_Recv returned %d\n", Status); return; } u32 is_brs = RxFrame[1] & XCANFD_DLCR_BRS_MASK ? 1 : 0; u32 is_fdf = RxFrame[1] & XCANFD_DLCR_EDL_MASK ? 1 : 0; // bsp_canfd_debug_printf("%08X ", RxFrame[0]); u8 *FramePtr = (u8 *)(&RxFrame[2]); if (is_extended) { bsp_canfd_debug_printf("%08X ", id1 << 18 | id2); } else { bsp_canfd_debug_printf("%03X ", id1); } if (is_remote) { bsp_canfd_debug_printf("R [%d]", len); } else { bsp_canfd_debug_printf("D "); if (is_fdf) { bsp_canfd_debug_printf("F "); } else { bsp_canfd_debug_printf("- "); } if (is_brs) { bsp_canfd_debug_printf("B "); } else { bsp_canfd_debug_printf("- "); } if ((!is_fdf) && (!is_brs)) { bsp_canfd_debug_printf("[%d] ", len); } else { bsp_canfd_debug_printf("[%02d] ", len); } for (int i = 0; i < len; i++) { bsp_canfd_debug_printf("%02X ", FramePtr[i]); } } bsp_canfd_debug_printf("\n"); }
如下:
int main() { xil_printf("============================================\n"); XCanFd CanFd0; int Status = bsp_canfd_init(&CanFd0, XPAR_CANFD_0_BASEADDR, 500000, 0.8, 4000000, 0.8); if (Status != 0) { xil_printf("Error: bsp_canfd_init returned %d\n", Status); return -1; } for (int i = 0; i < 4; i++) { struct canfd_frame frame = { .can_id = 0x123, .len = 8, .flags = 0, .__res0 = 0, .__res1 = 0, .data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F}, }; // std can frame.can_id = 0x123; frame.len = 8; frame.flags = 0; int Status = bsp_canfd_send(&CanFd0, &frame); // std can remote frame.can_id = 0x124 | CAN_RTR_FLAG; frame.len = 8; frame.flags = 0; Status |= bsp_canfd_send(&CanFd0, &frame); // std can fd frame.can_id = 0x125; frame.len = 64; frame.flags = CANFD_FDF; Status |= bsp_canfd_send(&CanFd0, &frame); // std can fd brs frame.can_id = 0x126; frame.len = 64; frame.flags = CANFD_FDF | CANFD_BRS; Status |= bsp_canfd_send(&CanFd0, &frame); // ext can frame.can_id = 0x12345678 | CAN_EFF_FLAG; frame.len = 8; frame.flags = 0; Status |= bsp_canfd_send(&CanFd0, &frame); // ext can remote frame.can_id = 0x12345679 | CAN_EFF_FLAG | CAN_RTR_FLAG; frame.len = 8; frame.flags = 0; Status |= bsp_canfd_send(&CanFd0, &frame); // ext can fd frame.can_id = 0x1234567A | CAN_EFF_FLAG; frame.len = 64; frame.flags = CANFD_FDF; Status |= bsp_canfd_send(&CanFd0, &frame); // ext can fd brs frame.can_id = 0x1234567B | CAN_EFF_FLAG; frame.len = 64; frame.flags = CANFD_FDF | CANFD_BRS; Status |= bsp_canfd_send(&CanFd0, &frame); if (Status != 0) { xil_printf("Error: bsp_canfd_send %d returned %d\n", i, Status); return -1; } } while (1) { } return 0; }
设置:
MCU连续发出的32帧报文:
逻辑分析仪上可以看出来两帧之间卡着标准的3 ITM来的
出现BRS时的情况, 左边500K, 右边4M
CAN分析仪向FPGA发送测试:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。