I2C总线
PHILIPS公司开发的两线式串行总线
GPIO模拟i2c驱动中有自己的一套传输算法。GPIO模拟I2C是要占用CPU资源的,而用I2C芯片是不占CPU资源的
特点
接口线少,控制方式简单,器件封装形式小,通信速率较高
特征
- 一条串行数据线SDA,一条串行时钟线SCL
- 它是一个真正的多主机总线,如果两个或更多主机同时初始化,数据传输可以通过冲突检测和仲裁防止数据被破坏
- 串行的8位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s
- 连接到相同总线的IC数量只受到总线的最大电容400pF限制
架构
- I2C core框架
提供了核心数据结构的定义和相关接口函数,用来实现I2C适配器。驱动和设备驱动的注册、注销管理
实现在/drivers/i2c目录下的i2c-core.c和i2c-dev.c - I2C总线驱动
定义描述具体I2C总线适配器的i2c_adapter数据结构、实现在具体I2C适配器上的I2C总线通信方法,并由i2c_algorithm数据结构进行描述。 经过I2C总线驱动的的代码,可以为我们控制I2C产生开始位、停止位、读写周期以及从设备的读写、产生ACK等
实现在/drivers/i2c目录下busses文件夹。例如:Linux I2C GPIO总线驱动为i2c_gpio.c;I2C总线算法在/drivers/i2c目录下algos文件夹。例如:Linux I2C GPIO总线驱动算法实现在i2c_algo_bit.c - I2C设备驱动
对具体I2C硬件驱动的实现。I2C 设备驱动通过I2C适配器与CPU通信。其中主要包含i2c_driver和i2c_client数据结构,i2c_driver结构对应一套具体的驱动方法,例如:probe、remove、suspend等,需要自己申明;i2c_client数据结构由内核根据具体的设备注册信息自动生成
实现在/drivers/i2c目录下chips文件夹
设备连接图
波形图
开始信号:当SCL为高电平时,SDA由高电平向低电平跳变,表示将要开始传输数据
结束信号:当SCL为高电平时,SDA由低电平向高电平跳变,表示结束传输数据
i2c_client
struct i2c_client
{
unsigned short flags; //标志位
unsigned short addr; //设备的地址,低7位为芯片地址
char name[I2C_NAME_SIZE]; //设备的名称,最大为20个字节
struct i2c_adapter *adapter; //依附的适配器i2c_adapter,适配器指明所属的总线
struct i2c_driver *driver; //指向设备对应的驱动程序
struct device dev; //设备结构体
int irq; //设备申请的中断号
struct list_head list; //连接到总线上的所有设备
struct list_head detected; //已经被发现的设备链表
struct completion released; //是否已经释放的完成量
};
地址码
1101000x
读地址:11010001 = 0xd1
写地址:11010000 = 0xd0
设备地址:01101000 = 0x68 //高位补0 地址码
i2c_driver
struct i2c_driver
{
int id; //驱动标识ID
unsigned int class; //驱动的类型
int (*attach_adapter)(struct i2c_adapter *); //当检测到适配器时调用的函数
int (*detach_adapter)(struct i2c_adapter *); //卸载适配器时调用的函数
int (*detach_client)(struct i2c_client *) __deprecated; //卸载设备时调用的函数
/*以下是一种新类型驱动需要的函数,这些函数支持IIC设备动态插入和拔出。如果不想支持只实现上面3个。要不实现上面3个。
要么实现下面5个。不能同时定义*/
int (*probe)(struct i2c_client *, const struct i2c_device_id *); //新类型设备探测函数
int (*remove)(struct i2c_client *); //新类型设备的移除函数
void (*shutdown)(struct i2c_client *); //关闭IIC设备
int (*suspend)(struct i2c_client *, pm_messge_t mesg); //挂起IIC设备
int (*resume)(struct i2c_client *); //恢复IIC设备
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); //使用命令使设备完成特殊的功能。类似ioctl()函数
struct devcie_driver driver; //设备驱动结构体
const struct i2c_device_id *id_table; //设备ID表
int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *); //自动探测设备的回调函数
const struct i2c_client_address_data *address_data; //设备所在的地址范围
struct list_head clients; //指向驱动支持的设备
};
i2c_adapter
struct i2c_adapter
{
struct module *owner; //模块计数
unsigned int id; //alogorithm的类型,定义于i2c_id.h中
unsigned int class; //允许探测的驱动类型
const struct i2c_algorithm *algo; //指向适配器的驱动程序
void *algo_data; //指向适配器的私有数据,根据不同的情况使用方法不同
int (*client_register)(struct i2c_client *); //设备client注册时调用
int (*client_unregister(struct i2c_client *); //设备client注销时调用
u8 level;
struct mutex bus_lock; //对总线进行操作时,将获得总线锁
struct mutex clist_lock; //链表操作的互斥锁
int timeout; //超时
int retries; //重试次数
struct device dev; //指向适配器的设备结构体
int nr;
struct list_head clients; //连接总线上的设备的链表
char name[48]; //适配器名称
struct completion dev_released; //用于同步的完成量
};
i2c_algorithm
struct i2c_algorithm
{
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msg, int num);
//传输函数指针,指向实现IIC总线通信协议的函数,用来确定适配器支持那些传输类型
int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size,
union i2c_smbus_data *data); /*smbus方式传输函数指针,指向实现SMBus总线通信协议的函数。
SMBus和IIC之间可以通过软件方式兼容,所以这里提供了一个函数,但是一般都赋值为NULL*/
u32 (*functionality)(struct i2c_adapter *); //返回适配器支持的功能
};
i2c_msg
struct i2c_msg
{
__u16 addr; //IIC设备地址。这个字段说明一个适配器在获得总线控制权后,可以与多个IIC设备进行交互
__u16 flags; //消息类型标志
__u16 len; //消息字节长度
__u8 *buf; //指向消息数据的缓冲区
};
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_driver 与 i2c_client
i2c_driver 对应一套驱动方法,是纯粹的用于辅助作用的数据结构,它不对应于任何的物理实体。 i2c_client 对应于真实的物理设备,每个 I2C 设备都需要一个 i2c_client 来描述。 i2c_client 一般被包含在 i2c 字符设备的私有信息结构体中
i2c_driver 与 i2c_client 发生关联的时刻在 i2c_driver 的 attach_adapter() 函数被运行时。 attach_adapter() 会探测物理设备,当确定一个 client 存在时,把该 client 使用的 i2c_client 数据结构的 adapter 指针指向对应的 i2c_adapter
driver 指针指向该 i2c_driver ,并会调用 i2c_adapter 的 client_register() 函数。相反的过程发生在 i2c_driver 的 detach_client() 函数被调用的时候
i2c_adpater 与 i2c_client
i2c_adpater 与 i2c_client 的关系与 I2C 硬件体系中适配器和设备的关系一致,即 i2c_client 依附于 i2c_adpater 。由于一个适配器上可以连接多个 I2C 设备,所以一个 i2c_adpater 也可以被多个 i2c_client 依附, i2c_adpater 中包括依附于它的 i2c_client 的链表
SMBus
SMBus 是 I2C 的子集
- i2c_smbus_read_byte
从设备读取一个字节(不定义位置偏移,使用以前发起的命令的偏移)。意义不大,无基地址 - i2c_smbus_write_byte
从设备写入一个字节(使用以前发起的命令的偏移) - i2c_smbus_write_quick
向设备发送一个比特 - i2c_smbus_read_byte_data
从设备指定偏移处读取一个字节。第一个msg用来传送读的基地址,第二个msg用来读取数据 - i2c_smbus_write_byte_data
向设备指定偏移处写入一个字节。传送两个msg - i2c_smbus_read_word_data
从设备指定偏移处读取二个字节 - i2c_smbus_write_word_data
向设备指定偏移处写入二个字节 - i2c_smbus_read_block_data
从设备指定偏移处读取一块数据 - i2c_smbus_write_block_data
向设备指定偏移处写入一块数据(<= 32 字节)
上面的一系列函数最终都是调用的i2c_smbus_xfer()函数
/**
* i2c_smbus_xfer - execute SMBus protocol operations
* @adapter: Handle to I2C bus
* @addr: Address of SMBus slave on that bus
* @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC)
* @read_write: I2C_SMBUS_READ or I2C_SMBUS_WRITE
* @command: Byte interpreted by slave, for protocols which use such bytes
* @protocol: SMBus protocol operation to execute, such as I2C_SMBUS_PROC_CALL
* @data: Data to be read or written
*
* This executes an SMBus protocol operation, and returns a negative
* errno code else zero on success.
*/
s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
char read_write, u8 command, int protocol,
union i2c_smbus_data *data)
{
unsigned long orig_jiffies;
int try;
s32 res;
/* If enabled, the following two tracepoints are conditional on
* read_write and protocol.
*/
trace_smbus_write(adapter, addr, flags, read_write,
command, protocol, data);
trace_smbus_read(adapter, addr, flags, read_write,
command, protocol);
flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
if (adapter->algo->smbus_xfer) {
i2c_lock_adapter(adapter);
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (res = 0, try = 0; try <= adapter->retries; try++) {
res = adapter->algo->smbus_xfer(adapter, addr, flags,
read_write, command,
protocol, data);
if (res != -EAGAIN)
break;
if (time_after(jiffies,
orig_jiffies + adapter->timeout))
break;
}
i2c_unlock_adapter(adapter);
if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
goto trace;
/*
* Fall back to i2c_smbus_xfer_emulated if the adapter doesn't
* implement native support for the SMBus operation.
*/
}
res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
command, protocol, data);
trace:
/* If enabled, the reply tracepoint is conditional on read_write. */
trace_smbus_reply(adapter, addr, flags, read_write,
command, protocol, data);
trace_smbus_result(adapter, addr, flags, read_write,
command, protocol, res);
return res;
}
EXPORT_SYMBOL(i2c_smbus_xfer);
首先在判断主控制器是否支持smbus_xfer传输,但是通常i2c主控制器都是不支持的,所以直接调用i2c_smbus_xfer_emulated()函数
I2C总线的更多相关文章
- I2C总线(异步)
起始位与停止位的定义: 起始信号:当SCL为高期间,SDA由高到低的跳变:启动信号是一种电平跳变时序信号,而不是一个电平信号. 停止信号:当SCL为高期间,SDA由低到高的跳变:停止信号也是一种电平跳 ...
- i2c总线,设备,驱动之间的关系
------ 总线上先添加好所有具体驱动,i2c.c遍历i2c_boardinfo链表,依次建立i2c_client, 并对每一个i2c_client与所有这个线上的驱动匹配,匹配上,就调用这个驱动的 ...
- [I2C]I2C总线协议图解
转自:http://blog.csdn.net/w89436838/article/details/38660631 1 I2C总线物理拓扑结构 I2C 总线在物理连接上非常简单,分别由S ...
- Linux设备驱动模型之I2C总线
一.I2C子系统总体架构 1.三大组成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C总线驱动(适配器)和设备驱动的注册.注销方法,提供了与具体硬件无关的I2C读写函数. (2)I2 ...
- I2C总线和S5PV210的I2C总线控制器
一.什么是I2C通信协议? 1.物理接口:SCL + SDA (1)SCL(serial clock):时钟线,传输CLK信号,一般是I2C主设备向从设备提供时钟的通道. (2)SDA(serial ...
- I2C总线协议的简要说明
为了快速的了解I2C总线协议,此处采用另类的方式进行说明. 倘若你和另外一个人只能通过一个开关加灯泡的装置在不同的两个房间进行交流,以下是很简单能说明的一个模型: 你的房间有一个开关,另外一间房间有一 ...
- Linux+I2C总线分析(主要是probe的方式)
Linux I2C 总线浅析 ㈠ Overview Linux的I2C体系结构分为3个组成部分: ·I2C核心: I2C核心提供了I2C总线驱动和设备驱动的注册.注销方法,I2C通信方法(即“algo ...
- Linux I2C总线控制器驱动(S3C2440)
s3c2440的i2c控制器驱动(精简DIY),直接上代码,注释很详细: #include <linux/kernel.h> #include <linux/module.h> ...
- Linux I2C总线设备驱动模型分析(ov7740)
1. 框架1.1 硬件协议简介1.2 驱动框架1.3 bus-drv-dev模型及写程序a. 设备的4种构建方法a.1 定义一个i2c_board_info, 里面有:名字, 设备地址 然后i2c_r ...
- I2C 总线协议
1.I2C协议 2条双向串行线,一条数据线SDA,一条时钟线SCL. SDA传输数据是大端传输,每次传输8bit,即一字节. 支持多主控(multimastering),任何时间点只能 ...
随机推荐
- PHPUnit 单元测试教程
一.官网下载对应 PHP 版本的代码库 https://phpunit.de/getting-started-with-phpunit.html 二.安装 PHPUnit 官网提供了两种方法安装 1. ...
- kotlin基础 字符串模板
${变量名} var tmp="字符串模板” print("今天学习${tmp}这个知识点")
- leetcode 968. Binary Tree Cameras
968. Binary Tree Cameras 思路:如果子节点只能覆盖到父节点.当前节点,但是父节点可以覆盖到他的父节点.子节点.当前节点,所以从叶子节点往上考虑 0代表子节点没有被覆盖 1代表子 ...
- 工控随笔_23_WinCC报Application CCArchiveConnMon.exe could not establish a connection to the Win CC license server
西门子的软件都是比较庞大的,安装一个软件要很长时间,而且安装的过程中很容易因为系统兼容性问题导致不能成功安装的情况, 而有时还会出现安装成功,但是不能正常使用的情况.这个时候就很麻烦,一般除了重装系统 ...
- UltraISO制作启动U盘
使用UltraISO可以制作纯净版本启动U盘 下载 下载地址https://cn.ultraiso.net/ 打开ISO镜像 下载后双击安装完成以后打开软件 文件-打开-选择一个ISO镜像,例如win ...
- CVE-2019-16278-Nostromo Web Server远程代码执行
本文主题主要是分析CVE-2019-16278漏洞原因.漏洞如何利用以及为什么会受到攻击.这个CVE跟Nostromo Web服务器(又名nhttpd)有关,这个组件是在FreeBSD,OpenBSD ...
- python从写定时器学习Thread
目录 python从写定时器学习Thread Timer 对象 粗陋的循环定时器 更 pythonic 循环定时器 FAQ python从写定时器学习Thread python 如何写一个定时器,循环 ...
- Redis 分布式锁,C#通过Redis实现分布式锁(转)
目录(?)[+] 分布式锁一般有三种实现方式: 可靠性 分布式锁一般有三种实现方式: 1. 数据库乐观锁; 2. 基于Redis的分布式锁; 3. 基于ZooKeeper的分布式锁.本篇博客将介绍 ...
- C# web项目乱码问题解决
在 web.config 文件中添加代码 <globalization requestEncoding="GB2312" responseEncoding="GB ...
- B+树比B树更适合实际应用中操作系统的文件索引和数据库索引
B+树比B树更适合实际应用中操作系统的文件索引和数据库索引 为什么选择B+树作为数据库索引结构? 背景 首先,来谈谈B树.为什么要使用B树?我们需要明白以下两个事实: [事实1]不同容量的存储器, ...