/****************************************************************************** 版权所有: 文件名称: 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< 8) frame.can_dlc = 8; else frame.can_dlc = cnt; for(j=0; j= 5000) { cycle = 0; switch (index) { case 0: can_send_data(CAN_1, (unsigned char *)"hello stm32", strlen("hello stm32") - 1); break; case 1: can_send_data(CAN_2, (unsigned char *)"hello stm32", strlen("hello stm32") - 1); break; default: break; } } 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 ; can_id = frame.can_id; 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; ino = 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); 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=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=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;ilongframe_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;icanctrl |= 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, 10); 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) { #endif } /****************************************************************************** 函数名称: _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;itx_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_OFFSET_LEN) & CAN_FRAME_MASK_LEN; // 查找起始帧 pos_index = 0; for(i=0;irx_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_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 CAN_LONGFRAME_DATA_LEN) { loop = LOOP_BEGIN; } return 0; } /*------------------------------ 文件结束 ------------------------------------- */