mycan.c
来自「基于MCF2812的FLEXCAN总线驱动程序」· C语言 代码 · 共 370 行
C
370 行
#define CONFIG_M5282 //added
#define CONFIG_CLOCK_20MHz //added
#define CONFIG_COLDFIRE//added
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include <linux/kernel.h>
#include "sched.h"
#include <linux/interrupt.h>
#include <linux/poll.h> //for select
#include <asm/delay.h>
#include "mycan.h"
DECLARE_TASKLET(bh_can_data,get_can_data,0);
volatile unsigned char user_open = 0;
void can_release(void);
int can_open(struct inode *inode, struct file *file);
int can_close(struct inode *inode, struct file *file);
ssize_t can_read(struct file *file,char *buf,size_t count,loff_t *loff);
unsigned int can_select(struct file *file, struct poll_table_struct *wait);
ssize_t can_write( struct file *file, const char *buf, size_t count, loff_t *loff);
struct file_operations can_fops = {
read: can_read,
write: can_write,
poll: can_select,
open: can_open,
release: can_close,
};
//................file operations................
ssize_t can_write( struct file *file, const char *buf, size_t count, loff_t *loff)
{
can_obj *pcan;
unsigned short i=1;
pcan = (can_obj *)(MCFFLEXCAN_BASE+0x80+0x10*i);
//Writing the Control/Status word to hold Tx MB inactive (code = 1000)
pcan->bid.code = 0x8;
//Writing the ID_HIGH and ID_LOW words.
pcan->bid.id0=0;
pcan->bid.id15=0;
pcan->bid.id18=0;
pcan->bid.srr=1;
pcan->bid.ide=1;
pcan->bid.rtr=0;
//* Writing the Data bytes "MYCAN!"
pcan->msg= "MYCAN!" ;
printk("Sending....\n");
// Writing the Control/Status word (cold=1100, active Code, Length=7)
pcan->bid.code = 0xc; pcan->bid.length=0x7;
printk("Sending completed!\n");
return -EIO;
} //write function to be implemented
ssize_t can_read(struct file *file,char *buf,size_t count,loff_t *loff)
{
can_obj *pcan;
unsigned short i;
char msg[9];
for(i=3;i<=15;i++)
{
pcan = (can_obj *)(MCFFLEXCAN_BASE+0x80+0x10*i);
if(( int len=(int)pcan->bid.length )!=0) //if the box is not empty
{
int j;
for(j=0;j<len;j++)
{
msg[j]=pcan->msg[j];
}
printk("There are %d words in the message box %d,it is:\n",len,i);
printk(msg);//...........??? to be checked in linux
pcan->bid.code = 0x4; // set active and empty
return -EIO;
}
}
printk("No message in every box!\n");
return -EIO; //read function to be implemented
}
unsigned int can_select(struct file *file, struct poll_table_struct *wait) //检查是否可读或可写
//一般用于程序询间设备是否可读和写,或是否一个“异常”条件发生了。如果指针为NULL,系统假设设备总是可读和可写的.而且没有异常需要处理。
{
unsigned int mask=0;
unsigned int minor = file->f_dentry->d_inode->i_rdev;//设备的从设备好
poll_wait(file,&read_wq[minor],wait);//将当前进程进入等待队列排队
if(user_mes[minor].head != user_mes[minor].tail)
mask |= POLLIN|POLLRDNORM;//管道能无阻塞可读
mask |= POLLOUT|POLLWRNORM; //管道能无阻塞可写
return mask;
}
// ................can open and close..................
int can_open(struct inode *inode, struct file *file)
{
int minor=MINOR(inode->i_rdev);
file->f_dentry->d_inode->i_rdev = minor;
if(!user_open) //一个子设备也没有devserver open 队列初始化
{
user_mes[0].head = user_mes[0].tail = 0;
user_mes[1].head = user_mes[1].tail = 0;
//rx_buf.head = rx_buf.tail = 0;
if(can_init()<0) return -ENXIO;//CAN的初始化
init_waitqueue_head(&read_wq[0]) ;//载入进程
init_waitqueue_head(&ack_wq);
}
file->f_op = &can_fops; //the interrupt-driven 程序首地址
MOD_INC_USE_COUNT; //用户数+1
user_open |= 1<<minor;
return 0;
}
int can_close(struct inode *inode, struct file *file)
{
unsigned int minor = file->f_dentry->d_inode->i_rdev;
printk("can_close enter\n");
if(user_open&(1<<minor))
{
user_open &= ~(1<<minor);
MOD_DEC_USE_COUNT; //用户数-1
if(!user_open) can_release();
return 0;
}
return -EBADF;
}
//.........................intterupt.........................
volatile unsigned short rec_mask=0;
void can_interrupt(int irq,void *dev_id,struct pt_regs *ptregs)
{
//136,137,138 map to mb0~mb2 tx-buf no interrupt 153,154,155 map to error bus wakeup
if(irq>138 && irq<152)
{
char code;
can_obj *pcan;
unsigned short i=3;
unsigned short mask = 0x8; //from mb 3 start
while(pCanBase->iflag & 0xfff8)
{
if(pCanBase->iflag & mask)
{
pcan = (can_obj *)(MCFFLEXCAN_BASE+0x80+0x10*i);
code =pcan->bid.code; //
pcan->bid.code = 0; //message buffer is not active
if(code == 2 ||code == 6)//if full
{
rec_mask |= mask;
tasklet_schedule(&bh_can_data);
}
pCanBase->iflag |= mask; //clear iflag;
}
mask = mask<<1; i++;
}
}
else if(irq == 152) //收发错误中断
{
pCanBase->estat &= 0xfc;
printk("estate txerr rxerr %x %x %x\n",pCanBase->estat,pCanBase->txectr,pCanBase->rxectr);
}
else if(irq == 153) //总线中断
{
can_init();
}
else
printk("candrv unknown interrupt source %d\n",irq);
}
//..................................CAN cleanup and init//////////////
#ifdef MODULE
void cleanup_module(void)//在模块被卸载时调用,负责进行设备驱动程序的清除工作。
//仅当模块被下载前才被调用,好像它跟内核说: "我不在这里了,别调用我了"
{
can_release();//释放申请的I/O地址
unregister_chrdev(CAN_MAJOR, "cancard");//注销登记的字符设备
}
extern int init_module(void)//供insmod在加载此模块的时候自动调用,负责进行设备驱动程序的初始化工作。
//init_module返回0以表示初始化成功,返回负数表示失败。
//init_module为以后调用模块的函数做准备.好像在说:"我在这里这是我能做的"
#else
extern int candrv_init(void)
#endif
{
int i;
if(register_chrdev(100, "cancard",&can_fops)< 0)//若小于0,则无法申请此设备号,返回负数
{
printk("CAN driver can't get Major %d\n", CAN_MAJOR);
return(-EIO);
}
printk(KERN_INFO"MCF5282 CAN Driver " __DATE__ " " __TIME__ "\n");
printk(KERN_INFO"emc lib eme8@tsinghua.edu.cn\n");
DisableInterrupt();//中断无效
for(i = 136; i < 155; i++)
{
if(request_irq(i,can_interrupt,SA_SHIRQ, "cancard",NULL)<0)//申请中断号
{
printk(KERN_INFO "candrv_init: can't get irq %i\n",i);//得不到所要申请的硬件中断号
return -1;
}
}
for(i=0;i<19;i++)//interrupt
{
((volatile unsigned char*)(MCF_MBAR+0xd48+i)) =0x3f; //赋值操作Interrupt Control Register 1 08 to 26 优先级等
//volatile是C++关键字,是一个声明变量时用的修饰符,说明这个变量有可能被其他的线程或者中断等外部条件改变。如果在多线程环境中,线程间共享变量应该用这个修饰符。
}
*((volatile unsigned long *)(MCF_MBAR+0xd0c)) = 0xf80000fe; //赋值操作Interrupt Mask Register
//for(i=0;i<MAX_SLAVE_ADDR;i++) can_dev[i] = LINK_OFF;//终止驱动
return 0;
}
///////////////////////////////////////--refer by others--------------===========
/*can_init函数:初始化Memory Map,除了Rx Error Counter和Tx Error Counter没有初始化外,其他的都初始化赋值了。先初始化Message Buffer Structure,再初始化Message Buffer Memory Map步骤如下:
1.将引脚AS2,AS3,AS4,AS5作为primary function引脚(P548)。IPSBAR=0x40000000(P184)
2.初始化寄存器CANMCR:先中止CAN时钟,然后进行软件复位,复位失败则跳出初始化函数。
3.设置控制寄存器0:允许Buss off中断,并设置收发引脚的配置控制(0为显性,1为隐性)
4.设置控制寄存器1:Sampling mode为0,设置Propagation segment time为5个时钟周期(时钟周期为多少?)
5.设置控制寄存器2:其值为:1110_0100B。Resynchronizaton Jump Width=4个周期,length of phase buffer segment 1=5个周期,length of phase buffer segment 2=5个周期
6.通过配置寄存器PRESDIV,设置S-clock的大小为:系统频率的1/4(系统频率为多少?)
7.设置RXGMASK, RX14MASK, and RX15MAS:1_1111_0000_0000(h) 0(l):MB4-Id(设置收发ID?)
8.定义Message Buffers的收发情况:0~2为发,3~15为收
9.初始化中断标志位iflag和屏蔽位imask(收发后BUFFER0,BUFFER1,BUFFER2不产生中断,其他的BUFFER产生中断——即收到信号后产生中断,发送后不产生中断)
10.初始化estat:初始化错误状态和总线状态
11.通过CANMCR激活CAN
12.显示几个初始化寄存器的值
**********************************************************************************************************************
**********************************************************************************************************************
reset_rx_mb函数:将对应的Buffern设置为“收”
1.将Message Buffers置于不激活状态
2.第3~14个Message Buffers收信号地址为0;
3.第15个Message Buffers收信号地址为11_1100_0000_0000
4.将Message Buffers置于“空且激活”状态
*/
int can_init(void)
{
unsigned short reg;
//MCF5282_GPIO_PASPAR = 0x0FF0; /* Initialize Port AS PAR to have Can TX/RX signals enabled */
*((volatile unsigned short *)(0x40100056)) = 0x0FF0;/* Initialize Port AS PAR to have Can TX/RX signals enabled */
pCanBase->canmcr = CANMCR_STOP_CLOCK|CANMCR_SOFT_RST;
udelay(20);
reg = pCanBase->canmcr;
if(reg&CANMCR_SOFT_RST)
{
printk("can_init fail\n");
return -1;
}
/* Initialize the transmit and receive pin modes and enable Bus_off and error interrupt in control register 0 */
//pCanBase->canctrl0 = ENABLE_BOFF_INT|0x02; //rx- recessive tx-Open drain
pCanBase->canctrl0 = ENABLE_BOFF_INT|0|0; //rx- negative polarity tx-positive polarity
//PRESDIV S-CLOCK PROPSEG PSEG1 PSEG2 RJW
//0x02 16M 4 4 4 4
pCanBase->canctrl1 = SAMP|CAN_PROPSEG_1000K; //CANCTRL1 SAMP|TSYNC|LBUF|LOM|PROPSEG
pCanBase->canctrl2 = (CAN_RJW<<6)|(CAN_PSEG1_1000K<<3)|CAN_PSEG2_1000K; //CANCTRL2 RJW|PSEG1|PSEG2 00 111000
pCanBase->presdiv = CAN_PRESDIV_1000K; //PRESDIV PRES_DIV
//printk("bit time %x %x\n",pCanBase->canctrl1,pCanBase->canctrl2);
//printk("prop seg1 seg2 %d %d %d %x\n",CAN_PROPSEG_1000K,CAN_PSEG1_1000K,CAN_PSEG2_1000K,pCanBase->canctrl2);
pCanBase->rxgmskhi = 0x1f00; /*滤波器设置*/
pCanBase->rxgmsklo = 0;
pCanBase->rx14mskhi = 0x1f00;
pCanBase->rx14msklo = 0;
pCanBase->rx15mskhi = 0x1f00;
pCanBase->rx15msklo = 0;
for(reg=0;reg<3;reg++) //message buffer 0~2 for tx
*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*reg)) = 0x80; //tx not active
for(reg=3;reg<=15;reg++) //message buffer 3~15 for rx
reset_rx_mb(reg); //just below it
//reg = pCanBase->timer; //release all message buffer
pCanBase->iflag |= 0xffff;
pCanBase->estat &= 0xfff8;
pCanBase->imask = 0xfff8; //enable rx interrupt;
pCanBase->canmcr = 0;
udelay(20);
printk("can init end cmr estat iflag %x %x %x\n",pCanBase->canmcr,pCanBase->estat ,pCanBase->iflag);
printk("txe rxe %x %x\n",pCanBase->rxectr,pCanBase->txectr);
return 0;
}
/////////////////////////////////////////
inline void reset_rx_mb(int no)
{
*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no)) = 0; // rx not ready
if(no != 15)
*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no+2)) = 0x0008; //receive msg addr is 0
else
*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no+2)) = 0x1f08; //message buffer 15 for broadcast information
*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no+4)) = 0; //ID|data frmae
*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no)) = 0x40; //rx active and empty ready for receive
}
//////////by other///////////
void can_release(void)
{
int i;
DisableInterrupt();//中断无效
*((volatile unsigned short *)(MCFFLEXCAN_BASE)) = 0x1000;
for(i=136;i<155;i++)free_irq(i,NULL);//释放在init_module()中申请的中断
}
///////////by other////////////////
inline static void DisableInterrupt(void)
{
*((volatile unsigned char *)(MCFFLEXCAN_BASE + 6)) = 0x0|0|2; //控制寄存器0,关闭总线与错误中断
*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x22)) = 0; //中断掩码寄存器
}
//////////////////////////
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?