赞
踩
I2C 总线,为两线式串行总线。
CPU与外设之间的数据通信采用两根信号线分别是:
SDA数据线以及SCL时钟控制信号线。
SDA:用于CPU与外设的数据传输。
SCL:用于同步双方的数据。
CPU在SCL为低电平时,将数据放在数据线上,那么设备在同周期的高电平,从数据线上获取数据。
串行:CPU和外设之间的数据通信是一个时钟周期传输一位。
总线:在SCL和SDA两根信号线上可以挂接多个外设。
示意图,如下:
上拉电阻:两个信号线,各界上一个上拉电阻,两根线默认都是高电平。
1. CPU是如何找到总线上某个具体的外设的呢?(设备地址)
2. CPU一旦找到某个具体的外设,如果通过两根线进行访问的呢?
3. SDA与SCL既然同时存在,是如何配合使用的呢?
SDA 可以由通信间双方进行控制。
SCL只能由CPU进行控制。
对于SDA,配置输入的一方,释放控制权;配置输出的一方,获取控制权。另,不能同时配置输出,但是可以同时配置输入,此时由上拉电阻控制。
又称起始信号,CPU访问总线上的某个外设,CPU先向总线上发送START信号。
至少需要两个周期:
第一个周期内:SDA 与 SCL 同为高电平。
第二个周期内:SCL 维持高电平,而SDA由高电平到低电平发生跳变。
即
SCL 保持高电平
SDA 由高电平到低电平发生跳变
结束信号。CPU要结束对设备的访问,CPU发送STOP信号。
SCL 保持高电平,而SDA 由低电平到高电平跳变,表示结束信号。
同一个总线上的各个外设,都有一个唯一的设备地址,表示设备在总线上的唯一性标志,外设的设备地址,由芯片厂家和设计原理图来决定。CPU欲访问总线上的某个外设,首先需要向该总线上发送这个设备的地址。
R/W读写位,如果是写设备,读写位为 0,读设备,读写位为 1.
注意,设备地址并不包括读写位,将读写位去除后,地址右移1位,高位补0,得到设备地址。
如:
读设备地址: 1010001
写设备地址: 1010000
实际的设备地址: 0101000
但是实际手册给出来的是这样的:
比如:
1 0 1 0 (A2) (A1) (A0) 0/1:
A2 A1 A0 位 接 上拉电阻而未接地 或者 接入高电平 那么该 3 bit 都取 1.
否则,如果都接地,那么都取 0. 那么得到设备地址
0 1 0 1 0 0 0 0 : 也就是 0X50 .
用于表示CPU和外设的一个交互的状态,表示CPU与外设进行通信时是否发生了错误,低电平为有效的ACK信号。
I2C 总线数据传输一次性只能传1个字节,一个周期,只能传 1个bit,从高位开始。
具体的操作,要看芯片手册时序图。
Linux内核I2C总线驱动
I2C总线的硬件其实本身包括两部分:
I2C硬件控制器(集成CPU内部),I2C外设本身
Linux内核对于I2C总线提出两种驱动
操作硬件就是I2C总线硬件控制器
仅仅负责发起硬件的操作时序,例如:START->设备地址|读写位->[ACK]->片内地址->[ACK]->片内数据->...
其中:
START信号,读写位,ACK,STOP信号都是标准的,固定的!
标准的信号硬件控制器能够自己产生!
但是设备地址,片内地址,片内数据是动态改变的,不确定的
这三个数据必须由用户来提供!用户需要将这三个数据告诉I2C总线驱动,来完成完整的传输过程
注意:I2C总线驱动都是由CPU的芯片厂家提供,驱动开发者只需配置内核支持I2C总线驱动即可:
make menuconfig
里面去选择 Device Driver --> I2C SUPPORT
管理的硬件仅仅是I2C外设本身
要给I2C总线提供三个重要的数据:设备地址,片内地址,片内数据
因为这三个对于I2C外设本身具有一定的意义和含义
将来I2C设备驱动将这三个数据发送给I2C总线驱动,I2C总线驱动完成最终的传输过程
此驱动是驱动开发的重点!
open,read,write,ioctl等对I2C外设进行读写操作
本质上就是I2C设备驱动和I2C总线驱动的一个桥梁
I2C总线驱动层(芯片厂家实现)
从I2C设备驱动层获取要访问的数据,最终操作硬件完成硬件的传输
问:如何实现linux内核I2C设备驱动程序呢?
明确:I2C设备驱动操作的硬件仅仅是I2C外设本身,获取用户要访问的数据,利用SMBUS提供的接口将数据丢给I2C总线驱动
I2C设备驱动的实现还是依赖:设备-总线-驱动编程模型
1.内核已经帮你定义好了一个虚拟总线i2c_bus_type
数据类型:struct bus_type
并且在这个总线上维护这两个链表:dev链表和drv链表
2.dev链表上每一个节点描述的I2C外设的硬件信息,对应节点的数据结构为 struct i2c_client,每当向dev链表添加一个I2C外设的硬件信息时,驱动只需要用i2c_client定义初始化和注册一个节点到dev链表即可,内核会帮你遍历drv链表,取出drv链表上每一个节点和这个硬件节点进行匹配,匹配通过 调用总线提供的match函数,match函数通过比较硬件节点i2c_client的name和软件节点i2c_driver的id_table的name,如果匹配成功,内核调用i2c_driver的probe函数,然后把匹配成功的硬件节点的首地址传递给probe函数,如果匹配不成功,没关系,起码硬件信息添加完成,静静等待着软件节点的到来
3.drv链表上每一个节点描述的I2C外设的软件信息,对应节点的数据结构为struct i2c_driver,每当向drv链表添加一个I2C外设的软件信息时,驱动只 需要用i2c_driver定义初始化和注册一个节点到drv链表即可,内核会帮你遍历dev链表,取出dev链表上每一个节点和这个软件节点进行匹配,匹配通过调用总线提供的match函数,match函数通过比较硬件节点i2c_client的name和软件节点i2c_driver的id_table的name,如果匹配成功,内核调用i2c_driver的probe函数,然后把匹配成功的硬件节点的首地址传递给probe函数,如果匹配不成功,没关系,起码软件信息添加完成,静静等待着硬件节点的到来
4.probe函数至于做什么事,完全由驱动开发者来决定
结论:如果要实现I2C设备驱动只需要关注:
切记切记:i2c外设的硬件信息的代码必须在平台代码中完成,不能动态加载和卸载
addr: I2C外设的设备地址
name: 硬件节点的名称,用于匹配
dev: 重点关注dev的void *platform_data,用来装载自定义的硬件信息
irq: 装载中断号
作用:描述I2C外设的硬件信息
切记:其中addr和name字段必须要进行初始化
说明:i2c_client不像platform_device,由驱动直接定义初始化和注册,需要利用另外一个数据结构来间接定义初始化和注册一个i2c_client,这个数据结构为:struct i2c_board_info
i2c_client 代表了一个外设的硬件,而 i2c_driver 是该外设硬件对象的“行为”,这是Linux 内核内部面向对象编程的一般方式。
type: 用于指定硬件信息的名称,将来这个字段会赋值给i2c_client的name
addr: 保存I2C外设的设备地址,将来这个字段会赋值给i2c_client的addr
platform_data: 装载自定义的硬件信息,将来会赋值给i2c_client的dev的platform_data
irq: 中断号,会赋值给i2c_client的irq
作用:用来指定I2C外设的硬件信息,将来内核根据这个硬件信息来间接定义初始化和注册一个i2c_client
注意:如果将来向内核添加一个i2c外设的硬件信息,现在无需对i2c_client进 行直接定义,初始化和注册,只需对i2c_board_info进行定义初始化和注册即可,将来内核会根据你注册的硬件信息会帮你定义初始化和注册i2c_client
切记切记:i2c外设的硬件信息的代码必须在平台代码中完成,不能动态加载和卸载
1. 需要在平台代码中,添加以下对象
2. 在平台代码的某个函数中进行注册硬件信息到内核,注册的方法:
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
功能:注册I2C外设硬件信息到内核
busnum:I2C外设所在的总线编号,通过原理图获取所在的总线编号
info:定义初始化的i2c_board_info对象
len:硬件信息的个数
结果:一旦完成I2C外设的注册,将来内核根据以上信息会帮你定义初始化和注册一个i2c_client
要编 image ,不能动态加载卸载,没开发板,就罢了,试验就罢了...
platform分离机制能够应用于任何一个硬件设备!
i2c分离机制仅仅应用于硬件接口为I2C接口的硬件设备!
对于X86架构,支持两类总线,一类总线的位宽为16位,地址空间为64K,这个地址空间又称IO空间,如果把一个外设连接到这类总线,CPU访问这个外设只能通过in,out两条特殊的指令;还有另一个类总线位宽为32位,地址空间为4G,这个地址空间又称内存空间,如果把一个外设连接到这类总线上,CPU访问这个外设通过地址指针的形式访问即可;以上两个地址空间CPU能够直接寻址!
对于ARM架构,没有IO空间,只有内存空间!
所以如果将来要访问某个外设,一定一定要搞清楚这个外设的地址!一旦搞定这个外设的地址,软件只需利用指针的形式访问即可!
通过芯片手册和原理图
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。