/****************************************************************************** 版权所有: 文件名称: flexcan.c 文件版本: 01.01 创建作者: sunxi 创建日期: 2025-09-28 功能说明: FLEXCAN驱动 其它说明: 修改记录: */ /*------------------------------- 头文件 -------------------------------------- */ #include "bspconfig.h" #include "rt_printf.h" #include "ustimer.h" #include "rt.h" #include "flexcan.h" #include #include #include #include #include #include #include #include #ifdef BSP_CAN_ENABLE /*------------------------------- 宏定义 -------------------------------------- */ #define CAN_FIFO // 优先级 #define CAN_PRIO_MAX 4 // 短帧BUF #define CAN_FRAME_NUM 256 // CAN短帧BUF数量 #define CAN_FRAME_LEN 16 // CAN短帧BUF长度 #define CAN_FRAME_HEAD_LEN 8 // CAN短帧帧头长度 #define CAN_FRAME_DATA_LEN 8 // CAN短帧数据长度 // 长帧BUF #define CAN_LONGFRAME_NUM 16 // CAN长帧BUF数量 #define CAN_LONGFRAME_LEN CAN_FRAME_LEN_MAX // CAN长帧BUF长度 #define CAN_LONGFRAME_HEAD_LEN 4 // CAN长帧头长度 #define CAN_LONGFRAME_DATA_LEN (CAN_LONGFRAME_LEN-CAN_LONGFRAME_HEAD_LEN) // CAN长帧数据长度 // 帧标志,数字越小,优先级越高 #define CAN_FRAME_SINGLE 0 // 单帧(既是起始帧,又是结束帧) #define CAN_FRAME_END 1 // 结束帧 #define CAN_FRAME_MIDDLE 2 // 中间帧 #define CAN_FRAME_BEGIN 3 // 开始帧 //帧ID中各个域的位偏移 #define CAN_FRAME_OFFSET_SN 0 // 帧序号偏移 #define CAN_FRAME_OFFSET_MARK 6 // 帧标志偏移 #define CAN_FRAME_OFFSET_SRC 8 // 帧源地址偏移 #define CAN_FRAME_OFFSET_DST 12 // 帧目的地址偏移 #define CAN_FRAME_OFFSET_TYPE 16 // 帧类型偏移 #define CAN_FRAME_OFFSET_PRIOR 23 // 帧优先级偏移(帧优先级是帧类型的高2位) #define CAN_FRAME_OFFSET_LEN 16 // 帧长度偏移 #define CAN_FRAME_MASK_SN 0X3F // 帧序号屏蔽位 #define CAN_FRAME_MASK_MARK 0X03 // 帧标志屏蔽位 #define CAN_FRAME_MASK_SRC 0X0F // 帧源地址屏蔽位 #define CAN_FRAME_MASK_DST 0X0F // 帧目的地址屏蔽位 #define CAN_FRAME_MASK_TYPE 0XFF // 帧类型屏蔽位 #define CAN_FRAME_MASK_PRIOR 0X03 // 帧优先级屏蔽位(帧优先级是帧类型的高2位) #define CAN_FRAME_MASK_LEN 0X0F // 帧长度屏蔽位 // 缓冲区为空 #define CAN_BUF_EMPTY(ring) ((ring)->head == (ring)->tail) // 缓冲区满 #define CAN_BUF_FULL(ring, size) (((unsigned char)((ring)->head - (ring)->tail)) == ((unsigned char)(size - 1))) // 缓冲区剩余空间 #define CAN_BUF_SPACE(ring, size) (((unsigned char)((ring)->tail - (ring)->head) - 1) & (unsigned char)(size - 1)) // 强制中断寄存器 #define REG_MCF_INTFRCL1 (*(volatile unsigned int *)(0xFC04C014)) // 调试开关 // #define CAN_DEBUG #ifdef CAN_DEBUG #define can_printf(x...) rt_printf(x) #else #define can_printf(x...) #endif // 打印报文 #ifdef CAN_DEBUG #define can_print_mem(x...) print_mem_time(x) #else #define can_print_mem(x...) #endif /*------------------------------ 类型结构 ------------------------------------- */ typedef enum { CAN_1, CAN_2, CAN_RES } can_type; // CANFD 基地址 static unsigned int g_rt_canfd_baseaddr[RT_CAN_NUM][RT_CAN_DEV_TYPE] = { {RT_M_CAN0, RT_M_RAM0, RT_M_TOP0, RT_M_DMA0}, {RT_M_CAN1, RT_M_RAM1, RT_M_TOP1, RT_M_DMA1}, {RT_M_CAN2, RT_M_RAM2, RT_M_TOP2, RT_M_DMA2}, {RT_M_CAN3, RT_M_RAM3, RT_M_TOP3, RT_M_DMA3}, }; // 保证所有结构的大小都是4的倍数 // 长帧缓冲区 struct can_longframe_buf { unsigned char head; // 头位置 unsigned char tail; // 尾位置 unsigned char reserverd[2]; unsigned char buf[CAN_LONGFRAME_NUM][CAN_LONGFRAME_LEN]; }; // 缓冲区描述符 struct can_buf { unsigned char head; // 头位置 unsigned char tail; // 尾位置 unsigned char frameno; // 帧序号 unsigned char reserverd; unsigned char buf[CAN_FRAME_NUM][CAN_FRAME_LEN]; }; // CAN统计信息数据结构 struct can_dev_stats { uint32_t rx_shortframes; // 接收短帧数 uint32_t tx_shortframes; // 发送短帧数 uint32_t rx_longframes; // 接收长帧数 uint32_t tx_longframes; // 发送长帧数 uint32_t rx_dropped; // 接收缓冲区满溢出次数 uint32_t tx_dropped; // 发送缓冲区满溢出次数 uint32_t hw_bus_errors; uint32_t overrun; uint32_t max_mbcnt; // 统计最大的未处理的MB个数 uint32_t max_proctime; // 处理MB的最大时间 }; #if 0 //短帧描述符 struct can_shortframe_des { unsigned char info; unsigned char flag1; unsigned char srcaddr; unsigned char dstaddr; unsigned char frameno; unsigned char data[8]; unsigned char reserved[3]; }; #endif // 时间戳差值数据结构 struct can_timestamp { unsigned short timestamp; // 时间戳差值,该差值是指当前时间戳与有数据的MB的时间戳差值 short caniflg_bit; // MB下标即是那一个MB }; // flexcan 设备数据结构 struct can_dev { int can_sock; uint32_t no; uint32_t base_addr; struct can_dev_stats stats; // 网络统计信息 struct can_timestamp ts[CAN_MB]; // 记录各时间戳差值 struct can_buf tx_buf[CAN_PRIO_MAX]; // 发送缓冲区 struct can_buf rx_buf[CAN_PRIO_MAX]; // 接收缓冲区 struct can_longframe_buf longframe_buf_rx[CAN_PRIO_MAX]; // 接收长帧缓冲区 }; /* Message type access macros.*/ #define FLEXCAN_SET_MODE_RETRIES 255 /* Message Buffer 0 configure as Tx */ #define SEND_BUF 15 #define SEND_BUF_BIT (1 << SEND_BUF) /* Structure of the message buffer */ struct can_mb { volatile u32 can_dlc; volatile u32 can_id; u8 data[8]; }; struct can_regs { volatile u32 canmcr; /* FLEXCAN 0x00 */ volatile u32 canctrl; /* FLEXCAN 0x04 */ volatile u32 cantimer; /* FLEXCAN 0x08 */ volatile u32 reserved1; volatile u32 canrxgmsk; /* FLEXCAN 0x10 */ volatile u32 canrx14msk; /* FLEXCAN 0x14 */ volatile u32 canrx15msk; /* FLEXCAN 0x18 */ volatile u32 canerrcnt; /* FLEXCAN 0x1C */ volatile u32 canerrstat; /* FLEXCAN 0x20 */ volatile u32 reserved2; volatile u32 canimask; /* FLEXCAN 0x28 */ volatile u32 reserved3; volatile u32 caniflg; /* FLEXCAN 0x30 */ volatile u32 reserved4[19]; struct can_mb cantxfg[CAN_MB]; volatile u32 reserved5[448]; volatile u32 rximr[CAN_MB]; }; /* @clock_src: 1 = The FLEXCAN clock source is the onchip Bus Clock. 0 = The FLEXCAN clock source is the chip Oscillator Clock.*/ struct can_platform_data { unsigned int clock_src; /* FLEXCAN_CLKSRC_BUS or FLEXCAN_CLKSRC_XTAL */ unsigned int clock_frq; /* can ref. clock, in Hz */ }; /*------------------------------ 全局变量 ------------------------------------- */ // flexcan设备 int g_can_fd = -1; static int bexit = 0; static u8 g_can_tx_call[CAN_BUS_NUM] = {0}; pthread_t can_tid[CAN_BUS_NUM]; pthread_t can_tid_s[CAN_BUS_NUM]; unsigned g_can_mapped_size; void *g_can_map_base[CAN_BUS_NUM], *g_can_virt_addr[CAN_BUS_NUM]; static struct can_dev g_can_dev[CAN_BUS_NUM] __attribute__((aligned(4))); FN_CAN_RECV_CALLBACK g_can_recv_callback; u8 g_app_buf_tx[CAN_PRIO_MAX][CAN_FRAME_LEN_MAX]; // 应用可根据优先级申请的长帧缓冲区 extern int g_print_can; extern int g_print_can_monitor; /*------------------------------ 函数声明 ------------------------------------- */ static void can_soft_recv_data(int sock); static int _can_set_reset_mode(struct can_dev *dev); static int _can_set_normal_mode(struct can_dev *dev); static int _can_set_bittiming(struct can_dev *dev); static void _can_chipset_init(struct can_dev *dev, int clock_src); static void _can_app_tx(int _no); static void _can_app_rx(struct can_dev *dev, struct can_frame *frame); void _can_isr_0(void); void _can_isr_1(void); void _can_isr_err_0(void); void _can_isr_err_1(void); int _can_irq_force(int no); int _can_irq_clear(int no); int _can_irq_is_force(int no); /*------------------------------ 内部函数 ------------------------------------- */ static int can_soft_send(int sock, struct can_frame frame) { int nbytes; int wlen = sizeof(struct can_frame); int times = 2; while (times--) { nbytes = write(sock, &frame, wlen); if (nbytes != wlen) { // rt_printf("Send Error frame(nbytes:%d, wlen:%d)\n", nbytes, wlen); usleep(200); continue; } else { // printf("Send frame(nbytes:%d, wlen:%d)\n", nbytes, wlen); return (0); } } return -1; } static int can_send_data(can_type type, unsigned char *buf, int len) { int i, j; int cnt; int sock; int ret = 0; struct can_frame frame; if (type == CAN_1) { // DEMO sock = g_can_dev[0].can_sock; frame.can_id = 0x100; } else { // DEMO sock = g_can_dev[1].can_sock; frame.can_id = 0x101; } for (i = 0; i < len; i += 8) { cnt = len - i; if (cnt > 8) frame.can_dlc = 8; else frame.can_dlc = cnt; for (j = 0; j < frame.can_dlc; j++) { frame.data[j] = buf[i + j]; } if (can_soft_send(sock, frame) < 0) { ret = -1; break; } } return ret; } static void *can_proc_send(void *arg) { int sock = *(int *)arg; int index = g_can_dev[0].can_sock == sock ? 0 : 1; if (index == 0) { prctl(PR_SET_NAME, "can_send_func0"); } else { prctl(PR_SET_NAME, "can_send_func1"); } while (!bexit) { if (main_mod_is_exit()) { break; } switch (index) { case 0: // can_send_data(CAN_1, (unsigned char *)"hello stm32", strlen("hello stm32") - 1); _can_app_tx(0); break; case 1: _can_app_tx(1); // can_send_data(CAN_2, (unsigned char *)"hello stm32", strlen("hello stm32") - 1); break; default: break; } // xenomai内核中此处usleep(10)创建第二个线程会出问题 // 延时太短导致CPU占用?改为1ms就正常了需验证动作时间 usleep(1000); } } static void *can_proc_recv(void *arg) { int nready; int maxfd; fd_set readfds; int sock = *(int *)arg; FD_ZERO(&readfds); FD_SET(sock, &readfds); maxfd = sock; int index = g_can_dev[0].can_sock == sock ? 0 : 1; if (index == 0) { prctl(PR_SET_NAME, "can_rev_func0"); } else { prctl(PR_SET_NAME, "can_rev_func1"); } while (!bexit) { if (main_mod_is_exit()) { break; } nready = select(maxfd + 1, &readfds, NULL, NULL, NULL); if (nready < 0) { perror("can select"); break; } else if (nready == 0) { continue; } /* data is ready */ if (FD_ISSET(sock, &readfds)) { can_soft_recv_data(sock); } else { ; } } } static int can_open(char *can_name) { struct ifreq ifr; struct sockaddr_can addr; int sock; int ret = -1; int loopback = 0; // struct can_filter rfilter[1]; /* open socket */ sock = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (sock < 0) { return ret; } strcpy(ifr.ifr_name, can_name); if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) { goto err_can_open; } addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; // fcntl(sock, F_SETFL, O_NONBLOCK); if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { goto err_can_open; } // close loopback setsockopt(sock, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback)); /* rfilter[0].can_id = 0x12; rfilter[0].can_mask = CAN_SFF_MASK; setsockopt(sock, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); */ return sock; err_can_open: close(sock); return ret; } static int can_soft_recv(int sock, struct can_frame *frame) { int nbytes; nbytes = read(sock, frame, sizeof(struct can_frame)); if (nbytes) { ; // printf("[can_recv]dlc = %d, nbytes = %d\n", frame->can_dlc, nbytes); } return nbytes; } static void can_soft_recv_data(int sock) { static unsigned char tail = 0; int i; int can_id; unsigned char can_dlc; unsigned char *data; struct can_frame frame; int index = g_can_dev[0].can_sock == sock ? 0 : 1; if (can_soft_recv(sock, &frame) < 0) return; frame.can_id = frame.can_id & CAN_EFF_MASK; can_dlc = frame.can_dlc; data = frame.data; // printf("CAN%d dlc = %d, can_id = %x\ndata:", index,frame.can_dlc, frame.can_id); // for(i=0; i page_size) { /* This access spans pages. * Must map two pages to make it possible: */ g_can_mapped_size *= 2; } g_can_fd = open("/dev/mem", O_RDWR | O_SYNC); if (g_can_fd < 0) { printf("open(/dev/mem) failed.\n"); return -1; } fflush(stdout); // 初始化缓冲区 memset(g_can_dev, 0, sizeof(g_can_dev)); for (i = 0; i < CAN_BUS_NUM; i++) { dev = &g_can_dev[i]; dev->no = i; target = g_rt_canfd_baseaddr[i][0]; if (i == 0) { /* CAN0 */ g_can_map_base[i] = mmap(NULL, g_can_mapped_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_can_fd, target & ~(off_t)(page_size - 1)); if (g_can_map_base[i] == (void *)-1) { printf("can[%d] dev null pointer!\n", i); } else { printf("BSP can[%d] map Successfull!\n", i); } fflush(stdout); dev->base_addr = g_can_map_base[i]; } else { /* CAN1 */ g_can_map_base[i] = mmap(NULL, g_can_mapped_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_can_fd, target & ~(off_t)(page_size - 1)); if (g_can_map_base[i] == (void *)-1) { printf("can[%d] dev null pointer!\n", i); } else { printf("BSP can[%d] map Successfull!\n", i); } fflush(stdout); dev->base_addr = g_can_map_base[i]; } /* set chip into reset mode */ _can_set_reset_mode(dev); _can_set_bittiming(dev); // 申请实时中断 if (i == 0) { rt_request_irq(CFG_CAN_VECTOR_BEGIN + 0, CFG_INT_LEVEL_CAN, _can_isr_0, "can_isr_0"); rt_request_irq(CFG_CAN_VECTOR_BEGIN + 1, CFG_INT_LEVEL_CAN, _can_isr_err_0, "can_isr_err_00"); rt_request_irq(CFG_CAN_VECTOR_BEGIN + 3, CFG_INT_LEVEL_CAN, _can_isr_err_0, "can_isr_err_01"); } else { rt_request_irq(CFG_CAN_VECTOR_BEGIN + 4, CFG_INT_LEVEL_CAN, _can_isr_1, "can_isr_1"); rt_request_irq(CFG_CAN_VECTOR_BEGIN + 5, CFG_INT_LEVEL_CAN, _can_isr_err_1, "can_isr_err_10"); rt_request_irq(CFG_CAN_VECTOR_BEGIN + 7, CFG_INT_LEVEL_CAN, _can_isr_err_1, "can_isr_err_11"); } // 获取CAN设备句柄 if (i == 0) { g_can_dev[i].can_sock = can_open("can0"); } else { g_can_dev[i].can_sock = can_open("can1"); } // 创建CAN设备接收线程 if (0 != pthread_create(&can_tid[i], NULL, can_proc_recv, (void *)&g_can_dev[i].can_sock)) { return -2; } // 创建CAN设备发送线程 if (0 != pthread_create(&can_tid_s[i], NULL, can_proc_send, (void *)&g_can_dev[i].can_sock)) { return -3; } /* init and start flexcan */ _can_chipset_init(dev, 0); _can_set_normal_mode(dev); } return 0; } int can_exit(void) { int i = 0; // exit can recv thread bexit = 1; for (i = 0; i < CAN_BUS_NUM; i++) { pthread_join(can_tid[i], NULL); pthread_join(can_tid_s[i], NULL); if (g_can_map_base[i]) { if (munmap(g_can_map_base, g_can_mapped_size) == -1) { printf("can[%d] dev munmap failed!", i); return -1; } } if (g_can_dev[i].can_sock >= 0) { close(g_can_dev[i].can_sock); } } if (g_can_fd >= 0) { close(g_can_fd); g_can_fd = -1; } rt_free_irq(CFG_CAN_VECTOR_BEGIN + 0); rt_free_irq(CFG_CAN_VECTOR_BEGIN + 1); rt_free_irq(CFG_CAN_VECTOR_BEGIN + 3); rt_free_irq(CFG_CAN_VECTOR_BEGIN + 4); rt_free_irq(CFG_CAN_VECTOR_BEGIN + 5); rt_free_irq(CFG_CAN_VECTOR_BEGIN + 7); pthread_mutex_destroy(&printf_mutex); return 0; } int can_regester_recv_callback(FN_CAN_RECV_CALLBACK fn) { g_can_recv_callback = fn; return 0; } u8 *can_request_tx_buf(u8 type) { int prior; // 提取优先级 prior = (type >> 6) & CAN_FRAME_MASK_PRIOR; return g_app_buf_tx[prior]; } int can_send(u32 no, u8 *buf) { struct can_dev *dev; struct can_mb *pfm; int i, sf_num, sf_len; int frame_mark; // 帧标识 unsigned char prior; // 应用优先级 unsigned char *p; u32 len; // 检查参数 if (no >= CAN_BUS_NUM) { return -1; } if (buf == NULL) { return -2; } // 检查地址 if (buf[1] >= CAN_BUS_ADDR_NUM || buf[2] >= CAN_BUS_ADDR_NUM) { return -5; } // 检查长度 len = buf[3]; if (len > CAN_LONGFRAME_DATA_LEN) { return -6; } dev = &g_can_dev[no]; // 提取优先级 prior = (buf[0] >> 6) & CAN_FRAME_MASK_PRIOR; // 将长帧转换为短帧 // 计算需要分为多少帧短帧 sf_num = (len + CAN_FRAME_DATA_LEN - 1) / CAN_FRAME_DATA_LEN; if (sf_num == 0) { sf_num = 1; } // 空间够吗? if (CAN_BUF_SPACE(&dev->tx_buf[prior], CAN_FRAME_NUM) < sf_num) { // 发送溢出次数 dev->stats.tx_dropped++; return -7; } // 打印报文 if (g_print_can) { print_msg("TX_CAN:", buf, len + CAN_LONGFRAME_HEAD_LEN); } // 帧序号递加 dev->tx_buf[prior].frameno++; i = 0; p = buf + CAN_LONGFRAME_HEAD_LEN; while (i < sf_num) { // 短帧数据长度 sf_len = len >= CAN_FRAME_DATA_LEN ? CAN_FRAME_DATA_LEN : len; // 帧标识 if (sf_num == 1) { frame_mark = CAN_FRAME_SINGLE; } else { if (i == 0) { frame_mark = CAN_FRAME_BEGIN; } else if (i == (sf_num - 1)) { frame_mark = CAN_FRAME_END; } else { frame_mark = CAN_FRAME_MIDDLE; } } // 指向当前头位置缓冲区 pfm = (struct can_mb *)dev->tx_buf[prior].buf[dev->tx_buf[prior].head]; // 结构信息 pfm->can_dlc = sf_len; // MB_CNT_CODE(0x08)|(1 << 21)|(1 << 22)|(sf_len << 16) // 帧ID pfm->can_id = (buf[0] << CAN_FRAME_OFFSET_TYPE) | (buf[1] << CAN_FRAME_OFFSET_DST) | (buf[2] << CAN_FRAME_OFFSET_SRC) | (frame_mark << CAN_FRAME_OFFSET_MARK) | (dev->tx_buf[prior].frameno & CAN_FRAME_MASK_SN); // 数据 memcpy(pfm->data, p, sf_len); len -= sf_len; // 剩余多少数据 p += sf_len; // 调整数据指针 // 头下标往后移 dev->tx_buf[prior].head++; // 下一短帧 i++; } // 统计发送长帧 dev->stats.tx_longframes++; // 启动发送 _can_irq_force(no); return (buf[3] + CAN_LONGFRAME_HEAD_LEN); } int can_recv(u32 no, u8 *buf, u32 len) { struct can_dev *dev; int i; int framelen; // 检查参数 if (no >= CAN_BUS_NUM) { return -1; } if (buf == NULL) { return -2; } dev = &g_can_dev[no]; // 从0优先级开始,读取接收缓冲区的数据 for (i = 0; i < CAN_PRIO_MAX; i++) { // 对应的长帧缓冲区没有长帧 if (CAN_BUF_EMPTY(&dev->longframe_buf_rx[i])) continue; // 长帧长度 framelen = dev->longframe_buf_rx[i].buf[dev->longframe_buf_rx[i].tail][CAN_LONGFRAME_HEAD_LEN - 1] + CAN_LONGFRAME_HEAD_LEN; // 拷贝数据到用户空间 if (framelen <= len) { memcpy(buf, dev->longframe_buf_rx[i].buf[dev->longframe_buf_rx[i].tail], framelen); // 调整尾位置 dev->longframe_buf_rx[i].tail = (dev->longframe_buf_rx[i].tail + 1) & (CAN_LONGFRAME_NUM - 1); } else { rt_printf("can_recv:framelen=%d, len=%d\r\n", framelen, len); framelen = -3; } return framelen; } return 0; } int can_stat(void) { int i = 0; rt_printf("flexcan communicate stat\r\n"); for (i = 0; i < CAN_BUS_NUM; i++) { rt_printf("flexcan%d:\r\n", i); rt_printf("tx_longframes:\t%u\r\n", g_can_dev[i].stats.tx_longframes); rt_printf("rx_longframes:\t%u\r\n", g_can_dev[i].stats.rx_longframes); rt_printf("tx_shortframes:\t%u\r\n", g_can_dev[i].stats.tx_shortframes); rt_printf("rx_shortframes:\t%u\r\n", g_can_dev[i].stats.rx_shortframes); rt_printf("tx_dropped:\t%u\r\n", g_can_dev[i].stats.tx_dropped); rt_printf("rx_dropped:\t%u\r\n", g_can_dev[i].stats.rx_dropped); rt_printf("hw_bus_errors:\t%u\r\n", g_can_dev[i].stats.hw_bus_errors); rt_printf("overrun:\t%u\r\n", g_can_dev[i].stats.overrun); } return 0; } int can_stat_reset(void) { int i = 0; for (i = 0; i < CAN_BUS_NUM; i++) { memset(&g_can_dev[i].stats, 0, sizeof(g_can_dev[i].stats)); } return 0; } /*------------------------------ 内部函数 ------------------------------------- 内部函数以下划线‘_’开头,不需要检查参数的合法性. */ /****************************************************************************** 函数名称: _can_set_reset_mode 函数版本: 01.01 创建作者: xxxxxx 创建日期: 2010-09-25 函数说明: 复位FLEXCAN 参数说明: dev: flexcan 设备 返回值:成功返回0,失败返回1 修改记录: */ static int _can_set_reset_mode(struct can_dev *dev) { return 1; } /****************************************************************************** 函数名称: _can_set_normal_mode 函数版本: 01.01 创建作者: xxxxxx 创建日期: 2010-09-25 函数说明: 设置正常模式 参数说明: dev: flexcan 设备 返回值:成功返回0,失败返回1 修改记录: */ static int _can_set_normal_mode(struct can_dev *dev) { return 1; } /****************************************************************************** 函数名称: _can_set_bittiming 函数版本: 01.01 创建作者: xxxxxx 创建日期: 2010-09-25 函数说明: 波特率设置函数 使用外部晶振50M 配置为500K: reg = CANCTRL_PRESDIV(9) | CANCTRL_RJW(0); reg |= (CANCTRL_PROPSEG(2) | CANCTRL_PSEG1(3) | CANCTRL_PSEG2(1) | CANCTRL_SAMP(0)); regs->canctrl |= reg; 配置为1M: reg = CANCTRL_PRESDIV(4) | CANCTRL_RJW(0); reg |= (CANCTRL_PROPSEG(3) | CANCTRL_PSEG1(2) | CANCTRL_PSEG2(1) | CANCTRL_SAMP(0)); regs->canctrl |= reg; 参数说明: dev: flexcan 设备 返回值: 返回0 修改记录: */ static int _can_set_bittiming(struct can_dev *dev) { /* Clear the old bittiming */ char cmd_buf[256] = {0x00}; sprintf(cmd_buf, "ip link set can%d down", dev->no); system(cmd_buf); /* 设置队列宽度 */ memset(cmd_buf, 0, sizeof(cmd_buf)); sprintf(cmd_buf, "ip link set can%d qlen %d", dev->no, 100); system(cmd_buf); /* 配置波特率为1M */ memset(cmd_buf, 0, sizeof(cmd_buf)); sprintf(cmd_buf, "ip link set can%d type can bitrate %d loopback off restart-ms %d", dev->no, 1000000, 100); system(cmd_buf); /* 启动can设备 */ memset(cmd_buf, 0, sizeof(cmd_buf)); sprintf(cmd_buf, "ip link set can%d up", dev->no); system(cmd_buf); return 0; } /****************************************************************************** 函数名称: _can_chipset_init 函数版本: 01.01 创建作者: xxxxxx 创建日期: 2010-09-25 函数说明: 初始化flexcan 参数说明: dev: flexcan 设备 clock_src: 时钟源,0表示外部晶振,1表示内部总线时钟 返回值: 修改记录: */ /* * initialize flexcan: * - set clock source * - set output mode * - set baudrate * - enable interrupts * - start operating mode */ static void _can_chipset_init(struct can_dev *dev, int clock_src) { } static void _can_app_tx(int _no) { int sock; int i = 0; struct can_mb *pfm; struct can_frame frame; struct can_dev *dev = &g_can_dev[_no]; // if(g_can_tx_call[_no] == 0) // return; // g_can_tx_call[_no] = 0; for (i = 0; i < CAN_PRIO_MAX; i++) { // 对应优先级的缓冲区是否有数据 if (CAN_BUF_EMPTY(&dev->tx_buf[i])) { continue; } // 当前位置的缓冲区 pfm = (struct can_mb *)dev->tx_buf[i].buf[dev->tx_buf[i].tail]; frame.can_id = pfm->can_id | CAN_EFF_FLAG; // 使用扩展帧ID frame.can_dlc = pfm->can_dlc; memcpy(frame.data, pfm->data, sizeof(frame.data)); sock = g_can_dev[_no].can_sock; if (can_soft_send(sock, frame) < 0) { rt_printf("%s send err!\r\n", __func__); break; } // 调整尾指针 dev->tx_buf[i].tail++; // 统计发送短帧总数加一 dev->stats.tx_shortframes++; } } /****************************************************************************** 函数名称: _can_int_tx 函数版本: 01.01 创建作者: xxxxxx 创建日期: 2010-09-25 函数说明: flexcan发送处理 参数说明: dev: flexcan 设备 返回值: 修改记录: */ static void _can_int_tx(struct can_dev *dev) { int i = 0; struct can_mb *pfm; int txbuf = SEND_BUF; volatile struct can_regs *regs = (volatile struct can_regs *)dev->base_addr; for (i = 0; i < CAN_PRIO_MAX; i++) { int j = 0; unsigned int code = 0; // 对应优先级的缓冲区是否有数据 if (CAN_BUF_EMPTY(&dev->tx_buf[i])) { continue; } // 当前位置的缓冲区 pfm = (struct can_mb *)dev->tx_buf[i].buf[dev->tx_buf[i].tail]; // 检查是否可以发送. code==8说明上一次成功发送完毕,code==0是第一次将CODE配置0了即是MB_CNT_CODE(0) code = (regs->cantxfg[txbuf].can_dlc >> 24) & 0x0F; if (!((code == 8) || (code == 0))) { // rt_printf("bus is busy\r\n"); break; } // 写数据到寄存器 regs->cantxfg[txbuf].can_dlc = pfm->can_dlc; regs->cantxfg[txbuf].can_id = pfm->can_id; for (j = 0; j < 8; j++) { regs->cantxfg[txbuf].data[j] = pfm->data[j]; } /*Control/status word to hold Tx MB active */ regs->cantxfg[txbuf].can_dlc |= MB_CNT_CODE(0x0c); // 调整尾指针 dev->tx_buf[i].tail++; // 统计发送短帧总数加一 dev->stats.tx_shortframes++; break; } } /****************************************************************************** 函数名称: _can_frame_short2long 函数版本: 01.01 创建作者: xxxxxx 创建日期: 2010-09-25 函数说明: 短帧组长帧 参数说明: dev: flexcan 设备 prior: 优先级 返回值: 修改记录: */ static int _can_frame_short2long(struct can_dev *dev, int prior) { static unsigned char pos_rec[CAN_FRAME_NUM]; int pos_index; int i, len, is_deal; struct can_mb *pfm; struct can_mb *pfmtmp; unsigned char *pd, *p; unsigned char tmppos = dev->rx_buf[prior].head - 1; unsigned char srcaddr; unsigned char dstaddr; unsigned char frameno; unsigned char frame_type; unsigned char frame_len; unsigned int frame_mark; unsigned char srcaddrtmp; unsigned char dstaddrtmp; unsigned char framenotmp; unsigned char frame_type_tmp; // 结束帧指针 pfm = (struct can_mb *)dev->rx_buf[prior].buf[tmppos]; srcaddr = (pfm->can_id >> CAN_FRAME_OFFSET_SRC) & CAN_FRAME_MASK_SRC; dstaddr = (pfm->can_id >> CAN_FRAME_OFFSET_DST) & CAN_FRAME_MASK_DST; frameno = pfm->can_id & CAN_FRAME_MASK_SN; frame_type = (unsigned char)(pfm->can_id >> CAN_FRAME_OFFSET_TYPE) & CAN_FRAME_MASK_TYPE; frame_len = pfm->can_dlc & CAN_FRAME_MASK_LEN; //(pfm->can_dlc >> CAN_FRAME_OFFSET_LEN) & CAN_FRAME_MASK_LEN; // 查找起始帧 pos_index = 0; for (i = 0; i < CAN_FRAME_NUM; i++) { // 短帧 pfmtmp = (struct can_mb *)dev->rx_buf[prior].buf[tmppos]; frame_mark = (pfmtmp->can_id >> CAN_FRAME_OFFSET_MARK) & CAN_FRAME_MASK_MARK; srcaddrtmp = (pfmtmp->can_id >> CAN_FRAME_OFFSET_SRC) & CAN_FRAME_MASK_SRC; dstaddrtmp = (pfmtmp->can_id >> CAN_FRAME_OFFSET_DST) & CAN_FRAME_MASK_DST; framenotmp = pfmtmp->can_id & CAN_FRAME_MASK_SN; frame_type_tmp = (unsigned char)(pfmtmp->can_id >> CAN_FRAME_OFFSET_TYPE) & CAN_FRAME_MASK_TYPE; // 是要找的短帧 if ((srcaddr == srcaddrtmp) && (dstaddr == dstaddrtmp) && (frameno == framenotmp) && (frame_type == frame_type_tmp)) { // 记录短帧位置 pos_rec[pos_index++] = tmppos; // 找到起始帧 if ((frame_mark == CAN_FRAME_BEGIN) || (frame_mark == CAN_FRAME_SINGLE)) { break; } } // 前一短帧 tmppos--; } if (pos_index == 0) { rt_printf("_can_frame_short2long:pos_index=%d\r\n", pos_index); dev->stats.rx_dropped++; return -1; } if (i == CAN_FRAME_NUM) { #if 0 rt_printf("_can_frame_short2long:i=%d,pos_index=%d.\r\n",i,pos_index); #endif dev->stats.rx_dropped++; return -11; } // 检查长度 len = frame_len + (pos_index - 1) * CAN_FRAME_DATA_LEN; if (len > CAN_LONGFRAME_DATA_LEN) { rt_printf("_can_frame_short2long:i=%d\r\n", i); dev->stats.rx_dropped++; return -2; } // 长帧缓冲区首指针 pd = dev->longframe_buf_rx[prior].buf[dev->longframe_buf_rx[prior].head]; p = pd; // 长帧头 p[0] = (pfmtmp->can_id >> CAN_FRAME_OFFSET_TYPE); p[1] = dstaddrtmp; p[2] = srcaddrtmp; p[3] = len; // 长帧数据 p += CAN_LONGFRAME_HEAD_LEN; while (pos_index--) { len = pos_index == 0 ? frame_len : 8; pfmtmp = (struct can_mb *)dev->rx_buf[prior].buf[pos_rec[pos_index]]; memcpy(p, pfmtmp->data, len); // 置帧空标志 pfmtmp->can_dlc = 0; p += 8; } // 打印报文 if (g_print_can) { print_msg("RX_CAN:", pd, pd[3] + CAN_LONGFRAME_HEAD_LEN); } // 回调处理此长帧 is_deal = 0; if (g_can_recv_callback) { is_deal = g_can_recv_callback(dev->no, pd); } // 如果此长帧没有处理,调整头位置 if (is_deal != 1) { if (CAN_BUF_SPACE(&dev->longframe_buf_rx[prior], CAN_LONGFRAME_NUM) == 0) { dev->stats.rx_dropped++; rt_printf("长帧溢出\r\n"); } else { dev->longframe_buf_rx[prior].head = (dev->longframe_buf_rx[prior].head + 1) & (CAN_LONGFRAME_NUM - 1); } // 唤醒主循环处理此长帧 mainloop_wakeup(); } return 0; } /****************************************************************************** 函数名称: _can_int_rx 函数版本: 01.01 创建作者: xxxxxx 创建日期: 2010-09-25 函数说明: flexcan接收中断处理 参数说明: dev: flexcan 设备 i: 表示第几个接收MB 返回值: 修改记录: */ void _can_bus_monitor(u8 *buf) { static s8 str[128]; s8 *p; int i; sprintf(str, "CAN_RS:"); p = str + 7; for (i = 0; i < 16; i++) { sprintf(p, "%02x ", buf[i]); p += 3; } sprintf(p, "\r\n"); rt_printf(str); } static void _can_app_rx(struct can_dev *dev, struct can_frame *frame) { struct can_mb *pfm; int ctrl = frame->can_dlc; int canid = frame->can_id; u32 prior = (canid >> CAN_FRAME_OFFSET_PRIOR) & 0x03; u32 srcaddr = (canid >> CAN_FRAME_OFFSET_SRC) & CAN_FRAME_MASK_SRC; int k; // 取短帧BUF pfm = (struct can_mb *)dev->rx_buf[prior].buf[dev->rx_buf[prior].head]; if (pfm->can_dlc) { #if 0 print_mem("CAN_BUF_FULL: ",(u8*)pfm,16); #endif dev->stats.overrun++; } // 得到内容 pfm->can_dlc = ctrl; pfm->can_id = frame->can_id; for (k = 0; k < 8; k++) pfm->data[k] = frame->data[k]; // 如果总线监视,打印短帧 if (g_print_can_monitor) { _can_bus_monitor((u8 *)pfm); } // 如果是自己发送的帧,直接返回 if (srcaddr == 0) { // 置帧空标志 pfm->can_dlc = 0; return; } // 统计接收短帧总数 dev->stats.rx_shortframes++; // 调整当前位置 dev->rx_buf[prior].head++; // 是结束帧就开始组长帧 if (((canid >> CAN_FRAME_OFFSET_MARK) & CAN_FRAME_MASK_MARK) < 0x02) { // 统计接收长帧总数 dev->stats.rx_longframes++; // 短帧组长帧 _can_frame_short2long(dev, prior); } } static void _can_int_rx(struct can_dev *dev, int i) { volatile struct can_regs *regs = (volatile struct can_regs *)dev->base_addr; struct can_mb *mb = (struct can_mb *)®s->cantxfg[i]; struct can_mb *pfm; int ctrl = mb->can_dlc; int canid = mb->can_id; u32 prior = (canid >> CAN_FRAME_OFFSET_PRIOR) & 0x03; u32 srcaddr = (canid >> CAN_FRAME_OFFSET_SRC) & CAN_FRAME_MASK_SRC; int k; // 取短帧BUF pfm = (struct can_mb *)dev->rx_buf[prior].buf[dev->rx_buf[prior].head]; if (pfm->can_dlc) { #if 0 print_mem("CAN_BUF_FULL: ",(u8*)pfm,16); #endif dev->stats.overrun++; } // 得到内容 pfm->can_dlc = ctrl; pfm->can_id = mb->can_id; for (k = 0; k < 8; k++) pfm->data[k] = regs->cantxfg[i].data[k]; // 如果总线监视,打印短帧 if (g_print_can_monitor) { _can_bus_monitor((u8 *)pfm); } // 如果是自己发送的帧,直接返回 if (srcaddr == 0) { // 置帧空标志 pfm->can_dlc = 0; return; } // 统计接收短帧总数 dev->stats.rx_shortframes++; // 调整当前位置 dev->rx_buf[prior].head++; // 是结束帧就开始组长帧 if (((canid >> CAN_FRAME_OFFSET_MARK) & CAN_FRAME_MASK_MARK) < 0x02) { // 统计接收长帧总数 dev->stats.rx_longframes++; // 短帧组长帧 _can_frame_short2long(dev, prior); } } void _can_isr(int no) { struct can_dev *dev = &g_can_dev[no]; volatile struct can_regs *regs = (volatile struct can_regs *)dev->base_addr; u32 oflags; // 得到中断标志 oflags = regs->caniflg; // 处理发送软中断 if (_can_irq_is_force(no)) { // 应用程序启动发送 oflags |= SEND_BUF_BIT; _can_irq_clear(no); } // 检查发送标志 if (oflags & SEND_BUF_BIT) { // 清发送中断 regs->caniflg = SEND_BUF_BIT; oflags &= (~SEND_BUF_BIT); // 发送一帧 _can_int_tx(dev); } // 处理接收中断 // 硬件overrun if (oflags & 0x80) { dev->stats.overrun++; } // 接收一帧 if (oflags & 0x20) { _can_int_rx(dev, 0); } // 清接收中断标志 regs->caniflg = oflags; return; } void _can_isr_err(int no) { struct can_dev *dev = &g_can_dev[no]; volatile struct can_regs *regs = (struct can_regs *)dev->base_addr; u32 errstate = regs->canerrstat; regs->canerrstat = errstate; dev->stats.hw_bus_errors++; // 统计出错信息 return; } void _can_isr_0(void) { _can_isr(0); } void _can_isr_1(void) { _can_isr(1); } void _can_isr_err_0(void) { _can_isr_err(0); } void _can_isr_err_1(void) { _can_isr_err(1); } int _can_irq_force(int no) { #ifdef __KERNEL__ uint32_t flags; no *= 4; rt_irq_save(flags); REG_MCF_INTFRCL1 |= 1 << no; rt_irq_restore(flags); #else g_can_tx_call[no] = 1; #endif return 0; } int _can_irq_clear(int no) { uint32_t flags; no *= 4; rt_irq_save(flags); REG_MCF_INTFRCL1 &= ~(1 << no); rt_irq_restore(flags); return 0; } int _can_irq_is_force(int no) { no *= 4; if (REG_MCF_INTFRCL1 & (1 << no)) { return 1; } else { return 0; } } /*------------------------------ 测试函数 ------------------------------------- 一个实体文件必须带一个本模块的测试函数来进行单元测试,如果的确不方便在本模块中 进行单元测试,必须在此注明实际的测试位置(例如在哪个实体文件中使用哪个测试函数). */ #define LOOP_BEGIN 1 int can_test(void) { static unsigned char buf_tx[CAN_LONGFRAME_LEN], buf_rx[CAN_LONGFRAME_LEN]; static unsigned char loop = LOOP_BEGIN; static uint32_t us0 = 0, err_count = 0; uint32_t us1; int i; int len_tx, len_rx; // 1S调用一次 us1 = ustimer_get_origin(); if (us1 - us0 < USTIMER_SEC * 10) { return 0; } us0 = us1; // 发送一帧 memset(buf_tx, 0, sizeof(buf_tx)); buf_tx[0] = loop; buf_tx[1] = 1; buf_tx[2] = 2; buf_tx[3] = loop; for (i = 0; i < buf_tx[3]; i++) { buf_tx[CAN_LONGFRAME_HEAD_LEN + i] = i; } len_tx = can_send(0, buf_tx); // len_tx = can_send(1,buf_tx); // 延时5ms ustimer_delay(USTIMER_MS * 50); // 接收一帧 memset(buf_rx, 0, sizeof(buf_rx)); len_rx = can_recv(0, buf_rx, 256); if ((len_tx == len_rx) && (memcmp(buf_tx, buf_rx, len_tx) == 0)) { rt_printf("can_test ok(%03d,err_count=%d):[len_tx=%d,len_rx=%d]\r\n", loop, err_count, len_tx, len_rx); } else { err_count++; rt_printf("can_test err(%03d,err_count=%d):[len_tx=%d,len_rx=%d]\r\n", loop, err_count, len_tx, len_rx); // can_print_mem("TX:",buf_tx,len_tx); // can_print_mem("RX:",buf_rx,len_rx); } // loop++; if (loop > CAN_LONGFRAME_DATA_LEN) { loop = LOOP_BEGIN; } return 0; } #endif /*------------------------------ 文件结束 ------------------------------------- */