⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c44b0-mcp2510.c

📁 Linux环境下
💻 C
📖 第 1 页 / 共 2 页
字号:
*		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 + -