瑞芯微Rockchip开发者社区
直播中

王晾其

7年用户 977经验值
私信 关注
[问答]

如何对基于RK3328的I2C读写芯片寄存器进行测试呢

如何对基于RK3328的I2C读写芯片寄存器进行测试呢?有哪些步骤?

回帖(1)

张嘉

2022-3-9 16:01:53

  • 1、I2C协议解读

    I2C一共有两根线,一条时钟线SCL,一条数据线SDA

    总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平

    总线上连接的每一个从设备都有一个从设备地址,占7个bit位

    I2C总线数据传输速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s

    2、I2C时序

    如下图所示,当SCL为高电平时,SDA由高到低的跳变,表示产生一个起始条件;当时钟线SCL高电平期间,读取数据线SDA上的电平大小,为一个bit的数据,读8次即一个byte的数据(11010000);当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位;当SCL为高而SDA由低到高的跳变,表示产生一个停止条件;



    3、I2C电路


    I2c0的引脚接音频芯片的i2c控制引脚





    4、从设备I2C的dts(设备树)设置



    5、通过I2C读写音频寄存器的值


    /*
            i2c_test
    */

    #include
    #include
    #include
    #include

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include



    #define DEVICE_NAME "lpf_i2c"

    struct i2c_client *i2c_test;

    struct test_device{
            int major;
            struct class *class;
            struct device *dev;
          
    };

    struct test_device *i2c_test_device;


    int test_device_open(struct inode *inode,struct file *filp)
    {

            printk("---------LPF:%s----------n",__func__);
          
            return 0;
    }

    int test_device_release(struct inode *inode,struct file *filp)
    {

            printk("---------LPF:%s----------n",__func__);

            return 0;
    }

    static const struct file_operations test_device_fops={
            .owner = THIS_MODULE,
            .open = test_device_open,
            .release = test_device_release,
    };



    static void i2c_test_write(struct i2c_client *client,uint8_t regaddr, uint8_t *data)
    {
            struct i2c_msg        msgs[2];
            int i;
            int ret;
            __u8 buffer[2];
        __u8 read_data[1];
          
            buffer[0] = regaddr;
            buffer[1] = *data;

            for(i=0;i<2;i++){                        //写寄存器 write:0x30+ack 0x04+ack 0x02+ack
                    if(i == 0){
                               msgs[0].addr = client->addr;
                        msgs[0].flags = 0;
                        msgs[0].len = 2;
                        msgs[0].buf = buffer;

                    }else{                                  //读寄存器    write:0x30+ack 0x04+ack read:0x31+ack 0x02+nak
                            msgs[0].addr = client->addr;
                            msgs[0].flags = 0;
                            msgs[0].len = 1;
                            msgs[0].buf = ®addr;
                                  
                            msgs[1].addr = client->addr;
                            msgs[1].flags = 1;
                            msgs[1].len = 1;
                            msgs[1].buf= read_data;
                    }

            //参数1 ---- i2c_adapter对象地址
            //参数2 ---- 数据包的地址:struct i2c_msg
            //参数3 ---- 数据包的个数
            //返回值---- 成功:数据包的个数,失败:负数
                    if(i==0){
                            ret = i2c_transfer(client->adapter, msgs,1);
                            if(ret<0){
                                    printk("------LPF:i2c error ret = %d  client->addr = %#x -------n",
                                    ret,client->addr);
                            }
                    }else{
                            ret = i2c_transfer(client->adapter, msgs,2);
                            if(ret<0){
                                    printk("------LPF:i2c error ret = %d  client->addr = %#x -------n",
                                    ret,client->addr);
                            }


                    }
                    msleep(10);
            }

    }

    static ssize_t echo_test_device_value(struct device *dev,struct device_attribute *attr, const char *buf, size_t len)        
    {
            uint8_t data= 0x02;             //要向寄存器写入的值
            uint8_t regaddr= 0x04;          //寄存器地址
          
            printk("---------LPF:%s----------n",__func__);

            /*将应用空间传递的(char *)类型数据转换为内核空间10进制整形 */
            //value = simple_strtoul(buf, NULL, 16);
          
          
            i2c_test_write(i2c_test,regaddr,&data);
          
            return len;
    }

    static ssize_t cat_test_device_value(struct device *dev,struct device_attribute *attr, char *buf)
    {

            printk("---------LPF:%s----------n",__func__);
          
            return 0;

    }


    static DEVICE_ATTR(test_device_value, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP  ,cat_test_device_value, echo_test_device_value);


    static int i2c_test_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {

            int ret;      

            printk("------LPF:%s------n",__func__);

            i2c_test=kzalloc(sizeof(struct i2c_client),GFP_KERNEL);
            if(!i2c_test){
                    printk("------LPF:kzlloc failed!------n");
                    ret = -ENOMEM;
            }

            i2c_test=client;

            /*空间申请*/
            i2c_test_device = kzalloc(sizeof(struct test_device),GFP_KERNEL);
            if(IS_ERR(i2c_test_device)){
                    printk("-------LPF-%s:kzalloc i2c_test_device failed!--------n",__func__);
                    ret = PTR_ERR(i2c_test_device);
                    goto err_i2c_test_kzalloc;
            }

            /* 设备号申请*/
            i2c_test_device->major = register_chrdev(0, "test_device_major", &test_device_fops);
            if(i2c_test_device->major < 0){
                    printk("-------LPF-%s:failed to creat i2c_test_device->major-------n",__func__);
                    ret = -EINVAL;
                    goto err_kzalloc;
            }

            /*创建设备类*/
            i2c_test_device->class = class_create(THIS_MODULE, "test_device_class");
            if(IS_ERR(i2c_test_device->class)){
                    printk("-------LPF-%s:failed to creat i2c_test_device->class--------n",__func__);
                    ret = PTR_ERR(i2c_test_device->class);
                    goto err_register;
            }

            /*创建test_device_device设备节点文件*/
            i2c_test_device->dev = device_create(i2c_test_device->class,NULL,MKDEV(i2c_test_device->major, 0),NULL,"test_device_device");
            if(IS_ERR(i2c_test_device->dev)){
                    printk("-------LPF-%s:failed to creat i2c_test_device->dev--------n",__func__);
                    ret = PTR_ERR(i2c_test_device->dev);
                    goto err_device_create;
            }

            /* 在 设备目录下创建一个test_device_value属性文件 /sys/class/test_device_class/test_device_device/test_device_value */
            ret=sysfs_create_file(&(i2c_test_device->dev->kobj), &dev_attr_test_device_value.attr);
            if(ret != 0){
                    printk("-------LPF-%s:failed to creat sysfs_create_file ret:%d--------n",__func__,ret);
                    goto err_sysfs_create_file;
            }

            return ret;
          
    err_sysfs_create_file:
            device_destroy(i2c_test_device->class,MKDEV(i2c_test_device->major, 0));
    err_device_create:
            class_destroy(i2c_test_device->class);
    err_register:
            unregister_chrdev(i2c_test_device->major,"digital_tube_major");
    err_kzalloc:
            kfree(i2c_test_device);
    err_i2c_test_kzalloc:
            kfree(i2c_test);
          
            return ret;
    }

    static int i2c_test_exit(struct i2c_client *client)
    {
            printk("---------LPF:%s----------n",__func__);
            return 0;

    }


    static const struct of_device_id i2c_test_of_match[] = {
            { .compatible = "ti,tlv320aic3111" },  //驱动会去dts匹配compatible属性,执行probe函数
            { },
    };

    static const struct i2c_device_id i2c_test_id[] = {
            { "tlv320aic3111" },
            { },
    };


    static struct i2c_driver i2c_test_driver = {
            .driver = {
                    .name = DEVICE_NAME,
                    .of_match_table = i2c_test_of_match,
            },
            .probe    = i2c_test_probe,
            .remove   = i2c_test_exit,
            .id_table = i2c_test_id,  //必须填充id_table,不然probe回调失败
    };

    module_i2c_driver(i2c_test_driver);

    /*
    module_i2c_driver(i2c_test_driver)展开如下:

        module_i2c_driver(i2c_test_driver)
        static int __int i2c_test_driver_init(void)
        {
            return i2c_register_driver(&i2c_test_driver);
        }
        module_init(i2c_test_driver_init);
        static void __exit adxl34x_driver_exit(void)
        {
            return i2c_del_driver(&adxl34x_driver);
        }
        module_exit(i2c_test_driver_exit);

    */

    MODULE_LICENSE("GPL");
    MODULE_VERSION("4.4");
    MODULE_AUTHOR("lpf");
    MODULE_DESCRIPTION("i2c test driver");
    6、I2C时序抓取结果

    向音频芯片的0X04寄存器成功写入0X02的值,并读出寄存器的值

    0x30-8位(从设备地址7位(dts里的0x18)+1位读写位(写是0)        0x31-8位(从设备地址7位(dts里的0x18)+1位读写位(读是1)

    写寄存器 write:0x30+ack 0x04+ack 0x02+ack            

    struct i2c_msg        msgs[1];
    __u8 buffer[2];

    buffer[0]=0x04;
    buffer[1]=0x02;
    msgs[0].addr = client->addr;
    msgs[0].flags = 0;    //0表示写
    msgs[0].len = 2;    //先写寄存器地址0x04,再向0x04执行的寄存器赋值0x02
    msgs[0].buf = buffer;

    i2c_transfer(client->adapter, msgs,1);



    读寄存器    write:0x30+ack 0x04+ack read:0x31+ack 0x02+nak

    struct i2c_msg        msgs[2];

    __u8 buffer[1];
    buffer[1]=0x04;
    __u8 read_data[1];

    msgs[0].addr = client->addr;   //从设备地址
    msgs[0].flags = 0;    //读寄存器需要先写寄存器的地址
    msgs[0].len = 1;
    msgs[0].buf = buffer;    //寄存器地址
                                  
    msgs[1].addr = client->addr;
    msgs[1].flags = 1;     //写完再读
    msgs[1].len = 1;
    msgs[1].buf= read_data;    //读出来的值保存在这里

    i2c_transfer(client->adapter, msgs,2);



举报

更多回帖

发帖
×
20
完善资料,
赚取积分