微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 嵌入式Linux中I2C设备驱动程序的研究与实现

嵌入式Linux中I2C设备驱动程序的研究与实现

时间:02-13 来源:互联网 点击:

储能力为1KB。

3.1 I2C 设备驱动程序的一般结构及运行流程图

开发一个具体的I2C 设备驱动需要一个完整、标准的结构,而该结构的实现是通过编写两个方面的接口而完成的, 一个是用以挂接I2C adapter 层来实现对I2C 总线及I2C设备具体的访问方法, 即I2C 核心层的接口, 主要实现attach_adapter,detach_client,command 等接口函数。另一个是对用户应用层的接口, 提供用户程序访问I2C设备的接口, 包括实现open,release,read,write 以及ioctl 等标准文件操作的接口函数。下面将通过对核心层接口和应用层接口的分析来说明I2C 设备驱动程序的运行机制。图2 为I2C 设备驱动程序运行流程图(图中at 代表具体的设备AT24C08):

3.2 I2C 设备驱动的I2C 核心层接口分析

如图2 的用户空间在通过insmod 命令加载设备驱动程序时, 设备驱动将通过使用动态模块的方式加载并指向设备初始化函数at_init(),在初始化函数中使用regiSTer_chrdev()进行字符型设备的注册, 并可以通过静态和动态两种方法来申请注册到系统中的设备号。另外将调用核心i2c -core.c 中提供的i2c_add_driver()函数注册由at_driver 数据结构描述的驱动方法,该数据结构中完成了对驱动程序的标示, 并包含了两个重要的成员函数at_attach_adapter()和at_detach_client()。

在i2c_add_driver () 注册at_driver 数据结构后,at_attach_adapter()函数就会被自动调用,其遍历系统中的每个i2c 总线驱动, 探测想要访问的设备, 连接符合i2c driver 特定条件的i2c adapter,并通过i2c adapter 实现对I2C 总线及其设备的访问。

而at_attach_adapter()的功能则是依靠调用i2c-core.c 核心中的i2c_probe()函数来实现的,通过i2c_probe()函数可以认领adapter所指向的适配器上的所有合适的设备。设备可能使用的地址由addr_data 数组指出。通过设备地址每次检测到新设备后,i2c_probe()将使用它的第三个参数即回调函数初始化设备的数据结构i2c_client,并用i2c_check_functiONality()确定I2C 适配器所支持的通信方法。另外再使用i2c_attach_client()知会I2C 核心系统中包含了一个新的I2C 设备。

通过rmmod 命令对设备驱动进行卸载时, 在卸载函数at_exit()中将使用i2c_del_driver(),其调用会引起与数据结构at_driver 关联的每个i2c_client 与之解除关联, 随后at_detach_client()函数也将因此而被调用,而at_detach_client()中的i2c_detach_client()又完成与i2c_attach_client()相反的过程,并使用kfree 释放由client 所占的内存。另外卸载函数at_exit()中还将使用unregister_chrdev()对字符型设备进行注销。

3.3I2C设备驱动用户应用层接口分析

在注册字符型设备时, 设备驱动中初始化了一个structfile_operations 文件操作结构体变量用于链接字符设备驱动程序和用户应用程序,在该结构中定义了一组函数指针。系统就是通过这组函数指针对AT24C08 进行具体的操作,系统首先通过设备文件的主设备号找到相应的设备驱动程序, 然后读取这个数据结构相应的函数指针,找到相关的功能函数,接着把控制权交给该函数,从而就在上层屏蔽了设备驱动的具体实现细节,提供给用户一个方便快捷的接口。该结构中的at_open(),对应于用户应用层的open()接口函数,其通过mknod 创建的设备节点对设备文件进行打开操作。而对应用户层release () 接口函数的at_release () 则负责设备文件的释放操作。file_operations 中的at_ioctl()则主要是为用户提供一些控制该AT24C08 的命令。对一块具体设备进行读写操作是编写驱动要达到目的,file_operations结构体中所指向的读写函数at_read(),at_write()完成了对AT24C08 的写入和读出操作。

就写函数而言, 在写数据之前必须先输入测试单元的起始地址, 然后再对写入的数据分配相应内存, 然后使用copy_from_user 命令把从用户空间获得的数据拷贝到内核空间,并构造I2C 消息数据,最终通过i2c-core.c 的i2c-transfer()函数进行I2C消息数组的传输,而i2c_transfer()将指向总线驱动中的算法i2c_algorithm 所对应的具体适配器的master_xfer()方法,这样就借助i2c-core.c 作为纽带连接了设备驱动和总线驱动,并完成了两者之间的通信,其运行流程如图2 的内核空间所示。

对于读函数at_read(),同样要对数据进行内存的分配,构造I2C消息,传输I2C 消息以及转换数据空间等。两者的主要区别则体现在对I2C 消息的构造上,在读出数据之前,先要写地址,根据写入的地址来寻找将要读出的数据的起始地址, 所以在读函数中就需要构造两条I2C 消息,一条用于写地址操作,另一条用于读数据操作。另

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top