📄 can.c
字号:
/****************************************Copyright (c)**************************************************
** 西安傅立叶电子有限公司
** 研 发 部
** http://www.FFTChina.com
**-----------------------------------------文件信息-----------------------------------------------------
**文 件 名: cantest.c
**创 建 人:
**最后修改日期: 2005年6月30日
**描 述: CAN模块测试驱动程序(中断模式)
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include "linux/types.h"
#include "linux/fs.h"
#include "linux/mm.h"
#include "linux/errno.h"
#include "linux/major.h"
#include "linux/blkdev.h"
#include "linux/capability.h"
#include "linux/smp_lock.h"
#include "linux/module.h"
#include "linux/version.h"
#include "linux/kernel.h"
#include "linux/config.h"
#include "asm/uaccess.h"
#include "asm/io.h"
#include <asm/arch/hardware.h>
#include <linux/interrupt.h>
#include "sja1000.h"
#include "9200.h"
void *can1addr;
void *can0addr;
char kernel_version[]=UTS_RELEASE;
char CanDatBuf[10]; //在这里定义一个全局数组变量,用与存放接收到的CAN信息
char GETDAT = 0xff; //这是一个接收数据的全局标志位
unsigned int fftcan_major=0;
AT91PS_SYS AT91_SYS1 = (AT91PS_SYS) AT91C_VA_BASE_SYS; //将指定地址转换成一个数据结构
void setcanport(unsigned char chanal, unsigned char reg, unsigned char data1);
unsigned char getcanport(unsigned char chanal, unsigned char reg);
unsigned char getcanport(unsigned char chanal, unsigned char reg);
int read_fftcan(struct file *file, char *buf, size_t count,loff_t *f_pos);
int write_fftcan(struct file *file,const char *buf,size_t count,loff_t *f_pos);
void FFT_init_can(unsigned char chanal,unsigned char ac,unsigned char am,unsigned char btr0,unsigned char btr1);
static int ioctl_fftcan(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
/*******************************************************
** 函数原形:irq_handler(int irq, void *dev_id, struct pt_regs *regs)
** 参数: irq : 中断号
** dev_id : 申请时告诉系统的设备标识
** regs : 中断发生时的寄存器内容
** 函数说明:中断服务程序
/*******************************************************/
void irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int canint;
int channel;
unsigned char dlc,i,intstatus,temp;
AT91F_AIC_DisableIt(AT91C_ID_PIOB); //关闭中断
printk("hello,you have interrupt\n");
canint = AT91F_PIOB_GetInterruptStatus();//检查中断状态位
channel = (canint&0x18000);
switch(channel)
{
case 0x10000:
channel = 1;
break;
case 0x8000:
channel = 0;
break;
default:
channel =0xff;
break;
}
intstatus = getcanport(channel,REG_INTERRUPT);//读取SJA1000的中断寄存器,可以知道是何种中断
printk("can int status reg is %X\n",intstatus);
if((channel == 1)||(channel == 0))
{
GETDAT = channel; //该标志位等于CAN通道号
//printk("can get dat channel is %d\n",channel);
if((getcanport(channel,REG_RxBuffer2) & 0x10) == 0)
{
dlc = (getcanport(channel,REG_RxBuffer2) & 0x0f) + 2;
} else {
dlc = 2;
}
for(i = 0; i < dlc ;i ++ )
{
CanDatBuf[i] = getcanport(channel,REG_RxBuffer1+i); //该缓冲区用来存放CAN接收到的数据
}
CanDatBuf[i] = '\0';
setcanport(channel,REG_COMMAND,0x04); //free receive memory
setcanport(channel,REG_COMMAND,0x08); //free overflow memory
}
else
GETDAT = 0xff;
enable_irq(AT91C_ID_PIOB); //开PB口中断
}
/***********************************************************
** 函数原形:setcanport(unsigned char chanal, unsigned char reg, unsigned char data1)
** 参数: chanal : can通道号
** reg : 寄存器地址
** data : 要写入的数据
** 函数说明:向CAN写数据
/***********************************************************/
void setcanport(unsigned char chanal, unsigned char reg, unsigned char data1)
{
if(!chanal) //是通道0的话
{ /*与IOREMAP配套的使用函数*/
writeb(reg,can0addr+8); //模拟ALE锁存地址,发地址信号;
writeb(data1,can0addr); //发送数据到地址
}
else
{
writeb(reg,can1addr+8);
writeb(data1,can1addr);
}
}
/*******************************************************
*函数原形:getcanport(unsigned char chanal, unsigned char reg)
*参数: chanal : can的通道号
* reg :寄存器地址
*返回值 : 读出寄存器的值
*函数说明:读出寄存器的值
/*******************************************************/
unsigned char getcanport(unsigned char chanal, unsigned char reg)
{
unsigned char temp;
if(!chanal)
{
writeb(reg,can0addr+8); //先将地址发送出去,然后再读出此处的值;
temp=readb(can0addr);
}
else
{
writeb(reg,can1addr+8);
temp=readb(can1addr);
}
return (temp);
}
/*******************************************************
*函数原形:read_fftcan(struct file *file, char *buf, size_t count,loff_t *f_pos)
*参数: buf : 传入该函数的数据缓冲区指针
* count:没有使用
*返回值 : 0
*函数说明:读出接收到的CAN数据
/*******************************************************/
int read_fftcan(struct file *file, char *buf, size_t count,loff_t *f_pos)
{
buf = CanDatBuf; //指向CAN接收数据缓冲区
return 0 ;
}
/*******************************************************/
/*Transmit one message
count-----CAN的通道号
buf ---- 传递的数据指针
说明:已经修改
*******************************************************/
int write_fftcan(struct file *file,const char *buf,size_t count,loff_t *f_pos)
{
unsigned char chanal;
unsigned char temp ;
int i;
unsigned char dlc;
chanal = count; //在这里我们将count当成通道号来进行传递;
temp = getcanport(chanal,REG_STATUS);
while((getcanport(chanal,REG_STATUS) & 0x08) == 0)printk("send dat not finish!\n"); //检查发送缓冲区是否释放
while((getcanport(chanal,REG_STATUS) & 0x04) == 0)printk("senddatreg locked\n");
if((*(buf+1)&0x10) == 0)
{
dlc = (*(buf+1) & 0x0f) + 2;
}
else
{
dlc = 2;
}
for(i = 0 ;i < dlc;i ++)
{
setcanport(chanal,REG_TxBuffer1+i,*(buf+i));
}
setcanport(chanal,REG_COMMAND,0x01); //将当前的信息发送出去
return (0);
}
/*******************************************************
*函数原形:FFT_init_can(unsigned char chanal,unsigned char ac,unsigned char am,unsigned char btr0,unsigned char btr1)
*参数: chanel: CAN的通道号
ac : 验收代码寄存器的值
* am :验收屏蔽寄存器的值
btr0 : 波特率设置
btr1 :
*返回值 : 0 :说明初始化成功
*函数说明:配置CAN总线
/*******************************************************/
void FFT_init_can(unsigned char chanal,unsigned char ac,unsigned char am,unsigned char btr0,unsigned char btr1)
{
unsigned char temp ;
/*Config MOD&CR register进入复位模式,同时使能发送和接收中断*/
do
{
temp = 0x01;
setcanport(chanal,REG_CONTROL,temp);
} while((temp&0x01) != 0x01);
//测试波特率的值
setcanport(chanal, REG_BTR0, btr0);
setcanport(chanal, REG_BTR1, btr1);
//设置验收代码寄存器的值
setcanport(chanal,REG_ACR, ac);
//设置验收滤波寄存器的值
setcanport(chanal,REG_AMR, am);
//设置输出控制寄存器的值
setcanport(chanal,REG_OCR, 0xda);
//设置始时钟分频寄存器的值
setcanport(chanal, REG_CDR, 0x48);
//退出复位模式
do
{
setcanport(chanal, REG_CONTROL,0x02 );
temp = getcanport(chanal,REG_CONTROL);
} while((temp & 0x01) != 0 );
}
/*******************************************************
** 函数原形 :open_fftcan();
** 说明 :
*******************************************************/
int open_fftcan(struct inode *inode,struct file *file)
{
return 0;
}
/*******************************************************
** 函数原形 :
** 函数说明 :
*******************************************************/
int release_fftcan(struct inode *inode,struct file *file)
{
return 0;
}
/***************************************************************************************************
*函数原形:ioctl_fftcan(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
*参数: cmd : 传入该函数的命令参数
* 0 :判断是否CAN0收到可用数据
1 :判断是否CAN1收到可用数据
3 :初始化CAN0总线
4 :初始化CAN1总线
arg :传入的参数
*返回值 : 0 :CAN0接收到有效数据
1 :CAN1接收到有效数据
3 :成功初始化CAN0
4 :成功初始化CAN1
5 :无效的命令
*函数说明:向CAN总线发送数据
/**************************************************************************************************/
static int ioctl_fftcan(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
unsigned char temp1;
unsigned char ac,am,btr0,btr1,chanal;
switch (cmd)
{
case 0:
case 1:
temp1 = GETDAT;
break;
case 3: /*应该对通道0进行初始化*/
chanal = 0;
ac = (arg & 0xff000000) >> 24 ; //应当右移恢复原来的数据
am = (arg & 0x00ff0000) >> 16;
btr0 = (arg & 0x0000ff00) >> 8;
btr1 = (arg & 0x000000ff) ;
FFT_init_can(chanal,ac,am,btr0,btr1); //初始化CAN0的基本控制器
temp1 = 3;
break;
case 4: /*对通道1进行初始化*/
chanal = 1;
ac = (arg & 0xff000000) >> 24 ;
am = (arg & 0x00ff0000) >> 16;
btr0 = (arg & 0x0000ff00) >> 8;
btr1 = (arg & 0x000000ff) ;
FFT_init_can(chanal,ac,am,btr0,btr1);
temp1 = 4;
break;
default:
temp1 = 5;
break;
}
return (temp1);
}
/**************************************
** 函数指针结构: file_operations
** 说明 :
***************************************/
struct file_operations fftcan_fops={
read : read_fftcan,
write: write_fftcan,
ioctl: ioctl_fftcan,
open : open_fftcan,
release: release_fftcan,
};
/******************************************************
** 初始化模块:在加载模块时候调用
** 函数原形 : init_module(void)
** 说 明 :不用修改
******************************************************/
int init_module(void)
{
int result;
AT91F_PIOB_CfgPMC();
AT91F_PIOB_CfgInput(AT91C_PIO_PB15|AT91C_PIO_PB16); //配置为输入
AT91F_PIOB_InterruptEnable(AT91C_PIO_PB15|AT91C_PIO_PB16);//中断使能
AT91F_PIOB_GetInterruptStatus();
result=register_chrdev(0,"fftcan",&fftcan_fops); //注册一个设备,得到驱动的主设备号
if(result<0)
{
printk("cannot get fftcan major number\n"); //没有成功
return result;
}
printk("congraulation,fftcan are successful registed\n");
if(fftcan_major==0)
{
fftcan_major=result; //记录下主设备号
}
//映射物理地址到IO内存,可以让软件直接访问IO内存
can0addr= ioremap(0x50800000,0x20);
/*将物理地址直接映射到IO内存*/
can1addr=ioremap(0x50c00000,0x20); /*第一个参数是物理地址,第2个是映射的大小,因为CAN只有32字节的地址空间,所以就0X10*/
free_irq(AT91C_ID_PIOB, NULL);
request_irq(AT91C_ID_PIOB,
irq_handler, /* our handler */
0,
"fftcantest", NULL);
if (result < 0)
{
printk(KERN_INFO "test: can't install interrupt\n");
}
enable_irq(AT91C_ID_PIOB);
return 0;
}
/*******************************************************
** 函数原形 : cleanup_module(void)
** 说明 : 在卸载模块时调用
******************************************************/
void cleanup_module(void)
{
iounmap(can0addr);
iounmap(can1addr);
free_irq(AT91C_ID_PIOB, NULL);
unregister_chrdev(fftcan_major,"fftcan");
printk("exit fftcan\n");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -