导图社区 I2C
这是一篇关于I2C的思维导图,详细的总结了数据结构关系,体系结构,总线工作原理的内容点。有需要的小伙伴可以下载收藏哦!
编辑于2022-12-06 11:39:22 浙江省这是一篇关于程序和库信息的思维导图,主要内容包括:(查看基础信息),获取ELF节的长度信息,显示可执行文件或库需要静态加载的动态库完整列表--显示加载时的依赖项,列出二进制文件的节信息,查看动态节,列出并查看段,查看重定位节,反汇编,列出库中未定义的符号,列出动态符号,列出二进制文件或库的符号表,查看节中的数据,符号的类型。
这是一篇关于设备驱动的思维导图,主要内容包括:主要功能,设备驱动模型。阐述了设备驱动的主要功能、信号定义、设备驱动模型等内容。
这是一篇关于算法的思维导图,主要内容包括:云计算,内存管理算法,分布式同步算法,避免死锁算法,进程调度算法,磁盘调度算法。
社区模板帮助中心,点此进入>>
这是一篇关于程序和库信息的思维导图,主要内容包括:(查看基础信息),获取ELF节的长度信息,显示可执行文件或库需要静态加载的动态库完整列表--显示加载时的依赖项,列出二进制文件的节信息,查看动态节,列出并查看段,查看重定位节,反汇编,列出库中未定义的符号,列出动态符号,列出二进制文件或库的符号表,查看节中的数据,符号的类型。
这是一篇关于设备驱动的思维导图,主要内容包括:主要功能,设备驱动模型。阐述了设备驱动的主要功能、信号定义、设备驱动模型等内容。
这是一篇关于算法的思维导图,主要内容包括:云计算,内存管理算法,分布式同步算法,避免死锁算法,进程调度算法,磁盘调度算法。
I2C
体系结构
I2C核心
提供了I2C总线驱动和设备驱动的注册 注销方法 I2C通信方法 为系统中每个I2C总线增加相应的读写方法
I2C总线驱动
对I2C硬件体系结构中适配器端的实现 总线驱动的职责是为系统中每个I2C总线增加相应的读写方法 总线驱动本身并不会进行任何通信
I2C设备驱动
I2C设备驱动是对I2C硬件体系结构中设备端的实现 设备驱动是与挂在I2C总线上具体设备通信的驱动 设备一般是挂接在受控的I2C适配器上 通过I2C适配器与CPU交换数据
相关寄存器
IICCON
用于控制是否发出ACK信号 设置发送器的时钟 开启I2C中断 标识中断是否发生
IICSTAT
用于选择I2C接口的工作模式 发送S信号 P信号 使能接收/发送功能 并标识各种状态
IICADD
位[1:7]表示从机地址 IICADDR寄存器在串行输出使能位IICSTAT[4]=0时才可以写入 任何时间都可以读出
IICDS
位[0:7]保存要发送或已经接收的数据 在串行输出使能位IICSTAT[4]=1时才可以写入 任何时间都可以读出
工作原理
i2c总线是由数据线SDA和时钟SCL构成的串行总线 每个器件都由一个唯一的地址 可作为总线上的一个发送器件或接收器件
信号状态
空闲状态
SDA和SCL都为高电平
开始条件
SCL为高电平时 SDA由高电平向低电平跳变 开始传送数据
结束条件
SCL为低电平时 SDA由低电平向高电平跳变 结束传送数据
数据有效
在SCL的高电平期间 SDA上传输的数据保持稳定 SDA上的数据只能在SCL为低电平期间变化
ACK信号
数据传输的过程中 接收器件每接收一个字节数据要产生一个ACK信号 向发送器件发出特定的低电平脉冲 表示已经收到数据
例外
当从机不能响应从机地址时(设备正忙或这个地址没有对应设备)会没有ACk信号 这时主机会发生出一个P信号终止传输或者重新发送一个S信号开始新的传输
如果从机接收器在传输过程中不能接收更多的数据时 也不会发出ACK信号 从而主机就会发出一个P信号终止传输或者重新发送一个S信号开始新的传输
主机接收器在接收到最后一个字节后 不会发出ACK信号 于是从机发生器释放SDA线以允许主机发出P信号结束传输
基本流程
I2C总线必须由主器件控制 主器件产生串行时钟SCL 同时控制总线的传输方向 并产生开始和停止条件 数据传输中首先主器件产生开始条件 随后是器件的控制字节(7位从器件地址+1位读写标识) 接下来是读写数据的操作 以及ACK响应型号 数据传输结束后 主器件产生停止条件
时序
i2c单字节读时序
1)、主机发送起始信号 2)、主机发送要读取的 I2C 从设备地址 3)、读写控制位,因为是向 I2C 从设备发送数据,因此是写信号 4)、从机发送的 ACK 应答信号 5)、重新发送 START 信号 6)、主机发送要读取的寄存器地址 7)、从机发送的 ACK 应答信号 8)、重新发送 START 信号 9)、重新发送要读取的 I2C 从设备地址 10)、读写控制位,这里是读信号,表示接下来是从 I2C 从设备里面读取数据 11)、从机发送的 ACK 应答信号 12)、从 I2C 器件里面读取到的数据 13)、主机发出 NO ACK 信号,表示读取完成,不需要从机再发送 ACK 信号了 14)、主机发出 STOP 信号,停止 I2C 通信
i2c单字节写时序
1)、开始信号。 2)、发送 I2C 设备地址 3)、I2C 器件地址后面跟着一个读写位,为 0 表示写操作,为 1 表示读操作。 4)、从机发送的 ACK 应答信号。 5)、重新发送开始信号。 6)、发送要写写入数据的寄存器地址。 7)、从机发送的 ACK 应答信号。 8)、发送要写入寄存器的数据。 9)、从机发送的 ACK 应答信号。 10)、停止信号。
传输格式
I2C控制器内部结构
数据结构关系
匹配成功的条件是什么?
设备是什么时候加入到总线上的?
static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; if (!driver_match_device(drv, dev)) return 0; if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev); device_unlock(dev); if (dev->parent) device_unlock(dev->parent); return 0; }
判断设备和驱动是否匹配
int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int (*fn)(struct device *, void *)) { struct klist_iter i; struct device * dev; int error = 0; klist_iter_init_node(&bus->klist_devices, &i, (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); return error; }
int driver_attach(struct device_driver *drv) { return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); }
这张图中的链表是 i2c bus 下的kset。 kset、kobject、parent和list,在权威书籍LDD3-chapter14(linux设备驱动)中有一个很经典的图
创建 sys/bus/i2c/at24
kobject_init_and_add
static struct i2c_driver at24_driver = { .driver = { .name = "at24", .owner = THIS_MODULE, .bus=&i2c_bus_type }, .probe = at24_probe, .remove = at24_remove, .id_table = at24_ids, .p= ... };
复制的左边
struct driver_private { struct kobject kobj; struct klist klist_devices; struct klist_node knode_bus; struct module_kobject *mkobj; struct device_driver *driver; };
bus_add_driver 新建一个内存结点
int bus_add_driver(struct device_driver *drv) { struct bus_type *bus; struct driver_private *priv; int error = 0; bus = bus_get(drv->bus); if (!bus) return -EINVAL; pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { error = -ENOMEM; goto out_put_bus; } klist_init(&priv->klist_devices, NULL, NULL); priv->driver = drv; drv->p = priv; priv->kobj.kset = bus->p->drivers_kset; error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name); if (error) goto out_unregister; klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); if (error) { printk(KERN_ERR "%s: uevent attr (%s) failed\n", __func__, drv->name); } error = driver_add_groups(drv, bus->drv_groups); if (error) { /* How the hell do we get out of this pickle? Give up */ printk(KERN_ERR "%s: driver_create_groups(%s) failed\n", __func__, drv->name); } if (!drv->suppress_bind_attrs) { error = add_bind_files(drv); if (error) { /* Ditto */ printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __func__, drv->name); } } return 0; out_unregister: kobject_put(&priv->kobj); kfree(drv->p); drv->p = NULL; out_put_bus: bus_put(bus); return error; }
kobject_init_and_add 比较重要
这个新的priv结构体 和driver就是 一一对应的关系
drv->name="at24"
int driver_register(struct device_driver *drv) { int ret; struct device_driver *other; BUG_ON(!drv->bus->p); if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown)) printk(KERN_WARNING "Driver '%s' needs updating - please use " "bus_type methods\n", drv->name); other = driver_find(drv->name, drv->bus); if (other) { printk(KERN_ERR "Error: Driver '%s' is already registered, " "aborting...\n", drv->name); return -EBUSY; } ret = bus_add_driver(drv); if (ret) return ret; ret = driver_add_groups(drv, drv->groups); if (ret) { bus_remove_driver(drv); return ret; } kobject_uevent(&drv->p->kobj, KOBJ_ADD); return ret; }
driver_find 会执行 从I2c总线上查找同名设备
struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, };
nt i2c_register_driver(struct module *owner, struct i2c_driver *driver) { int res; /* Can't register until after driver model init */ if (unlikely(WARN_ON(!i2c_bus_type.p))) return -EAGAIN; /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; /* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */ res = driver_register(&driver->driver); if (res) return res; pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ i2c_for_each_dev(driver, __process_new_driver); return 0; }
#define i2c_add_driver(driver) \ i2c_register_driver(THIS_MODULE, driver)
i2c_driver
driver
name
owner
bus
probe
remove
id_table
static struct i2c_driver at24_driver = { .driver = { .name = "at24", .owner = THIS_MODULE, .bus=&i2c_bus_type }, .probe = at24_probe, .remove = at24_remove, .id_table = at24_ids, };
module_init(at24_init);
static int __init at24_init(void) { if (!io_limit) { pr_err("at24: io_limit must not be 0!\n"); return -EINVAL; } io_limit = rounddown_pow_of_two(io_limit); return i2c_add_driver(&at24_driver); } module_init(at24_init); static void __exit at24_exit(void) { i2c_del_driver(&at24_driver); } module_exit(at24_exit);