【kernel9】i2c协议,smbus,设备添加


1.I2C协议:总线空闲的时SCL和SDA处于高电平,I2C总线标准模式下速度可达100Kb/S,快速模式下可达400Kb/S

在这里插入图片描述

i2c-dev.c是通用驱动。
在这里插入图片描述
在这里插入图片描述
I2C读时序(i2cget):如下sda写W低(所有都是scl高时,sda才生效),一个主机可控制多个从机,使用7位地址,最多可使用128个唯一地址,如下发送数据是读出的值。
在这里插入图片描述
i2c没有像spi片选线,主机将从机地址发给每个从机比较(寻址),匹配则向主机发送低电平ACK,不匹配则SDA保持高。
在这里插入图片描述
如下A表示ACK,逻辑分析仪一个接SDA,一个接SCL,一个接地。
在这里插入图片描述
I2C写时序(i2cset):
在这里插入图片描述

2.SMBUS:是I2C的一个子集

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

#include "stdio.h"
#include "stdlib.h"
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned char u8;
#define POLY    (0x1070U << 3)

static u8 crc8(u16 data)
{
   
    int i;
    for (i = 0; i < 8; i++) {
   
        if (data & 0x8000)
            data = data ^ POLY;
        data = data << 1;
    }
    return (u8)(data >> 8);
}

static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
{
   
    int i;
    for (i = 0; i < count; i++)
        crc = crc8((crc ^ p[i]) << 8);
    return crc;
}

int main()
{
   
    u8 pec;
    char buf[12] = {
   0xcc};   // cc是8位即addr(0x66)+写(0)
    char buf0[12] = {
   0xcd};  // cd是addr+读
    char buf1[12] = {
   0x88};  // 读的寄存器地址
    char buf2[12] = {
   0xc2,0xe0};  // 读出的数据
    pec = i2c_smbus_pec(0, buf, 1);
    pec = i2c_smbus_pec(pec, buf1, 1);
    pec = i2c_smbus_pec(pec, buf0, 1);
    pec = i2c_smbus_pec(pec, buf2, 2);
    printf("test===0x%x\n",pec);  // 正常解析前5个字节的crc8打印出0x3d,如果前面数据有错误,则打印出0xff,pec会多retry几次。
    return 0;
}

在这里插入图片描述

i2ctools

--:地址被探测了,但没有芯片应答。
UU:探测被跳过了(不能确定有没有芯片,大概率有芯片),这个地址目前正被驱动程序使用,驱动里配置了这个地址(0x14)。
37:在0x37这个地址找到了芯片。
在这里插入图片描述
如下-f:force, -y:yes,i2cdetect -y -q 5。
在这里插入图片描述
i2ctransfer支持16位/32位寄存器的读写,w后面数字是设备/slave/器件即0x50后面的字节数。如下是8位寄存器,用i2cdump。
在这里插入图片描述
在这里插入图片描述

# dmesg
i2c i2c-1: Added multiplexed i2c bus 14
...
i2c i2c-1: Added multiplexed i2c bus 21
pca954x 1-0073: registered 8 multiplexed busses for I2C switch pca9548

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2个msg都存在
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.i2c-dev.c

如果传入的major=0,则会遍历数组到空余的项并把fops结构体放入,返回空余项下标作为新的主设备号。
在这里插入图片描述

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>

#define I2C_SLAVE_FORCE_CLAIM	0x1

int main() {
   
    unsigned long request;
    const char *device = "/dev/i2c-37";
    int file;
    int addr = 0x58;
    if ((file = open(device, O_RDWR)) < 0) {
   
        printf("Failed to open the i2c bus");
        return 1;
    }

    if (0x0 & I2C_SLAVE_FORCE_CLAIM) {
   
      printf("I2C_SLAVE_FORCE\n");
      request = I2C_SLAVE_FORCE;
    } else {
   
      printf("I2C_SLAVE\n"); // 0x0走这个
      request = I2C_SLAVE;
    }

    int rc = ioctl(file, request, addr);
    // I2C_SLAVE:0x48存在返回-1(卸载0x48驱动后0x48存在返回0), 0x58不存在返回0
    // I2C_SLAVE_FORCE : 0x48存在和0x58不存在都返回0  // 0x98这些i2cdetetc不存在的都是返回-1
    printf("rc: %d\n", rc);
    close(file);
    return 0;
}

在这里插入图片描述

// i2c-dev.c
static int __init i2c_dev_init(void)
{
   
    int res;

    printk(KERN_INFO "i2c /dev entries driver\n");

	//从主设备号开始,次设备号从0开始,拥有I2C_MINORS个
    res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c");			//注册字符驱动设备
    if (res)
        goto out;

    i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");			//创建名为i2c-dev的class
    if (IS_ERR(i2c_dev_class)) {
   
        res = PTR_ERR(i2c_dev_class);
        goto out_unreg_chrdev;
    }
    i2c_dev_class->dev_groups = i2c_groups;

    /* Keep track of adapters which will be added or removed later */
    res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
    if (res)
        goto out_unreg_class;

    /* Bind to already existing adapters right away */
    /* 对于每一个已经存在的adapters都会去调用i2cdev_attach_adapter */
    i2c_for_each_dev(NULL, i2cdev_attach_adapter);

    return 0;

out_unreg_class:
    class_destroy(i2c_dev_class);
out_unreg_chrdev:
    unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
out:
    printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
    return res;
}


static int i2cdev_attach_adapter(struct device *dev, void *dummy)
{
   
    struct i2c_adapter *adap;
    struct i2c_dev *i2c_dev;
    int res;

    if (dev->type != &i2c_adapter_type)
        return 0;
    adap = to_i2c_adapter(dev);

    i2c_dev = get_free_i2c_dev</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农编程录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值