📄 s3c44b0-mcp2510.c
字号:
* nbuffer为第几个缓冲区可以为3或者4 ** CanData为CAN数据结构 *\***********************************************************/static void MCP2510_Read_Can(unsigned char nbuffer, PCanData candata){ unsigned char mcp_addr = (nbuffer<<4) + 0x31, ctrl; int IsExt; char dlc; IsExt=MCP2510_Read_Can_ID( mcp_addr, &(candata->id)); ctrl=MCP2510_Read(mcp_addr-1); dlc=MCP2510_Read( mcp_addr+4); if ((ctrl & 0x08)) { candata->rxRTR = TRUE; } else{ candata->rxRTR = FALSE; } dlc &= DLC_MASK; MCP2510_SRead(mcp_addr+5, candata->data, dlc); candata->dlc=dlc;}/*******************************************\* 设置MCP2510 CAN总线ID ** 参数: address为MCP2510寄存器地址** can_id为设置的ID值 ** IsExt表示是否为扩展ID *\*******************************************/static void MCP2510_Write_Can_ID(int address, __u32 can_id, int IsExt){ __u32 tbufdata; if (IsExt) { can_id&=0x1fffffff; //29位 tbufdata=can_id &0xffff; tbufdata<<=16; tbufdata|=((can_id>>(18-5))&(~0x1f)); tbufdata |= TXB_EXIDE_M; } else{ can_id&=0x7ff; //11位 tbufdata= (can_id>>3)|((can_id&0x7)<<13); } MCP2510_Swrite(address, (unsigned char*)&tbufdata, 4); MCP2510_Read_Can_ID(address, &tbufdata); DPRINTK("write can id=%x, result id=%x\n",can_id, tbufdata);}/***********************************************************\* 写入MCP2510 发送的数据 ** 参数: ** nbuffer为第几个缓冲区可以为0、1、2 ** CanData为CAN数据结构 *\***********************************************************/static void MCP2510_Write_Can( unsigned char nbuffer, PCanData candata){ unsigned char dlc; unsigned char mcp_addr = (nbuffer<<4) + 0x31; dlc=candata->dlc; MCP2510_Swrite(mcp_addr+5, candata->data, dlc); // write data bytes MCP2510_Write_Can_ID( mcp_addr, candata->id,candata->IsExt); // write CAN id if (candata->rxRTR) dlc |= RTR_MASK; // if RTR set bit in byte MCP2510_Write((mcp_addr+4), dlc); // write the RTR and DLC}/***********************************************************\* write and send Can data ** we must set can id first. ** parament: ** nbuffer: which buffer, should be: 0, 1, 2 ** pbuffer: send data ** nbuffer: size of data *\***********************************************************/static void MCP2510_Write_CanData( unsigned char nbuffer, char *pbuffer, int nsize){ unsigned char dlc; unsigned char mcp_addr = (nbuffer<<4) + 0x31; dlc=nsize&DLC_MASK; //nbuffer must <= 8 MCP2510_Swrite(mcp_addr+5, pbuffer, dlc); // write data bytes MCP2510_Write((mcp_addr+4), dlc); // write the RTR and DLC}/***********************************************************\* write and send Remote Can Frame ** we must set can id first. ** parament: ** nbuffer: which buffer, should be: 0, 1, 2 *\***********************************************************/static void MCP2510_Write_CanRTR( unsigned char nbuffer){ unsigned char dlc=0; unsigned char mcp_addr = (nbuffer<<4) + 0x31; dlc |= RTR_MASK; // if RTR set bit in byte MCP2510_Write((mcp_addr+4), dlc); // write the RTR and DLC}// Setup the CAN buffers used by the application.// We currently use only one for reception and one for transmission.// It is possible to use several to get a simple form of queue.//// We setup the unit to receive all CAN messages.// As we only have at most 4 different messages to receive, we could use the// filters to select them for us.//// mcp_init() should already have been called.static void MCP2510_Setup(PCanFilter pfilter){ // As no filters are active, all messages will be stored in RXB0 only if // no roll-over is active. We want to recieve all CAN messages (standard and extended) // (RXM<1:0> = 11). //SPI_mcp_write_bits(RXB0CTRL, RXB_RX_ANY, 0xFF); //SPI_mcp_write_bits(RXB1CTRL, RXB_RX_ANY, 0xFF); // But there is a bug in the chip, so we have to activate roll-over. if(pfilter){ //有过滤器 MCP2510_WriteBits(RXB0CTRL, (RXB_BUKT|RXB_RX_STDEXT|RXB_RXRTR|RXB_RXF0), 0xFF); MCP2510_WriteBits(RXB1CTRL, RXB_RX_STDEXT, 0xFF); } else{ MCP2510_WriteBits(RXB0CTRL, (RXB_BUKT|RXB_RX_ANY|RXB_RXRTR), 0xFF); MCP2510_WriteBits(RXB1CTRL, RXB_RX_ANY, 0xFF); }}/***********************************************************************************\ 发送数据 参数: data,发送数据 Note: 使用三个缓冲区循环发送,没有做缓冲区有效检测\***********************************************************************************/static int ntxbuffer=0;static inline void MCP2510_canTxBuffer(void){ switch(ntxbuffer){ case 0: MCP2510_transmit(TXB0CTRL); ntxbuffer=1; break; case 1: MCP2510_transmit(TXB1CTRL); ntxbuffer=2; break; case 2: MCP2510_transmit(TXB2CTRL); ntxbuffer=0; break; }}static inline void MCP2510_canWrite(PCanData data){ MCP2510_Write_Can(ntxbuffer, data); MCP2510_canTxBuffer();}static inline void MCP2510_canWriteData(char *pbuffer, int nbuffer){ MCP2510_Write_CanData(ntxbuffer, pbuffer, nbuffer); MCP2510_canTxBuffer();}static inline void MCP2510_canWriteRTR(void){ MCP2510_Write_CanRTR(ntxbuffer); MCP2510_canTxBuffer();}/***********************************************************************************\ 中断服务程序 \***********************************************************************************/static void s3c44b0_isr_mcp2510(void){ unsigned char byte; DPRINTK("enter interrupt!\n"); byte=MCP2510_Read(CANINTF); if(byte & RX0INT){ MCP2510_Read_Can(3,&(mcp2510dev.MCP2510_Candata[mcp2510dev.nCanRevpos])); MCP2510_WriteBits(CANINTF, ~RX0INT, RX0INT); // Clear interrupt NextCanDataPos(mcp2510dev.nCanRevpos); } if(byte & RX1INT){ MCP2510_Read_Can(4,&(mcp2510dev.MCP2510_Candata[mcp2510dev.nCanRevpos])); MCP2510_WriteBits(CANINTF, ~RX1INT, RX1INT); // Clear interrupt NextCanDataPos(mcp2510dev.nCanRevpos); } if(byte & (RX0INT|RX1INT)){ wake_up_interruptible(&(mcp2510dev.wq)); }}/*********************************************************************\ CAN设备初始化函数 参数: bandrate,CAN波特率\*********************************************************************/static int init_MCP2510(CanBandRate bandrate){ unsigned char i,j,a; MCP2510_Reset(); MCP2510_SetBandRate(bandrate,FALSE); // Disable interrups. MCP2510_Write(CANINTE, NO_IE); // Mark all filter bits as don't care: MCP2510_Write_Can_ID(RXM0SIDH, 0, TRUE); MCP2510_Write_Can_ID(RXM1SIDH, 0, TRUE); // Anyway, set all filters to 0: MCP2510_Write_Can_ID(RXF0SIDH, 0, 0); MCP2510_Write_Can_ID(RXF1SIDH, 0, 0); MCP2510_Write_Can_ID(RXF2SIDH, 0, 0); MCP2510_Write_Can_ID(RXF3SIDH, 0, 0); MCP2510_Write_Can_ID(RXF4SIDH, 0, 0); MCP2510_Write_Can_ID(RXF5SIDH, 0, 0); //Enable clock output MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1); // Clear, deactivate the three transmit buffers a = TXB0CTRL; for (i = 0; i < 3; i++) { for (j = 0; j < 14; j++) { MCP2510_Write(a, 0); a++; } a += 2; // We did not clear CANSTAT or CANCTRL } // and the two receive buffers. MCP2510_Write(RXB0CTRL, 0); MCP2510_Write(RXB1CTRL, 0); // The two pins RX0BF and RX1BF are used to control two LEDs; set them as outputs and set them as 00. MCP2510_Write(BFPCTRL, 0x3C); return 0;}static void MCP2510_SetFilter(PCanFilter pfilter){ MCP2510_Write(MCP2510REG_CANCTRL, MODE_CONFIG); // Disable interrups. MCP2510_Write(CANINTE, NO_IE); if(!pfilter){ // Mark all filter bits as don't care: MCP2510_Write_Can_ID(RXM0SIDH, 0, TRUE); MCP2510_Write_Can_ID(RXM1SIDH, 0, TRUE); // Anyway, set all filters to 0: MCP2510_Write_Can_ID(RXF0SIDH, 0, 0); MCP2510_Write_Can_ID(RXF1SIDH, 0, 0); MCP2510_Write_Can_ID(RXF2SIDH, 0, 0); MCP2510_Write_Can_ID(RXF3SIDH, 0, 0); MCP2510_Write_Can_ID(RXF4SIDH, 0, 0); MCP2510_Write_Can_ID(RXF5SIDH, 0, 0); } else{ // Mark MCP2510_Write_Can_ID(RXM0SIDH, pfilter->Mask, TRUE); MCP2510_Write_Can_ID(RXM1SIDH, pfilter->Mask, TRUE); // set all filters to same = pfilter->Filter: MCP2510_Write_Can_ID(RXF0SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF1SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF2SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF3SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF4SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF5SIDH, pfilter->Filter, pfilter->IsExt); } //Enable clock output if(mcp2510dev.loopbackmode) MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1); else MCP2510_Write(CLKCTRL, MODE_NORMAL| CLKEN | CLK1); // and the two receive buffers. MCP2510_Write(RXB0CTRL, 0); MCP2510_Write(RXB1CTRL, 0); MCP2510_Setup(pfilter);}static int s3c44b0_mcp2510_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int flags; local_irq_save(flags); switch (cmd){ case UPCAN_IOCTRL_SETBAND: //set can bus band rate MCP2510_SetBandRate((CanBandRate)arg ,TRUE); mdelay(10); break; case UPCAN_IOCTRL_SETID: //set can frame id data MCP2510_Write_Can_ID(TXB0SIDH, arg, arg&UPCAN_EXCAN); MCP2510_Write_Can_ID(TXB1SIDH, arg, arg&UPCAN_EXCAN); MCP2510_Write_Can_ID(TXB2SIDH, arg, arg&UPCAN_EXCAN); break; case UPCAN_IOCTRL_SETLPBK: //set can device in loop back mode or normal mode if(arg){ MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1); mcp2510dev.loopbackmode=1; } else{ MCP2510_Write(CLKCTRL, MODE_NORMAL| CLKEN | CLK1); mcp2510dev.loopbackmode=0; } break; case UPCAN_IOCTRL_SETFILTER://set a filter for can device MCP2510_SetFilter((PCanFilter)arg); break; } local_irq_restore(flags); DPRINTK("IO control command=0x%x\n", cmd); return 0;}/***************************************************************\* write and send Can data interface for can device file ** there are 2 mode for send data: ** 1, if write data size = sizeof(CanData) then send a full can frame ** 2, if write data size <=8 then send can data, ** we must set frame id first *\****************************************************************/static ssize_t s3c44b0_mcp2510_write(struct file *file, const char *buffer, size_t count, loff_t * ppos){ char sendbuffer[sizeof(CanData)]; if(count==sizeof(CanData)){ //send full Can frame---frame id and frame data copy_from_user(sendbuffer, buffer, sizeof(CanData)); MCP2510_canWrite((PCanData)sendbuffer); DPRINTK("Send a Full Frame\n"); return count; } if(count>8) return 0; //count <= 8 copy_from_user(sendbuffer, buffer, count); MCP2510_canWriteData(sendbuffer, count); DPRINTK("Send data size=%d\n", count); DPRINTK("data=%x,%x,%x,%x,%x,%x,%x,%x\n", sendbuffer[0],sendbuffer[1],sendbuffer[2],sendbuffer[3], sendbuffer[4],sendbuffer[5],sendbuffer[6],sendbuffer[7]); return count;}static int RevRead(CanData *candata_ret){ spin_lock_irq(&(mcp2510dev.lock)); memcpy(candata_ret, &(mcp2510dev.MCP2510_Candata[mcp2510dev.nCanReadpos]), sizeof(CanData)); NextCanDataPos(mcp2510dev.nCanReadpos); spin_unlock_irq(&(mcp2510dev.lock)); return sizeof(CanData);}static ssize_t s3c44b0_mcp2510_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){ CanData candata_ret;retry: if (mcp2510dev.nCanReadpos != mcp2510dev.nCanRevpos) { int count; count = RevRead(&candata_ret); if (count) copy_to_user(buffer, (char *)&candata_ret, count); DPRINTK("read data size=%d\n", count); DPRINTK("id=%x, data=%x,%x,%x,%x,%x,%x,%x,%x\n", candata_ret.id, candata_ret.data[0], candata_ret.data[1], candata_ret.data[2], candata_ret.data[3], candata_ret.data[4], candata_ret.data[5], candata_ret.data[6], candata_ret.data[7]); return count; } else { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on(&(mcp2510dev.wq)); if (signal_pending(current)) return -ERESTARTSYS; goto retry; } DPRINTK("read data size=%d\n", sizeof(candata_ret)); return sizeof(candata_ret);}static int s3c44b0_mcp2510_open(struct inode *inode, struct file *file){ int i,j,a; if(opencount==1) return -EBUSY; opencount++; memset(&mcp2510dev, 0 ,sizeof(mcp2510dev)); init_waitqueue_head(&(mcp2510dev.wq)); //Enable clock output MCP2510_Write(CLKCTRL, MODE_NORMAL| CLKEN | CLK1); // Clear, deactivate the three transmit buffers a = TXB0CTRL; for (i = 0; i < 3; i++) { for (j = 0; j < 14; j++) { MCP2510_Write(a, 0); a++; } a += 2; // We did not clear CANSTAT or CANCTRL } // and the two receive buffers. MCP2510_Write(RXB0CTRL, 0); MCP2510_Write(RXB1CTRL, 0); //Open Interrupt MCP2510_Write(CANINTE, RX0IE|RX1IE); MCP2510_Setup(NULL); MCP2510_OPEN_INT(); MOD_INC_USE_COUNT; DPRINTK("device open\n"); return 0;}static int s3c44b0_mcp2510_release(struct inode *inode, struct file *filp){ opencount--; MCP2510_Write(CANINTE, NO_IE); MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1); MCP2510_CLOSE_INT(); MOD_DEC_USE_COUNT; DPRINTK("device release\n"); return 0;}static struct file_operations s3c44b0_fops = { owner: THIS_MODULE, write: s3c44b0_mcp2510_write, read: s3c44b0_mcp2510_read, ioctl: s3c44b0_mcp2510_ioctl, open: s3c44b0_mcp2510_open, release: s3c44b0_mcp2510_release,};#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_spi_dir, devfs_spiraw;#endifstatic int __init s3c44b0_mcp2510_init(void){ int ret; int flags; local_irq_save(flags); EXTINT &= ~(0xf<<(24)); //EINT6 low level MCP2510_CLOSE_INT(); init_MCP2510(BandRate_250kbps); local_irq_restore(flags); ret = register_chrdev(0, DEVICE_NAME, &s3c44b0_fops); if (ret < 0) { printk(DEVICE_NAME " can't get major number\n"); return ret; } tsMajor = ret; /* Enable touch interrupt */ ret = request_irq(IRQ_MCP2510, s3c44b0_isr_mcp2510, SA_INTERRUPT, DEVICE_NAME, s3c44b0_isr_mcp2510); if (ret) return ret;#ifdef CONFIG_DEVFS_FS devfs_spi_dir = devfs_mk_dir(NULL, "can", NULL); devfs_spiraw = devfs_register(devfs_spi_dir, "0", DEVFS_FL_DEFAULT, tsMajor, SPIRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR, &s3c44b0_fops, NULL);#endif printk(DEVICE_NAME " initialized\n"); return 0;}static void __exit s3c44b0_mcp2510_exit(void){ printk(DEVICE_NAME " unloaded\n");}module_init(s3c44b0_mcp2510_init);module_exit(s3c44b0_mcp2510_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -