当前位置:文档之家› CAN总线在嵌入式Linux下驱动程序的实现

CAN总线在嵌入式Linux下驱动程序的实现

CAN总线在嵌入式Linux下驱动程序的实现时间:2009-11-05 09:41:22 来源:微计算机信息作者:黄捷峰蔡启仲郭毅锋田小刚1 引言基于嵌入式系统设计的工业控制装置,在工业控制现场受到各种干扰,如电磁、粉尘、天气等对系统的正常运行造成很大的影响。

在工业控制现场各个设备之间要经常交换、传输数据,需要一种抗干扰性强、稳定、传输速率快的现场总线进行通信。

文章采用CAN总线,基于嵌入式系统32位的S3C44B0X微处理器,通过其SPI接口,MCP2510 CAN控制器扩展CAN总线;将嵌入式操作系统嵌入到S3C44B0X微处理器中,能实现多任务、友好图形用户界面;针对S3C44B0X微处理器没有内存管理单元MMU,采用uClinux嵌入式操作系统。

这样在嵌入式系统中扩展CAN设备关键技术就是CAN设备在嵌入式操作系统下驱动程序的实现。

文章重点解决了CAN总线在嵌入式操作系统下驱动程序实现的问题。

对于用户来说,CAN设备在嵌入式操作系统驱动的实现为用户屏蔽了硬件的细节,用户不用关心硬件就可以编出自己的用户程序。

实验结果表明驱动程序的正确性,能提高整个系统的抗干扰能力,稳定性好,最大传输速率达到1Mb/s;硬件的错误检定特性也增强了CAN的抗电磁干扰能力。

2 系统硬件设计系统采用S3C44B0X微处理器,需要扩展CAN控制器。

常用的CAN控制器有SJA1000和MCP2510,这两种芯片都支持CAN2.0B标准。

SJA1000采用的总线是地址线和数据线复用的方式,但是嵌入式处理器外部总线大多是地址线和数据线分开的结构,这样每次对SJA1000操作时需要先后写入地址和数据2次数据,而且SJA1000使用5V逻辑电平。

所以应用MCP2510控制器进行扩展,收发器采用82C250。

MCP2510控制器特点:1.支持标准格式和扩展格式的CAN数据帧结构(CAN2.0B);2.0~8字节的有效数据长度,支持远程帧;3.最大1Mb/s的可编程波特率;4.2个支持过滤器的接受缓冲区,3个发送缓冲区;5.SPI高速串行总线,最大5MHz;6.3~5.5V宽电压范围供电。

MCP2510工作电压为3.3V,能够直接与S3C44B0X微处理器I/O口相连。

为了进一步提高系统抗干扰性,可在CAN控制器和收发器之间加一个光隔6N137。

其结构原理框图如图1:图1.S3C44B0X扩展CAN结构框图图2.字符设备注册表3 CAN设备驱动程序的设计Linux把设备看成特殊的文件进行管理,添加一种设备,首先要注册该设备,增加它的驱动。

设备驱动程序是操作系统内核与设备硬件之间的接口,并为应用程序屏蔽了硬件细节。

在linux中用户进程不能直接对物理设备进行操作,必须通过系统调用向内核提出请求,由内核调用相应的设备驱动。

因此首先建立Linux设备管理、设备驱动、设备注册、Linux 中断这几个概念。

3.1 Linux的设备管理Linux支持各种各样的外围设备,对这些设备的管理通称为设备管理。

设备管理分为两部分:一部分是驱动程序的上层,与设备无关的,这部分根据输入输出请求,通过特定的设备驱动程序接口与设备进行通信;另一部分是下层,与设备有关的,通常称为设备驱动程序,它直接与硬件打交道,并且向上层提供一组访问接口。

Linux设备管理为了对设备进行读、写等操作,把物理设备逻辑化,把它看成特殊的文件,称为设备文件,采用文件系统接口和系统调用来管理和控制设备。

Linux把设备分为三类,块设备、字符设备和网络设备。

每类设备都有不同管理控制方式和不同的驱动程序,这样方便于对系统进行裁减。

Linux内核对设备的识别是根据设备类型和设备号。

在字符设备中使用同一个驱动程序的每种设备都有唯一的主设备号。

CAN设备通过在/vendor/Samsung/44b0/Makefile文件下设置设备类型和设备号分别为can、125。

3.2 file_operations结构体Linux对设备操作的具体实现是由设备驱动程序完成。

设备驱动程序加载到系统中通过设备注册实现。

Linux驱动程序对文件的操作通过file_operations结构体来完成。

file_operations结构体是文件操作函数指针的集合。

在设备管理中该结构体各个成员项指向的操作函数就是设备驱动程序的各个操作例程,编写驱动程序实质上就是编写该结构体中的各个函数。

对不同的设备可以配备其中全部或部分的操作函数,不使用的函数指针置为NULL。

下面是CAN设备file_operations结构体:Static struct file_operations {write: s3c44b0_mcp2510_write,//写操作read: s3c44b0_mcp2510_read,//读操作ioctl: s3c44b0_mcp2510_ioctl,//读写之外的操作open: s3c44b0_mcp2510_open,//打开设备release: s3c44b0_mcp2510_release};//关闭设备这个结构的每一个成员的名字都对应着一个系统调用。

用户进程利用系统调用,来调用自己的驱动接口,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数。

3.3 设备注册在linux中,当一种设备安装到系统时必须向系统进行注册,设备注册的主要任务是把设备驱动程序加载到系统中。

Linux对不同的设备(如字符设备和块设备)分开进行注册管理。

每个设备描述符包括两个指针:name指向设备名字符串,fops指向文件操作函数结构file_operations,该结构体中包含着指向驱动程序各个操作例程的指针。

图2给出了linux 字符设备注册表的示意图。

CAN字符设备的注册函数是内核函数:register_chrdev(MAJOR_NR,DEVICE_NAME,&s3c44b0_mcp2510_fops);其中参数DEVICE_NAME表示设备名,s3c44b0_mcp2510_fops表示指向file_operations结构体的指针,即指向设备的驱动程序。

3.4 Linux中断的处理在linux系统里,对中断的处理是属于系统核心部分,因而如果设备与系统之间以中断方式进行数据交换,就必须把该设备的驱动程序作为系统核心的一部分。

设备驱动程序通过用request_irq函数来申请中断,通过free_irq来释放中断。

由于本实验未用到中断,因此在此不作详细介绍。

3.5 CAN驱动程序的实现3.5.1 编写驱动程序操作例程CAN设备属于字符设备,对于CAN总线设备,除了发送(使用write方法)、接受(使用read方法)以外,还需要控制CAN总线通信的波特率、设置工作模式、设置ID等,所以使用ioctl是最合适的方法。

CAN驱动程序的入口函数:int __init s3c44b0_mcp2510_init(void){ARMTargetInit();//初始化ARMinit_MCP2510(BandRat125kbps);//初始化CAN控制器ret=register_chrdev(MAJOR_NR,DEVICE_NAME,&s3c44b0_mcp2510_fops);}//注册CAN设备CAN驱动程序的退出函数:void __exit s3c44b0_mcp2510_exit(void){unregister_chrdev(MAJOR_NR,DEVICE_NAME);printk("MCP2510 Eixt!n");}CAN总线在嵌入式Linux下驱动程序的实现时间:2009-11-05 09:41:22 来源:微计算机信息作者:黄捷峰蔡启仲郭毅锋田小刚编写CAN设备驱动程序各个操作例程:1.ioctl函数:Static int s3c44b0_mcp2510_ioctl (struct inode * inode,struct file *file, unsined cmd ,unsigned long arg){switch(cmd){case SETBAND://设置波特率MCP2510_SetBandRate(BandRate,TRUE);break;case SETLPBK://设置工作方式MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLK| CLK1);break;case SETID://设置标识符MCP2510_Write_Can_ID(RXF0SIDH,U8 ID,0);break;case SETFILTER: //设置屏蔽码MCP2510_Write_Can_ID(RXM0SIDH,0x1ff,0);break;}}2.open函数(打开设备):static int s3c44b0_mcp2510_open(struct inode *inode,struct file *file){printk("device openn");return 0;}3.write函数(发送数据):static ssize_t s3c44b0_mcp2510_write(struct file *file,const char *buffer,size_t count,loff_t*ppos){copy_from_user(&temp,buffer,sizeof(mcpcan_data)); canWrite(temp.id,temp. data,temp.DataLen,temp.IdType,temp.BufNo);}//发送数据函数4.read函数(接收数据):static ssize_t s3c44b0_mcp2510_read(struct file *file,char *buffer,size_tcount,loff_t *ppos){Revdata(0x66,datas,0x08);//接收数据函数copy_to_user(buffer,Receivedata.data,0x08);return count;}3.5.2交叉编译CAN驱动程序交叉编译驱动程序需要一台装了Red Hat Linux的宿主机。

安装交叉编译工具的方法请参考相关文档(交叉编译工具:arm-elf-tools-20030314.sh)。

驱动程序的使用可以按照两种方式进行编译,一种是静态编译进内核,一种是编译成模块以供动态加载。

由于uclinux 不支持模块动态加载,所以这里只介绍将驱动程序静态编译进内核的方法。

为了让编译器编译所添加的驱动程序,需要修改相关文件。

相关主题