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

📄 can.c

📁 西安付立叶的基于at91rm9200的linux
💻 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 + -