I2C总线级驱动详解

iic总线以及驱动详解

I2C是一种两线接口,有两条双向的线,一条叫时钟线(SCL),一条叫数据线(SDA)

系统中所有的外围器件都具有一个7位的从器件专用地址码,主器件通过地址码来建立多机通信的机制,所以I2C省去了对从器件的片选线,所以I2C不管总线上挂了多少个器件,系统依然是简约的二线结构

主机可以向从机传输数据,从机也可以向主机传送数据,但是从机不能发起传输,传输是受主设备控制的。

协议:

空闲状态:I2C总线的两条线在空闲状态的情况下,都是处于高点平的状态,也就是说,规定当两条线都处于高点平状态的时候,就是总线的空闲状态,此时各个器件的输出都在截止状态,也就是释放总线,两条信号线各自的上拉电阻将点平拉高

起始位:时钟线SCL在高电平期间,数据线从高到低的跳变,起始信号是电平跳变的信号,而不是一个电平信号,也就是边沿触发

停止位:当时钟线SCL在高电平的时候,数据线从低到高的跳变,停止信号也是一种时钟的跳变信号,不是一个电平信号,也就是边沿触发

应答信号:在第九个时钟周期的时候,数据线SDA是低电平就代表应答,第九个时钟周期的时候,数据线SDA持续高电平,就是非应答

数据有效性:

I2C总线进行数据传输的时候,时钟信号为高点平的时候,数据线上的数据必须保持稳定,时钟线上的信号为低电平期间,数据线上的高电平或者低电平状态才允许变化。

工作过程:总线上的每一次通信都是由主控器引发的

如果是主设备向从设备发送数据:

​ 主设备发送起始位,这个起始位会通知总线上的所有设备,传输开始了,接下来主机发送设备地址,和这个设备地址匹配的从机将继续这个传输过程,不匹配的从机就会忽略接下来的传输,直到他们停止之后的下一个起始位的到来。主设备寻址到从设备后,发送主设备要读取或者写入的从设备内部的寄存器地址,之后,发送数据,数据发送完毕之后,发送停止位。

写:

起始信号 + 从机地址7位写标志位1位(0) + 应答信号 + 寄存器地址8位或者16位 + 应答位 + 要写入的数据8位 + 应答位 + 要写入的数据 + 应答位 … + 停止位

读:

起始信号 + 从机地址7位写标志位1位(0) + 应答位 + 寄存器地址 + 应答位

起始信号 + 从机地址7位读标志位1位(1) + 应答位 + 读到的数据 + 应答位 + 读到的数据 + 应答位…+ 读到的数据 + 非应答位 + 停止位

特点:

​ 半双工:半双工是同一时刻只能一端向另一端发送数据,因为I2C只有两根线,两根线中只有一根数据线,所以同一时刻只能一端向另一端发送,所以是半双工

​ 串行:串行是一次只能发一位数据,也就是一位一位数据的发送,只有一根数据线,发数据当然就是串行的

​ 同步:因为有时钟线,所以发送端和接收端是时钟同步的

​ 数据发送的时候,先发数据高位在发送数据低位

所以I2C是一种半双工同步的串行总线协议,具备应答机制

I2C子系统API

分配对象
struct i2c_drivers{
	probe
	remove
	struct device_driver driver
}
struct device_driver{
	name="不用名字匹配但是必须填"
	struct of_device_id * of_match_table
}
struct of_device_id oftables[] = {
	{.compatible = "厂商名和设备名 和设备数匹配的关键信息"}
	{}
};

一键注册注销函数
module_i2c_driver(变量名)

关于I2C各种信息的结构体
struct i2c_client {
     unsigned short flags;  //i2c的标志位  I2C_M_TEN
     unsigned short addr;  //从机地址
     char name[I2C_NAME_SIZE];  //设备的名
     struct i2c_adapter *adapter;//控制器的对象
};

发送消息的结构体
struct i2c_msg {
     __u16 addr;     //从机地址 i2c_client->addr
     __u16 flags;    //读写标志位 0 写  1读
     __u16 len;  //消息的长度
     __u8 *buf;  //消息的首地址
};
有几个起始位就要封装几个消息

发送消息的函数
I2C_transfer

I2C子系统的设备树:

&i2c1{
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&i2c1_pins_b>;       //管脚复用,工作状态                           pinctrl-1 = <&i2c1_sleep_pins_b>; //管脚复用,休眠状态
    i2c-scl-rising-time-ns = <100>;   //scl上升沿和下降沿的时间                 	  i2c-scl-falling-time-ns = <7>;
    status = "okay";                  //使能控制器
    /delete-property/dmas;            //删除dma属性                             	/delete-property/dma-names;
    
    si7006@40{
        compatible = "hqyj,si7006";  //和设备驱动匹配的名字
        reg = <0x40>;                //从机地址
    };
};
在根节点的外边引用I2C节点,并且将自己的节点设为其子节点

I2C总线的仲裁机制:

I2C是一种多主机多从机的结构,既然是多主机结构,就会有多个主机同时使用I2C总线的情况,这时候会怎样分配?

线’与‘机制—>数据线发送后回读机制—>低电平优先机制

I2C总线具有多主控能力,可以对发生在数据总线上的总线之间的竞争进行仲裁,仲裁的机制就是两线想要输出的结果相与,按照相与之后的结果进行传送,由于I2C总线在传输的时候要对自己输出的电平位进行检测,只要检测的电平位和自己发送的不一致,就放弃竞争,如果一致,就会继续占用总线。

举个例子:

主机1想要发送101…,主机2想要发送1001…,

总线启动后,两个主控器都要发送自己的数据,同时发送第一位,相与之后还是1,两个总线检测电平发现和自己发送的电平一致,所以,这时,总线还是得不到仲裁,同理,第二位相与之后是0,也得不到仲裁,当发送第三位的时候,相与为0,主机1检测自己的输出电平,发现与自身不符合,就只能放弃对中线的控制权,所以,总线2就成为总线的唯一掌控者。可以看出,在这种线与机制下,那个主机先发低电平那个主机有优势。

整个仲裁的过程,主机1和主机2都不会丢失数据

各个主机没有对总线实施控制权的优先级,他们只是遵循,谁先发送低电平,谁先掌握总线的控制权

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值