I2C驱动培训文档
更新时间:2024-05-28 14:49:01 阅读量: 综合文库 文档下载
- linux i2c驱动推荐度:
- 相关推荐
I2C驱动
一、 协议......................................................................................................................................... 2
基本概念 ................................................................................................................................... 2 主机发送数据流程 ................................................................................................................... 2 二、iomux ........................................................................................................................................ 8
I2c2的复用 ............................................................................................................................ 10 三、 驱动....................................................................................................................................... 12
基本知识 ................................................................................................................................. 12 思考问题1:I2c总线设备和i2c总线上可挂载的i2c设备是在Board-mx6q-sarbed的init board中初始化的,那么Board-mx6q-sarbed中init board是从什么时候开始执行的呢?15 Machine_desc的是怎么加载的呢? .................................................................................. 19 思考问题2:那么这些被加入到代码段中的fn,是在哪被调用的呢? ......................... 21 I2c驱动的代码流程 ............................................................................................................... 23 Dev下i2c设备节点 .............................................................................................................. 25 Platform下的i2c .................................................................................................................... 26 具体的i2c设备的初始化 ...................................................................................................... 27 思考问题3:上面调用到了master_xfer(),那么它是在哪初始化的呢? ....................... 31 /sys/bus/i2c及/sys/bus/i2c/device和driver增加 .................................................................. 32 /sys/bus/i2c/device和driver下的各个具体设备和驱动 ...................................................... 33 思考问题4:Platform总线是在哪初始化? ....................................................................... 36
一、协议
I2C 总线是一种用于IC器件之间连接的双向二线制总线 I2C总线有两根信号线,一根为SDA(数据线),一根为SCL(时钟线)。可发送和接收数据。任何时候时钟信号都是由主控器件产生。
I2C总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。
开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。 结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。 基本概念
主机 初始化发送,产生时钟信号和终止发送的器件 从机 被主机寻址的器件 发送器 发送数据到总线的器件 接收器 从总线接收数据的器件
多主机 同时有多于一个主机尝试控制总线 但不破坏报文
仲裁 是一个在有多个主机同时尝试控制总线,但只允许其中一个控制总线并使报文不被破坏的过程
同步 两个或多个器件同步时钟信号的过程 主机发送数据流程
(1)主机在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发送一个启动信号“S”,开始一次通信的开始
(2)主机接着发送一个命令字节。该字节由 7 位的外围器件地址和 1 位读写控制位 R/W组成(此时 R/W=0)
(3)相对应的从机收到命令字节后向主机回馈应答信号 ACK(ACK=0) (4)主机收到从机的应答信号后开始发送第一个字节的数据 (5)从机收到数据后返回一个应答信号 ACK (6)主机收到应答信号后再发送下一个数据字节
(7)当主机发送最后一个数据字节并收到从机的 ACK 后,通过向从机发送一个停止信号P结束本次通信并释放总线。从机收到P信号后也退出与主机之间的通信
注意:①主机通过发送地址码与对应的从机建立了通信关系,而挂接在总线上的其它从机虽然同时也收到了地址码,但因为与其自身的地址不相符合,因此提前退出与主机的通信; ②主机的一次发送通信,其发送的数据数量不受限制。主机是通过 P 信号通知发送的结束,从机收到 P 信号后退出本次通信;
③主机的每一次发送后都是通过从机的 ACK 信号了解从机的接收状况,如果应答错误则重发。
总线空闲状态
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。 启动信号
在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低(即负跳变),定义为I2C总线总线的启动信号,它标志着一次数据传输的开始。启动信号是一种电平跳变时序信号,而不是一个电平信号。启动信号是由主控器主动建立的,在建立该信号之前I2C总线必须处于空闲状态。 重启动信号
在主控器控制总线期间完成了一次数据通信(发送或接收)之后,如果想继续占用总线再进行一次数据通信(发送或接收),而又不释放总线,就需要利用重启动Sr信号时序。重启动信号Sr既作为前一次数
据传输的结束,又作为后一次数据传输的开始。利用重启动信号的优点是,在前后两次通信之间主控器不需要释放总线,这样就不会丢失总线的控制权,即不让其他主器件节点抢占总线。 停止信号
在时钟线SCL保持高电平期间,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号,它标志着一次数据传输的终止。停止信号也是一种电平跳变时序信号,而不是一个电平信号,停止信号也是由主控器主动建立的,建立该信号之后,I2C总线将返回空闲状态。 插入等待时间
如果被控器需要延迟下一个数据字节开始传送的时间,则可以通过把时钟线SCL电平拉低并且保持,使主控器进入等待状态。一旦被控器释放时钟线,数据传输就得以继续下去,这样就使得被控器得到足够时间转移已经收到的数据字节,或者准备好即将发送的数据字节。带有CPU的被控器在对收到的地址字节做出应答之后,需要一定的时间去执行中断服务子程序,来分析或比较地址码,其间就把SCL线钳位在低电平上,直到处理妥当后才释放SCL线,进而使主控器继续后续数据字节的发送。
总线封锁状态
在特殊情况下,如果需要禁止所有发生在I2C总线上的通信活动,封锁或关闭总线是一种可行途径,只要挂接于该总线上的任意一个器件将时钟线SCL锁定在低电平上即可。 总线竞争的仲裁
总线上可能挂接有多个器件,有时会发生两个或多个主器件同时想占用总线的情况,这种情况叫做总线竞争。I2C总线具有多主控能力,可以对发生在SDA线上的总线竞争进行仲裁,其仲裁原则是这样的:当多个主器件同时想占用总线时,如果某个主器件发送高电平,而另一个主器件发送低电平,则发送电平与此时SDA总线电平不符的那个器件将自动关闭其输出级。总线竞争的仲裁是在两个层次上进行的。首先是地址位的比较,如果主器件寻址同一个从器件,则进入数据位的比较,从而确保了竞争仲裁的可靠性。由于是利用I2C总线上的信息进行仲裁,因此不会造成信息的丢失。
时钟信号的同步
在I2C总线上传送信息时的时钟同步信号是由挂接在SCL线上的所有器件的逻辑“与”完成的。SCL线上由高电平到低电平的跳变将影响到这些器件,一旦某个器件的时钟信号下跳为低电平,将使SCL线一直保持低电平,使SCL线上的所有器件开始低电平期。此时,低电平周期短的器件的时钟由低至高的跳变并不能影响SCL线的状态,于是这些器件将进入高电平等待的状态。当所有器件的时钟信号都上跳为高电平时,低电平期结束,SCL线被释放返回高电平,即所有的器件都同时开始它们的高电平期。其后,第一个结束高电平期的器件又将SCL线拉成低电平。这样就在SCL线上产生一个同步时钟。可见,时钟低电平时间由时钟低电平期最长的器件确定,而时钟高电平时间由时钟高电平期最短的器件确定。
i2c的有关图例:
参考博客:
http://blog.csdn.net/chuckfql/article/details/19834137
二、iomux
I OMUXC指IO多路复用控制器。由于imx6集成了很多的功能模块,BGA封装容纳不了那么多引脚,所以就想到用IOMUXC的方式来解决此问题,也即一个功能模块的引脚,通过n选1的多路开关,把需要的外设连接到该引脚上。要使用哪个功能,就需要配置引脚参数。
在实际开发中,具体的配置是通过IOMUXC_SW_MUX_CTL_PAD_(BGAcontact NAME,比如UART3_RXD)寄存器来实现,然后通过配套的寄存器
IOMUXC_SW_PAD_CTL_PAD_(PAD NAME, 比如UART3_RXD)来配置管脚的驱动电压,回转率,驱动强度,开漏,上拉, DDR 类型等等。
下面通过一个具体实例,来让大家有个认识:
在linux或android系统中,假如我们要配置飞思卡尔IMX6处理器的GPIO管脚,比如是GPIO_19这个管脚,那么要像这样:
? ?
#define MX6Q_PAD_GPIO_19__GPIO_4_5 \\
(_MX6Q_PAD_GPIO_19__GPIO_4_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
其中_MX6Q_PAD_GPIO_19__GPIO_4_5定义为:
? ?
#define _MX6Q_PAD_GPIO_19__GPIO_4_5 \\ IOMUX_PAD(0x0624, 0x0254, 5, 0x0000, 0, 0)
这个IOMUX_PAD宏是定义GPIO的关键宏,其原型为:
? ?
#define IOMUX_PAD(_pad_ctrl_ofs, _mux_ctrl_ofs, _mux_mode, _sel_input_ofs, _sel_input, _pad_ctrl)
IOMUX_PAD宏有6个参数,每个参数的意思是: 参数
_pad_ctrl_ofs _mux_ctrl_ofs
含义
控制寄存器的偏移地址(16进制)
MUX控制寄存器的偏移地址(16进制), 用于选择引脚的功能
_mux_mode _select_input_ofs _select_input
MUX模式,bit0~3,范围0~7
SELECT_INPUT寄存器偏移地址(16进制) Daisy Chain模式, bit0~1,范围0~3
_pad_ctrl bits to be set in register _pad_ctrl_ofs for configuration selection
具体的含义要结合IMX6数据手册【Chapter 36 IMOUX Controller(IOMUXC)】的内容。 下面看下IOMUX_PAD(0x0624, 0x0254, 5, 0x0000, 0, 0)中参数的在数据手册中的位置,请看截图。
1、_pad_ctrl_ofs
从图中可以看到_pad_ctrl_ofs=0624h
2、_mux_ctrl_ofs、_mux_mode
如上图,_mux_ctrl_ofs取值为0x254,_mux_mode范围为000~110
只有_mux_mode = 0时,_select_input_ofs和_select_input才有效,其余时候_select_input_ofs和_select_input 都为0。
I2c2的复用
结合上边对iomux的介绍,参考原理图,
Tianqian
在Iomux工具中ball中查看U5
再查看下图标记部分
看完原理图,结合iomux工具,再参考数据手册,配置把U5复用为i2c2_scl功能
参考博客:
http://blog.csdn.net/loongembedded/article/details/9986961
三、驱动
基本知识
在 Linux内核源代码中的 drivers 目录下包含一个 i2c 目录,而在 i2c 目录下又包含如下文件和文件夹。 (1)i2c-core.c。
这个文件实现了 I2C 核心的功能以及/proc/bus/i2c*接口。 (2)i2c-dev.c
实现了 I2C 适配器设备文件的功能,每一个 I2C 适配器都被分配一个设备。通过适配器访问设备时的主设备号都为89,次设备号为0~255。应用程序通过“i2c-%d” (i2c-0, i2c-1,?, i2c-10,?)文件名并使用文件操作接口 open()、write()、read()、ioctl()和 close()等来访问这个设备。 i2c-dev.c 并没有针对特定的设备而设计,只是提供了通用的 read()、write()和 ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的 I2C 设备的存储空间或寄存器,并控制 I2C 设备的工作方式。 (3)busses 文件夹。
这个文件中包含了一些 I2C 总线的驱动,如针对 S3C2410、S3C2440 和 imx等处理器的 I2C 控制器驱动为 i2c-imx.c。 (4)algos 文件夹。
实现了一些 I2C 总线适配器的 algorithm。
内核中的 i2c.h 这个头文件对 i2c_driver、i2c_client、i2c_adapter 和 i2c_algorithm 这 4
个数据结构进行了定义。理解这 4 个结构体的作用十分关键。
下面介绍下它们之间主要的关系和作用
1、i2c_adapter 与i2c_algorithm,i2c_adapter 对应于物理上的一个适配器,而i2c_algorithm对应一套通信方法。
一个I2C适配器需要i2c_algorithm中提供的通信函数来控制适配器上产生特定的访问周期。缺少i2c_algorithm 的i2c_adapter 什么也做不了,因此i2c_adapter 中包含其使用的i2c_algorithm的指针。
i2c_algorithm 中的关键函数master_xfer()用于产生I2C 访问周期需要的信号,以i2c_msg(即I2C消息)为单位。i2c_msg结构体也非常关键。
2、i2c_driver 与i2c_client,i2c_driver 对应一套驱动方法,是纯粹的用于辅助作用的数据结构,它不对应于任何的物理实体。i2c_client对应于真实的物理设备,每个I2C设备都需要一个i2c_client来描述。i2c_client一般被包含在I2C字符设备的私有信息结构体中。
3、i2c_adpater 与i2c_client,i2c_adpater 与i2c_client 的关系与I2C 硬件体系中适配器和设备的关系一致,即i2c_client 依附于i2c_adpater。
思考问题1:I2c总线设备和i2c总线上可挂载的i2c设备是在
Board-mx6q-sarbed的init board中初始化的,那么Board-mx6q-sarbed中init board是从什么时候开始执行的呢?
我们知道内核启动的过程大致为以下几步:
1.检查CPU和机器类型
2.进行堆栈、MMU等其他程序运行关键的东西进行初始化 3.打印内核信息
4.执行各种模块的初始化 5.挂接根文件系统 6.启动第一个init进程
在4步骤之后,start_kernel--->rest_init
__initcall_start和__initcall_end在源码中并无定义,只是在include/linux/init.h中申明为外部变量。
arm平台下,连接控制脚本为vmlinux.lds, 它们定义是在/arch/arm/vmlinux.lds中,看下图红色标记部分。
其含义是指示连接程序让__initcall_start指向代码节.initcall.init的节首,而__initcall_end指向.initcall.init的节尾。
在内核中,只要把需要初始化调用的函数的指针放在__initcall_start和__initcall_end之间的节内,函数就会在内核初始化时被调用。
加入到.initcall.init的代码段,是按如上方式调用的。主要是各个驱动模块。
Machine_desc的是怎么加载的呢?
先看下面几个截图中红色标记部分:
由上图可以看到,成员函数init_machine就是在这里被调用的。但是它没有被显式调用,而是放在了arch_initcall这个宏里,去看看它怎么定义的:
#define arch_initcall(fn) __define_initcall(\#define __define_initcall(level,fn,id) \\
static initcall_t __initcall_##fn##id __used \\
__attribute__((__section__(\ level \))) = fn
customize_machine()被放到了.initcall3.init里。
理解:在/include/linux/init.h文件中
#define pure_initcall(fn) __define_initcall(\#define core_initcall(fn) __define_initcall(\#define core_initcall_sync(fn) __define_initcall(\#define postcore_initcall(fn) __define_initcall(\#define postcore_initcall_sync(fn) __define_initcall(\#define arch_initcall(fn) __define_initcall(\
#define arch_initcall_sync(fn) __define_initcall(\#define subsys_initcall(fn) __define_initcall(\#define subsys_initcall_sync(fn) __define_initcall(\#define fs_initcall(fn) __define_initcall(\#define fs_initcall_sync(fn) __define_initcall(\
#define rootfs_initcall(fn) __define_initcall(\#define device_initcall(fn) __define_initcall(\#define device_initcall_sync(fn) __define_initcall(\#define late_initcall(fn) __define_initcall(\
#define late_initcall_sync(fn) __define_initcall(\以上部分,在内核编译的时候就被加入到了代码段。(/arch/armkernel/vmlinux.lds) 具体到我们这个例子,arch_initcall(customize_machine)也就是说customize_machine()在内核编译的时候由arch_initcall(fn)放到了.initcall3.init里。
思考问题2:那么这些被加入到代码段中的fn,是在哪被调用的呢?
回顾上面的内容,有提到过driver模块等是在/init/main.c里do_initcalls()的函数里被调用。
再接着看,machine_desc 加入了.arch.info.init代码段,它的函数调用关系:
start_kernel()-->setup_arch-->setup_machine_tags-->for_each_machine_desc开始调用.arch.info.init代码段中的fn。
machine_desc的结构体的赋值如下图描述:
总结:(这里主要说的是i2c和machine——)
各个i2c device 或是其他驱动放在.arch.init代码段中,这些加入代码段的fn,会被do_initcalls()调用,从/init/main.c文件中的开始内核代码谈起,调用顺序如下: start_kernel-->rest_init-->kernel_init-->do_basic_setup()-->do_initcalls()
machine_desc 加入了.arch.info.init代码段,它的函数调用关系:
start_kernel()-->setup_arch-->setup_machine_tags-->for_each_machine_desc()
I2c驱动的代码流程
结合上图,再联系前面提到的machine_desc和i2c的加载过程,可知: 首先,先将i2c总线作为platform设备加入到platform总线。将i2c设别加到i2c总线上,值得注意的是i2c总线驱动还未加载。
接着,加载i2c总线驱动,也就是调用i2c_imx.c中的初始化函数i2c_adap_imx_init。 最后,加载i2c设备驱动,也egalax tp驱动为例,即调用egalax_ts.c中的egalax_ts_init。
Dev下i2c设备节点
在查看开发板设备下我们发现存在:
那么i2c设备节点在那里创建的呢?
看如下截图,可知是初始化i2c_dev_init时,调用register_chrdev将i2c-dev加入一个map,这个map里有设备与操作的一一对应关系。只要打开这个设备文件,我们就能使用它所定义的操作了。
节点是调用i2c_for_each_dev时,回调i2cdev_attach_adapter创建。
Platform下的i2c
是由platform创建的
主要的函数调用关系:
mx6_sabresd_board_init-->imx6q_add_imx_i2c->imx_add_platform_device-->imx_add_platform
_device_dmamask-->platform_device_add,当platform_device_add执行时,它执行了如下图中操作:
整个探测过程完成后,回到device_add()函数,接着通过klist_add_tail()函数把设备imx-i2c.0挂到其父设备节点,也就是/sys/devices/platform。
下面在简单的分析一下平台设备驱动的注册过程,在i2c-imx.c中通过platform_driver_probe-->platform_driver_register()注册i2c平台设备驱动
最后此函数通过调用driver_register()函数对驱动进行注册。
具体的i2c设备的初始化
加载i2c设备驱动,以egalax tp驱动为例,即调用egalax_ts.c中的egalax_ts_init。下面截图是函数的调用关系,看红色标记部分(注意箭头方向,是向左的哦)。
接上图的i2c_register_driver
开始调用具体的驱动probe 如egalax就是:
执行到这,下边就会处理中断了。(对于i2c来说主要是数据的收发,另外,上报给input子系统)
注:适配器实现其通信方法,主要实现 i2c_algorithm 的 master_xfer()函数和 functionality()数。
master_xfer()函数在适配器上完成传递给它的 i2c_msg 数组中的每个 I2C消息 functionality()函数非常简单,用于返回 FUNC_I2C、I2C_ FUNC_10BIT_ADDR、I2C_FUNC_SMBUS_READ_BYTE、I2C_FUNC_SMBUS_WRITE_BYTE等。
思考问题3:上面调用到了master_xfer(),那么它是在哪初始化的呢?
大家是否记得,文章的上面提到过,在加载i2c总线驱动时,调用i2c_imx.c中
i2c_adap_imx_init函数对i2c_adapter 的数据结构进行了初始化。master_xfer()也是在这初始化的。具体情况情看下边截图,中红色标记的部分:
/sys/bus/i2c及/sys/bus/i2c/device和driver增加
I2c总线是在i2c-core.c中i2c_init-->bus_register时,会在/sys/bus/生成i2c及子目录device和driver目录
postcore_initcall(i2c_init),对于它大家应该不会陌生,它是一个宏定义,前边说过它在内核编译的时候就被加入到了代码段。(/arch/armkernel/vmlinux.lds).initcall2.init里。 start_kernel-->rest_init-->kernel_init-->do_basic_setup()-->do_initcalls()
/sys/bus/i2c/device和driver下的各个具体设备和驱动
/sys/bus/i2c/device下的各个具体设备的增加的函数调用关系如下:
i2c_imx_probe-->i2c_add_numbered_adapter-->i2c_register_adapter-->device_register-->device_add
/sys/bus/i2c/driver下的各个具体设备驱动的增加函数调用关系如下:
egalax_ts_init-->i2c_add_driver-->i2c_register_driver-->driver_register-->bus_add_driver-->kobject_init_and_add-->kobject_add_varg-->kobject_add_internal-->create_dir
总体来说,驱动的注册可以简单概况为: 1、在总线上找找该驱动有没有被注册过
2、若没有注册过,则将驱动加入到总线驱动集合中 3、在总线上找能匹配驱动的设备 1、将总线上每个设备进行匹配
2、首先用总线的match 函数进行低级匹配 3、然后在用总线的probe函数进行高级匹配,若失败,则用驱动上的probe 进行高级匹配
4、如果匹配成功,则将设备绑定到驱动链表中
4、如果匹配成功,则将驱动加入到总线的驱动链表中
思考问题4:Platform总线是在哪初始化?
start_kernel-->rest_init-->kernel_init-->do_basic_setup()-->drive_init()-->platform_bus_init()
4、如果匹配成功,则将驱动加入到总线的驱动链表中
思考问题4:Platform总线是在哪初始化?
start_kernel-->rest_init-->kernel_init-->do_basic_setup()-->drive_init()-->platform_bus_init()
正在阅读:
I2C驱动培训文档05-28
高一自我鉴定800字_自我鉴定范文07-30
夜大自我鉴定02-24
转正自我鉴定02-24
函授自我鉴定02-24
老年人便秘要吃什么保健品03-13
民间非营利组织制度02-02
英语听力原文答案05-28
2015年安全生产工作汇报提纲06-19
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 驱动
- 文档
- 培训
- I2C
- 中行抵押住房贷款合同范本
- 施工组织设计2
- 陶瓷工艺学考前复习题 2016.06 - 没有答案
- 新生儿科题目 (1)
- 理综八生物部分
- 安徽师范大学本科生优秀毕业论文(设计、创作)培育计划项目申请书
- 梧桐意象解读
- 线路复测分坑作业指导书
- 四川省风景名胜区管理条例
- 济南英盛生物遗传性耳聋基因检测
- 2016尔雅像经济学家那样思考期末考试答案
- 技工学校专业目录
- 2011-2014年同等学力计算机综合真题答案解析
- 李毅同志在深入推进五个提升开展项目建设年活动动员大会上的讲话
- 反洗钱自我测试题 2015年第5期 LYP版
- 预拌砂浆生产原料及选用
- 党建论文
- 在学校传染病会议主持词
- 人教2011版小学数学三年级《长方形和正方形的面积》课后习题
- 《学前教育科研方法》平时作业及答案