• Linux内核之I2C协议


    I2C协议标准文档

    THE I2C-BUS SPECIFICATION VERSION 2.1 JANUARY 2000: https://www.csd.uoc.gr/~hy428/reading/i2c_spec.pdf
    I2C全称Inter-IC,又写作IIC,有些又归类为TWI(Two-Wire Interface).

    电路原理

    IIC仅由SDA数据线、SCL时钟线构成。并且两根线都需要接上拉电阻,原因是采用了OD门。

    OD门(Open Drain漏极开路)的作用:
    适用于 输出\输入
    单独使用时,可独立输出或输入低电平和高阻态(可理解为开路)

    • 我们只需要给一个上拉电阻产生高电平,在高阻态/开路的作用下,线路电平就会等同于上拉电阻的高电平;
    • 在低电平的作用下,线路电平仍然是低电平;
      所以接上拉电阻,可以让OD门有 输入\输出 高低电平 的功能,可以使用半双工,这就是通信的物理电路基础。

    高电平一般有1.8V 3.3V 5V 三种。
    上拉电阻阻值(3.3K~10K)与速度和容性负载相关,可以决定稳定性。
    image

    image

    而且标准文档还提供了不同电平之间的电路兼容方案
    image

    连接方式

    所有从机SDA都并联到主机上,所有从机SCK线都并联到主机SCL上。

    时序图

    关键点:
    空闲状态:SCL/SDA都是高电平。
    工作状态:SCL脉冲在高电平状态下指示SDA有效。

    经典的开始和结束信号

    SDA下降沿表示开始,上升沿表示结束

    image

    多机冲突与通讯
    有低电平的话,同一线上的都会被拉低。
    接到同一SCL线的都会被同步
    对端SDA的可判断电平不一致而打断操作。
    image
    image

    如果需要FPGA实现,还需要留意标准文档里的Table5和Fig.31的时间间隔要求。

    主要传输形式

    速度: 0100KHz400KHz~3.4MHz
    不同速度模式的设备混合接入总线系统,速度如表:
    image
    速度是需要“协商”的,如启用 High Speed Mode
    image

    保留地址作为管理码(master code),详见标准手册 10.1 Definition of bits in the first byte
    image

    开始条件S 8位管理码(00001xxx) 一位NACK
    image

    普通速率下传输数据(7地址模式)

    其数据可抽象简化为
    DEV_ADDR BYTE_DATA [..BYTE_DATA]

    发送设备地址(7位+R/W标识位) 另外也有10位地址的,就是两个地址字而已,用得少可以看标准文档。
    发送数据(8位一次)
    可选继续发送数据(每次也都是8位)

    每8位都需要从机回复一个A/A应答位。
    也就说,它是基于字节传输的超短距简单低速协议。
    I2C文档-时序

    I2C时序
    一般来说,I2C最适合用于读写寄存器,其数据形态与可以现有计算
    机/微机体系匹配,符合8/16/32/64位等以字节整倍数的寄存器。
    一个写入寄存器的例子(16位寄存器地址,32位寄存器数据): DEV_ADDR REG_ADDR0 REG_ADDR1 REG_DATA0 REG_DATA1 REG_DATA2 REG_DATA3
    Tips: 基于字节传输的协议都可以替代串口协议的部分应用场景。

    测试工具

    Linux上一般使用i2c-tools这个包的工具
    i2cdetect 用于扫描总线上挂接的从机设备地址。注意:非标设备不回复,则扫描不到。i2cdetect -y -r 0代表确认并以Read扫描一次IIC总线0下的所有非保留地址。把-r换成-q则表示以QUICK写模式扫描。
    i2cdump 用于读取某个i2c从机设备的所有寄存器数据。
    小技巧:当i2cdetect扫描不到的时候,可以用循环i2cdump抓出所有的从机设备数据,只要有数据的,说明该地址就有设备。

    关于i2cdetect不回复的问题排查,可以查看i2ctools源码: https://github.com/mozilla-b2g/i2c-tools/blob/master/tools/i2cdetect.c#L50

    其实就是从机要支持主机发送的 SMBUG_READ 指令
    image

    有个案例:https://bbs.aw-ol.com/topic/2304/分析笔记-linux-i2c-tools-使用踩坑笔记/2

    变种

    I2C的变种有 SMBUS MDIO I3C MIPI系等等协议。
    本质上都是1时钟线+1数据线,OD门实现双向高低电平。可并联。

    Linux内核I2C&SMBUS子系统 API文档

    see: https://www.kernel.org/doc/html/v5.14/driver-api/i2c.html
    文档路径 » The Linux driver implementer’s API guide » I2C and SMBus Subsystem
    SMBUS是I2C的兄弟协议,大部分SMBUS也是I2C,并且电气规定上比I2C更严格。

    (SoC)I2C控制器收发的内核API

    一些重要的结构体

    架构分层

    贴张经典老图,出处找不到了,侵权请联系

    image

    APP
    /dev/i2c-x (device文件节点)
    设备驱动driver


    i2c-Core I2C_Adapter (控制器)

    控制器一般是这样的:一般由I2C控制器的IP设计服务商给到SoC厂商,SoC厂商在处理器微电路设计适配后,仅放出寄存器给用户。所以我们用户只需要根据SoC数据手册对SoC寄存器操作即可。SoC会根据寄存器内容对控制器进行微电路操作的。

    SOC厂家的对接代码

    硬件上对应:
    n个SOC片上控制器 - Adapter
    n个从机硬件设备 - 一个Driver+多个同系列型号Device

    Adapter结构体里还包含了传输算法algo、独占操作lock_ops、适配器对应的device及其name、下挂的userspace_clients,总线恢复操作bus_rec、特性quirks、中断irq_domain等等。
    传输算法algo里面其实就是i2c和smbus的传输函数指针而已。

    总线API

    电源操作

    特性检测

    初始化/卸载操作

    向从机读写数据

    Linux内核I2C&SMBUS子系统架构

    从机设备驱动部分

    设备驱动编写:https://docs.kernel.org/i2c/writing-clients.html (较简单)

    I2C SysFs的:https://docs.kernel.org/i2c/i2c-sysfs.html
    用法:https://docs.kernel.org/i2c/instantiating-devices.html
    有以下几种为Linux内核创建I2C设备的方法(任选其一即可):

    • 结构信息

      • 设备树
      • ACPI(可以理解为X86的设备树)
    • 代码调用

      • 填充 struct i2c_board_info 结构体并使用i2c_new_client_device()创建
        image
      • 调用i2c_new_scanned_device() 等API函数
        image
    • 驱动里写

    • 用户空间使用sysfs接口

      • 例子echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device 或者delete_device

    核心 I2C-Core

    总线部分 BUS主控/片上外设驱动 Adapter

    这部分一般是原厂在弄

    从机设备节点

    从机设备驱动/板上外设驱动

    拿到新的IIC从机设备,首先就是根据其数据手册适配该外设的驱动

    我们要实现i2c_algorithm的transfer接口,才能完成对I2C主控/Soc的驱动适配。

    drivers/i2c

    除了一些 include/linux/i2c.h之类相关的头文件,剩下的实现都在 drivers/i2c
    src-file-tree

    i2c-core.h头文件主要是一个i2c_devinfo结构体和一些static inline静态内联函数定义

    image

    i2c-core-base.ccore层的实现,支撑了i2c-core-xxx.c的功能。
    i2c-core-of.c 是设备树的实现,主要是match、设备树sysfs导出、设备树属性reg host-notify wakeup-source 等支持,注册/反注册设备。
    i2c-core-acpi.c是X86特有的ACPI表(ACPI比ARM设备树更高级强大)
    i2c-core-slave.c是从机设备的核心支持,主要是从机模式选择、事件、注册/反注册的支持。
    i2c-core-smbus.c是SMBus支持。其读写最终会调用__i2c_smbus_xferadapter->algo->smbus_xfer()
    image

    xxx有acpi表、base、of设备树、从机slave、SMBUS等类型的注册/反注册。

    i2c-atr.c是I2C Address Translator地址翻译器的缩写,

    i2c-boardinfo.c 用于静态声明板载从机I2C设备。这个源码很少,仅有一个函数(加锁,然后把填充i2c_devinfo并加到i2c_board链表)。

    i2c-dev.c主要是SoC片上i2c总线控制器的驱动实现,即I2C主机设备字符驱动,代表了一个 i2c_adapter
    image

    i2c-mux.c是I2C多路总线驱动(Multiplexed I2C bus driver),用于支持控制器的多路通道设计。

    i2c-smbus.c是其SMBus驱动实现,几乎所有的I2C主控都是同时支持SMBus的。
    image
    i2c-stub.c是I2C/SMBus芯片模拟器
    image
    剩下的两个i2c-slave-eeprom.ci2c-slave-testuint.c都是I2C从机模拟器

    目录 drivers/i2c/algos下面是一些通用控制器的algo实现,比较古老了一般用不到,现在都是高度集成到SoC里了。目前实现了移位寄存器类型/PCF8584/PCA9564这几类拓展的适配器。放张PCF8584的框图欣赏一下,FPGA要实现也可以参考这种。
    image

    目录drivers/i2c/busses则较为庞大,是各厂家提供的总线驱动,遵守内核的i2c_adapter模型。SoC厂家可能会使用不同的IP定制,使得自家SoC能采用不同的I2C控制器,但是他们一般对片上外设的控制器是一致的,这个叫做总线控制。例如博通的[drivers/i2c/busses/i2c-bcm2835.c](struct bcm2835_i2c_dev {)
    和赛灵思的 drivers/i2c/busses/i2c-xiic.c ,虽然看起来复杂,但里面也基本都是ARM核通过寄存器配置片上外设(I2C控制器),比单片机裸机寄存器编程难,但也不会太难。
    这部分只有需要定制自己的SoC时才需要,一般能做SoC的都是原厂。

    目录drivers/i2c/muxes是一些板上外设的分线器/拓展器驱动,例如你SoC线不够用了,可以通过在板子上加个外设如PCA9544来拓展I2C的,让你1路变4路,多爽啊。
    image

    总结

    • i2c-core是内核对I2c的核心支持,最主要的就是提供了适配器模型,
    • 厂家提供的总线驱动drivers/i2c/busses都需要遵循这个适配器模型,而里面的操作基本都是写处理器的寄存器,由处理器最后去操作对应的控制器IP
    • 板载外设IIC设备的驱动编写则使用内核提供的Client API,见 https://docs.kernel.org/i2c/writing-clients.html
    • 板载外设IIC拓展器使用的是 drivers/i2c/muxes
    • SMBUS有自己的读写概念,所以额外实现。

    I2C例子:

    原厂写总线驱动

    SoC数据手册:https://docs.amd.com/r/en-US/ug1085-zynq-ultrascale-trm/I2C-Controllers
    代码:drivers/i2c/busses/i2c-xiic.c

    编写外设设备驱动

    基于I2C通信的DAC外设,数据手册:https://www.ti.com/lit/ds/symlink/dac7571.pdf?ts=1714157964385
    drivers/iio/dac/ti-dac5571.c


    __EOF__

  • 本文作者: YuCloud
  • 本文链接: https://www.cnblogs.com/yucloud/p/18157014/linux_kernel_i2c
  • 关于博主: love to create
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: Click【推荐】if the article helpful, and Welcome to discuss
  • 相关阅读:
    社区买菜系统 毕业设计 JAVA+Vue+SpringBoot+MySQL
    华为云IoT与OpenHarmony深度协同,加速设备上鸿即上云【云驻共创】
    SpringBoot : ch06 整合 web (一)
    Canal整合SpringBoot详解(二)
    进程间关系
    【使用 BERT 的问答系统】第 5 章 :BERT模型应用:问答系统
    JAVA基础算法(11)----- 最大二叉树
    目标检测:二维码检测方案
    【通信原理笔记】【二】随机信号分析——2.1 随机过程与其相关函数
    yum使用
  • 原文地址:https://www.cnblogs.com/yucloud/p/18157014/Linux_Kernel_I2C