Linux I2C 驱动实验

目录

一、Linux I2C 驱动简介

1、I2C 总线驱动

2、I2C 设备驱动

1、 i2c_client 结构体

2、 i2c_driver 结构体

二、硬件分析

三、设备树编写

1、pinctrl_i2c1

2、在 i2c1 节点追加 ap3216c 子节点

3、验证

四、 代码编写

1、makefile

2、ap3216c.h

 3、ap3216c.c

①、头文件

②、驱动出入口 

③、 i2c驱动结构体 

④、匹配函数

⑤、probe 函数

⑥、remove 函数

 ⑦、函数入口出口添加注册i2c_drive

⑧、读取AP3216C的N个寄存器

⑨、向AP3216C的N个寄存器写数据

⑩、读、写AP3216C一个寄存器

⑩①、读取AP3216C的数据

⑩②完善ap3216c_open、read函数

 代码如下

 

4、ap3216c.c


一、Linux I2C 驱动简介

        在IMX6ULL开发篇中"IIC实验"写了四个文件: bsp_i2c.c、bsp_i2c.h、 bsp_ap3216c.c 和 bsp_ap3216c.h。其中前两个是 I.MX6U 的 IIC 接口驱动,后两个文件是 AP3216C 这个 I2C 设备驱动文件。相当于有两部分驱动:
①、 I2C 主机驱动。
②、 I2C 设备驱动。
        对于 I2C 主机驱动,一旦编写完成就不需要再做修改,其他的 I2C 设备直接调用主机驱动提供的 API 函数完成读写操作即可。这个正好符合 Linux 的驱动分离与分层的思想,因此 Linux内核也将 I2C 驱动分为两部分:
①、 I2C 总线驱动, I2C 总线驱动就是 SOC 的 I2C 控制器驱动,也叫做 I2C 适配器驱动。
②、 I2C 设备驱动, I2C 设备驱动就是针对具体的 I2C 设备而编写的驱动

1、I2C 总线驱动

        在”platform驱动实验"的时候就说过, platform 是虚拟出来的一条总线,目的是为了实现总线、设备、驱动框架。对于 I2C 而言,不需要虚拟出一条总线,直接使用 I2C总线即可。 I2C 总线驱动重点是 I2C 适配器(也就是 SOC 的 I2C 接口控制器)驱动,Linux 内核将 SOC 的 I2C 适配器(控制器)抽象成 i2c_adapter, i2c_adapter 结构体定义在 include/linux/i2c.h 文件中,i2c_algorithm 类型的指针变量 algo,对于一个 I2C 适配器,肯定要对外提供读写 API 函数,设备驱动程序可以使用这些 API 函数来完成读写操作。 i2c_algorithm 就是 I2C 适配器与 IIC 设备进行通信的方法;i2c_algorithm 结构体定义在 include/linux/i2c.h 文件中,其中的master_xfer 就是 I2C 适配器的传输函数,可以通过此函数来完成与 IIC 设备之间的通信,smbus_xfer 是 SMBUS 总线的传输函数

        一般 SOC 的 I2C 总线驱动都是由半导体厂商编写的,比如 I.MX6U 的 I2C 适配器驱动 NXP 已经编写好了,这个不需要用户去编写。因此 I2C 总线驱动对我们这些 SOC 使用者来说是被屏蔽掉的,我们只要专注于 I2C 设备驱动即可。

2、I2C 设备驱动

        I2C 设备驱动重点关注两个数据结构: i2c_client 和 i2c_driver,i2c_client 就是描述设备信息的, i2c_driver 描述驱动内容,类似于 platform_driver

1、 i2c_client 结构体

i2c_client 结构体定义在 include/linux/i2c.h 文件中,内容如下:

struct i2c_client {
     unsigned short flags;     /* 标志 */
     unsigned short addr;     /* 芯片地址, 7 位,存在低 7 位*/
......
     char name[I2C_NAME_SIZE]; /* 名字 */
     struct i2c_adapter *adapter; /* 对应的 I2C 适配器 */
     struct device dev;     /* 设备结构体 */
     int irq;             /* 中断 */
     struct list_head detected;
......
 };

一个设备对应一个 i2c_client,每检测到一个 I2C 设备就会给这个 I2C 设备分配一个i2c_client

2、 i2c_driver 结构体

i2c_driver 类似 platform_driver,i2c_driver 结构体定义在 include/linux/i2c.h 文件中,部分如下

 struct i2c_driver {

    .........
    /* Standard driver model interfaces */
1    int (*probe)(struct i2c_client *, const struct i2c_device_id *);
    ......
2    struct device_driver driver;
3    const struct i2c_device_id *id_table;
    ..........

}

第 1 行,当 I2C 设备和驱动匹配成功以后 probe 函数就会执行,和 platform 驱动一样。
第 2行, device_driver 驱动结构体,如果使用设备树的话,需要设置 device_driver

                of_match_table 成员变量,也就是驱动的兼容(compatible)属性。
第3行, id_table 是传统的、未使用设备树的设备匹配 ID 表

重点工作就是构建 i2c_driver,构建完成以后需要向Linux 内核注册这个 i2c_driver

二、硬件分析

这部分在在IMX6ULL开发篇中"IIC实验"有详细介绍,下面就简单介绍

打开AP3216C原理图,这是一个IIC接口的器件,是一个环境光传感器

 I2C1_SCL: 使用的是UART4_TXD这个IO;I2C1_SDA: 使用的是UART4_RXD这个IO

打开ap3216数据手册

地址为0x1e

三、设备树编写

1、pinctrl_i2c1

打开设备树,找到i2c1,pinctrl_i2c1 就是 I2C1 的 IO 节点

        这里将 UART4_TXD 和 UART4_RXD 这两个 IO 分别复用为 I2C1_SCL 和 I2C1_SDA,电气属性都设置为 0x4001b8b0

2、在 i2c1 节点追加 ap3216c 子节点

        AP3216C 是连接到 I2C1 上的,因此需要在 i2c1 节点下添加 ap3216c 的设备子节点,默认内容如下

305-316行,NXP 官方的 EVK 开发板上接了 mag3110和fxls8471,这里使用的开发板并没有这这两个器件,所以删掉,并添加上我们使用的

300行,clock-frequency 属性为 I2C 频率,这里设置为 100KHz

302行,inctrl-0 属性指定 I2C 所使用的 IO 为上面的pinctrl_i2c1

305行,ap3216c 子节点, @后面的“1e”是 ap3216c 的器件地址

306行,设置 compatible 值为“my,ap3216c”

307行,reg 属性也是设置 ap3216c 器件地址的,因此 reg 设置为 0x1e

3、验证

改完成以后使用“make dtbs”重新编译一下,然后使用新的设备树启动 Linux 内核

/sys/bus/i2c/devices 目录下存放着所有 I2C 设备,如果设备树修改正确的话,会在/sys/bus/i2c/devices 目录下看到一个名为“0-001e”的子目录,如下

“0-001e”就是 ap3216c 的设备目录,“1e”就是 ap3216c 器件地址。进入0-001e 目录,可以看到“name”文件, name 问价就保存着此设备名字,在这里就是“ap3216c”,如下

四、 代码编写

1、makefile

需要的文件如下图左,修改makefile

2、ap3216c.h

定义器件及其寄存器地址

 3、ap3216c.c

①、头文件

②、驱动出入口 

 

③、 i2c驱动结构体 

46行,当 I2C 设备和驱动匹配成功以后 probe 函数就会执行,和 platform 驱动一样

47行,当关闭 驱动的时候remove 函数就会执行,和 platform 驱动一样

49行,name是在无设备树时用于和设备进行匹配,也就是上面写的实验,也作为驱动名字;

        使用设备树就设置of_match_table变量,也就是驱动的兼容(compatible)属性
53行,id_table 是传统的、未使用设备树的设备匹配 ID 表

④、匹配函数

i2c驱动结构体 里对应的函数

 236行,无设备树的时候匹配 ID 表
241行,设备树所使用的匹配表

⑤、probe 函数

在这里面实现基本的字符设备

#define AP3216C_CNT 1
#define AP3216C_NAME "ap3216c"

struct ap3216c_dev{
    int devid;
    int major;
    int minor;
    struct cdev cedv;
    struct class *class;
    struct device *device;
    void *private_data;/*私有数据*/
    unsigned short ir, als, ps;		/* 三个光传感器数据 */ 
};
static struct ap3216c_dev ap3216cdev;
static int ap3216c_open(struct inode *inode, struct file *filp)
{
   
    return 0;
}

static int ap3216c_release(struct inode *inode, struct file *filp)
{
    printk("ap3216c_release\r\n");
    return 0;
}
static ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
    return 0;
}

static struct file_operations ap3216c_fops  = {
    .owner  =   THIS_MODULE,
    .open   =   ap3216c_open,
    .read   =   ap3216c_read,
    .release = ap3216c_release,
};

static int ap3216c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
    int ret =0;
    /*搭建字符设备驱动框架*/
    /*1、创建字符设备*/
    ap3216cdev.major=0;
    if(ap3216cdev.major)
    {
        ap3216cdev.devid = MKDEV(ap3216cdev.major,0);
        ret = register_chrdev_region(ap3216cdev.devid,AP3216C_CNT,AP3216C_NAME);
    }else
    {
        ret = alloc_chrdev_region(&ap3216cdev.devid,0,AP3216C_CNT,AP3216C_NAME);
        ap3216cdev.major = MAJOR(ap3216cdev.devid);
        ap3216cdev.minor = MINOR(ap3216cdev.devid);
    }
    if(ret < 0)
    {
        printk("ap3216cdev_chrdev_region error!\r\n");
        goto fail_devid;
    }
    printk("ap3216cde major: %d minor: %d\r\n",ap3216cdev.major,ap3216cdev.minor);
    /*2、注册字符设备*/
    ap3216cdev.cedv.owner = THIS_MODULE;
    cdev_init(&ap3216cdev.cedv,&ap3216c_fops);
    ret = cdev_add(&ap3216cdev.cedv,ap3216cdev.devid,AP3216C_CNT);
    if(ret < 0)
    {
        printk("cdev_add error!\r\n");
        goto fail_cdev;
    }
    /*3、自动创建设备节点*/
    ap3216cdev.class = class_create(THIS_MODULE,AP3216C_NAME);
    if(IS_ERR(ap3216cdev.class))
    {
        ret = PTR_ERR(ap3216cdev.class);
        goto fail_class;
    }
    ap3216cdev.device = device_create(ap3216cdev.class, NULL,
                            ap3216cdev.devid, NULL,AP3216C_NAME);
    if(IS_ERR(ap3216cdev.device))
    {
        ret = PTR_ERR(ap3216cdev.device);
        goto fail_device;
    }

    printk("ap3216c_probe\r\n");
    ap3216cdev.private_data = client;
    return 0;
fail_device:
    class_destroy(ap3216cdev.class);
fail_class:
    cdev_del(&ap3216cdev.cedv);
fail_cdev:
    unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);
fail_devid:
    return ret;
}

" return 0 "前一行,将此函数的第一 个参数 client 传递给 ap3216cdev 的 private_data 成员变量

当设备和驱动匹配成功后,probe函数执行,传递的第一个参数就是i2c_client ,i2c_client 每检测到一个 I2C 设备就会给这个 I2C 设备分配一个i2c_client,这里用 ap3216cdev结构体中的private_data 成员接收

⑥、remove 函数

 ⑦、函数入口出口添加注册i2c_drive

 

50行,调用 i2c_add_driver 来向 Linux 内 核注册 i2c_driver,也就是 ap3216c_driver

i2c_add_driver 是一个宏,定义如下:

#define i2c_add_driver(driver) \
         i2c_register_driver(THIS_MODULE, driver)

i2c_add_driver 就是对 i2c_register_driver 做了一个简单的封装,只有一个参数,就是要注册的 i2c_driver。

66行,调用 i2c_del_driver 来注销掉前面 注册的 ap3216c_driver,函数原型如下:

void i2c_del_driver(struct i2c_driver *driver)

driver:要注销的 i2c_driver。返回值: 无。

⑧、读取AP3216C的N个寄存器

 这里先看61行,一般需要在 probe 函数里面初始化 I2C 设备,要初始化 I2C 设备就必须能够对 I2C 设备寄存器进行读写操作,这里就要用到 i2c_transfer 函数了,i2c_transfer 函数最终会调用 I2C 适配器中 i2c_algorithm 里面的 master_xfer 函数,对于 I.MX6U 而言就是i2c_imx_xfer 这个函数。 i2c_transfer 函数原型如下:

int i2c_transfer(struct i2c_adapter *adap,

                                struct i2c_msg *msgs,

                                int num)

adap: 所使用的 I2C 适配器, i2c_client 会保存其对应的 i2c_adapter。
msgs: I2C 要发送的一个或多个消息。
num: 消息数量,也就是 msgs 的数量。
返回值: 负值,失败,其他非负值,发送的 msgs 数量

 从上面介绍i2c_client结构体就能看到有adapter成员,在probe函数里面已经获取到ap3216cdev设备的private_data成员中

48行,就是把private_data成员中把私有数据提出来,就在61行第一个参数中使用i2c_client中的adapter成员

继续看 i2c_transfer 函数msgs 这个参数,这是一个 i2c_msg 类型的指针参数, I2C 进行数据收发
说白了就是消息的传递, Linux 内核使用 i2c_msg 结构体来描述一个消息。 i2c_msg 结构体定义
在 include/uapi/linux/i2c.h 文件中

 69行,从机地址

 70行,标志

72行,read data,读数据

79行,要发送消息(本 msg)长度

80行,发送消息的数据

47行,定义结构体数组,按照I2C读时序把操作分为两部分

前面两段作为一部分,就是50-54行;后面两段作另一部分,就是56-59行

50-54行,发送器件寄存器地址。从i2c_client中获取从机地址,标志为0,表示发送数据,要发送的数据,也就是器件寄存器地址,寄存器地址长度为1个字节

56-59行,读取数据。从i2c_client中获取从机地址,标志表示读数据,读出来的数据保存在val,最后为读取的长度

再回到61行,第二个参数就是结构体数组msg,第三个参数就是2,结构体数组msg的长度

⑨、向AP3216C的N个寄存器写数据

 76行,这里根据I2C写时序,寄存器地址和数据一次可以发完,所以只需要一个msg即可

79行,寄存器地址保存在b[0],先发寄存器地址

80行,把要发送的数据拷贝到b数组里面

⑩、读、写AP3216C一个寄存器

 就是调用函数

⑩①、读取AP3216C的数据

⑩②完善ap3216c_open、read函数

 

 代码如下

 

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "ap3216c.h"

#define AP3216C_CNT 1
#define AP3216C_NAME "ap3216c"

struct ap3216c_dev{
    int devid;/* 设备号 	 */
    int major;
    int minor;
    struct cdev cedv;/* cdev 	*/
    struct class *class;/* 类 		*/
    struct device *device;/* 设备 	 */
    void *private_data;/*私有数据*/
    unsigned short ir, als, ps;		/* 三个光传感器数据 */ 
};

static struct ap3216c_dev ap3216cdev;

/*读取AP3216C的N个寄存器*/
static int ap3216c_read_regs(struct ap3216c_dev *dev,u8 reg,
                                void *val, int len)
{
    int ret;
    struct i2c_msg msg[2];
    struct i2c_client *client = (struct i2c_client *)dev->private_data;

    /*msg[0]发送要读取的寄存器首地址*/
    msg[0].addr = client->addr;/*从机地址,也就是ap3216c*/
    msg[0].flags = 0;/* 标记为发送数据 */
    msg[0].buf = &reg;/*要发送的数据,也就是寄存器地址*/
    msg[0].len = 1;/*要发送的寄存器地址长度为1*/
    /*msg[1]读取数据*/
    msg[1].addr = client->addr;/*从机地址,也就是ap3216c*/
    msg[1].flags = I2C_M_RD;/*表示读数据*/
    msg[1].buf = val;/*接收到的从机地址*/
    msg[1].len = len;/*要读取的寄存器数据长度*/

    ret = i2c_transfer(client->adapter,msg,2);
    if(ret == 2){
        ret = 0;
    }else{
        printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);
        ret = -EREMOTEIO;
    }
    return ret;
}

/*向AP3216C的N个寄存器写数据*/
static int ap3216c_write_regs(struct ap3216c_dev *dev,u8 reg,
                                u8 *buf , u8 len)
{
    u8 b[256];
    struct i2c_msg msg;
    struct i2c_client *client = (struct i2c_client *)dev->private_data;
    /*构建要发送的数据,也就是寄存器首地址+实际的数据*/
    b[0] = reg;/*msg[0]发送要读取的寄存器首地址*/
    memcpy(&b[1], buf, len);
     
    msg.addr = client->addr;/*从机地址,也就是ap3216c*/
    msg.flags = 0;/*表示为要发送的数据*/
    msg.buf = b;/*要发送的数据,寄存器首地址+实际的数据*/
    msg.len = len +1;/*要发送的数据长度:寄存器首地址+实际的数据*/
    
    return i2c_transfer(client->adapter,&msg,1);
}
/*读取AP3216C一个寄存器*/
static unsigned char ap3216c_read_reg(struct ap3216c_dev *dev,u8 reg)
{
    u8 data=0;
    ap3216c_read_regs(dev,reg,&data,1);
    return data;
}
/*向AP3216C一个寄存器写数据*/
static void ap3216c_write_reg(struct ap3216c_dev *dev, u8 reg , u8 data)
{
    u8 buf = data;
    ap3216c_write_regs(dev,reg,&buf,1);
}

void ap3216c_readdata(struct ap3216c_dev *dev)
{
    unsigned char i =0;
    unsigned char buf[6];
    /* 循环读取所有传感器数据 */
    for(i = 0; i < 6; i++)	
    {
        buf[i] = ap3216c_read_reg(dev, AP3216C_IRDATALOW + i);	
    }
    if(buf[0] & 0X80) 	/* IR_OF位为1,则数据无效 */
		dev->ir = 0;					
	else 				/* 读取IR传感器的数据   		*/
		dev->ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03); 			
	
	dev->als = ((unsigned short)buf[3] << 8) | buf[2];	/* 读取ALS传感器的数据 			 */  
	
    if(buf[4] & 0x40)	/* IR_OF位为1,则数据无效 			*/
		dev->ps = 0;    													
	else 				/* 读取PS传感器的数据    */
		dev->ps = ((unsigned short)(buf[5] & 0X3F) << 4) | (buf[4] & 0X0F); 
}

static int ap3216c_open(struct inode *inode, struct file *filp)
{
    unsigned char value = 0;
    filp->private_data = &ap3216cdev;
    printk("ap3216c_open\r\n");
    /*初始化ap3216c*/
    ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x4);/*复位*/
    mdelay(50);/*50ms*/
    ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x3);/*复位*/
    value = ap3216c_read_reg(&ap3216cdev,AP3216C_SYSTEMCONG);
    printk("AP3216C_SYSTEMCONG = %#x\r\n",value);

  
    return 0;
}

static int ap3216c_release(struct inode *inode, struct file *filp)
{
    printk("ap3216c_release\r\n");
    return 0;
}
static ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
    long err=0;
    short data[3];
    struct ap3216c_dev *dev = (struct ap3216c_dev *)filp->private_data;
    /*向应用返回AP3216C的原始数据*/
    ap3216c_readdata(dev);
    data[0] =dev->ir;
    data[1] =dev->als;
    data[2] =dev->ps;
    err = copy_to_user(buf, data,sizeof(data));
    
    return 0;
}

static struct file_operations ap3216c_fops  = {
    .owner  =   THIS_MODULE,
    .open   =   ap3216c_open,
    .read   =   ap3216c_read,
    .release = ap3216c_release,
};

static int ap3216c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
    int ret =0;
    /*搭建字符设备驱动框架*/
    /*1、创建字符设备*/
    ap3216cdev.major=0;
    if(ap3216cdev.major)
    {
        ap3216cdev.devid = MKDEV(ap3216cdev.major,0);
        ret = register_chrdev_region(ap3216cdev.devid,AP3216C_CNT,AP3216C_NAME);
    }else
    {
        ret = alloc_chrdev_region(&ap3216cdev.devid,0,AP3216C_CNT,AP3216C_NAME);
        ap3216cdev.major = MAJOR(ap3216cdev.devid);
        ap3216cdev.minor = MINOR(ap3216cdev.devid);
    }
    if(ret < 0)
    {
        printk("ap3216cdev_chrdev_region error!\r\n");
        goto fail_devid;
    }
    printk("ap3216cde major: %d minor: %d\r\n",ap3216cdev.major,ap3216cdev.minor);
    /*2、注册字符设备*/
    ap3216cdev.cedv.owner = THIS_MODULE;
    cdev_init(&ap3216cdev.cedv,&ap3216c_fops);
    ret = cdev_add(&ap3216cdev.cedv,ap3216cdev.devid,AP3216C_CNT);
    if(ret < 0)
    {
        printk("cdev_add error!\r\n");
        goto fail_cdev;
    }
    /*3、自动创建设备节点*/
    ap3216cdev.class = class_create(THIS_MODULE,AP3216C_NAME);
    if(IS_ERR(ap3216cdev.class))
    {
        ret = PTR_ERR(ap3216cdev.class);
        goto fail_class;
    }
    ap3216cdev.device = device_create(ap3216cdev.class, NULL,
                            ap3216cdev.devid, NULL,AP3216C_NAME);
    if(IS_ERR(ap3216cdev.device))
    {
        ret = PTR_ERR(ap3216cdev.device);
        goto fail_device;
    }

    printk("ap3216c_probe\r\n");
    ap3216cdev.private_data = client;
    return 0;
fail_device:
    class_destroy(ap3216cdev.class);
fail_class:
    cdev_del(&ap3216cdev.cedv);
fail_cdev:
    unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);
fail_devid:
    return ret;
}
static int ap3216c_remove(struct i2c_client *client)
{
    cdev_del(&ap3216cdev.cedv);
    unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);
    device_destroy(ap3216cdev.class, ap3216cdev.devid);
    class_destroy(ap3216cdev.class);
    printk("ap3216c_remove\r\n");
    return 0;
}
/*传统匹配表*/
static struct i2c_device_id ap3216c_id[] = {
    {"my,ap3216c",0},
    {}
};
/*设备树匹配*/
static struct of_device_id ap3216c_of_match[] = {
    {.compatible = "my,ap3216c"},
    {}
};
/*i2c_driver*/
static struct i2c_driver ap3216c_driver= {
    .probe = ap3216c_probe,
    .remove = ap3216c_remove,
    .driver = {
        .name = "ap3216c",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(ap3216c_of_match),
    },
    .id_table = ap3216c_id,
};
/*驱动入口*/
static int __init ap3216c_init(void)
{
    int ret = 0;
    /*添加*/
    ret = i2c_add_driver(&ap3216c_driver);
    return ret;
}
/*驱动出口*/
static void __exit ap3216c_exit(void)
{
    i2c_del_driver(&ap3216c_driver);
}

module_init(ap3216c_init);
module_exit(ap3216c_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ba che kai qi lai");

4、ap3216c.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/input.h>

/*
    argc:应用程序参数个数(argv数组元素个数)
    argv:具体参数,也可以写作char **argv
    ./ap3216cAPP <filename>    
    ./ap3216cAPP  /dev/ap3216c
*/


int main(int argc, char *argv[])
{
    int fd,err;
    char *filename;
    unsigned short ir, als, ps, data[3];
    
    /*判断命令行输入参数是否正确*/
    if(argc != 2){
        printf("error usage!\r\n");
        return -1;
    }
    /*用指针指向文件*/
    filename = argv[1];
    /*打开文件*/
    fd = open(filename , O_RDWR);
    if(fd < 0){
        printf("file open failed\r\n",filename);
        return -1;
    }
   while(1)
   {
    err =read(fd,&data,sizeof(data));
    if(err == 0)
    {
        ir=data[0];
        als=data[1];
        ps=data[2] ;
        printf("ap3216c ir = %d,als = %d,ps = %d\r\n",ir,als,ps);
    }
    usleep(200000);/*200ms*/
   }
    

    /*关闭文件*/
    close(fd);

    return 0;
}

 用APP测试驱动

 用手接近和用灯照ap3216c传感器,数值都会发生变化

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
pcf8563_i2c1_r8_ruoge_ov2640通过给RTC驱动增加设备节点读取秒钟成功+直接读取I2C1获取秒钟值20160626_2201.7z http://blog.csdn.net/21cnbao/article/details/7919055 在Android源码树中添加userspace I2C读写工具(i2c-util) 本文使用的开发板是:杭州若格科技有限公司的全志R8。CPU:CPUARM Cortex-A8 更多芯片资料请参见全志官网: http://www.allwinnertech.com/clq/r/R8.html 通过/dev/i2c-n节点,用户可以在userspace直接访问板上的i2c外设寄存器,主要是透过I2C_RDWR这个IO控制命令将i2c_msg数组传递给kernel去执行。 开发板的/dev/i2c-1总线下挂有一片I2C的RTC:pcf8563。 root@android:/dev # cd /sys/class/i2c-adapter/ root@android:/sys/class/i2c-adapter # ll lrwxrwxrwx root root 1970-01-02 08:31 i2c-0 -> ../../devices/platform/sun5i-i2c.0/i2c-0 lrwxrwxrwx root root 1970-01-02 08:31 i2c-1 -> ../../devices/platform/sun5i-i2c.1/i2c-1 lrwxrwxrwx root root 1970-01-02 08:31 i2c-2 -> ../../devices/platform/sun5i-i2c.2/i2c-2 root@android:/sys/class/i2c-adapter # cd i2c-1 root@android:/sys/class/i2c-adapter/i2c-1 # ll drwxr-xr-x root root 1970-01-02 08:31 1-0051 --w------- root root 4096 1970-01-02 08:31 delete_device lrwxrwxrwx root root 1970-01-02 08:31 device -> ../../sun5i-i2c.1 drwxr-xr-x root root 1970-01-01 08:00 i2c-dev -r--r--r-- root root 4096 1970-01-02 08:31 name --w------- root root 4096 1970-01-02 08:31 new_device drwxr-xr-x root root 1970-01-01 08:00 power lrwxrwxrwx root root 1970-01-02 08:31 subsystem -> ../../../../bus/i2c -rw-r--r-- root root 4096 1970-01-01 08:00 uevent root@android:/sys/class/i2c-adapter/i2c-1 # root@android:/sys/class/i2c-adapter/i2c-1 # cd 1-0051/ root@android:/sys/class/i2c-adapter/i2c-1/1-0051 # ll lrwxrwxrwx root root 1970-01-02 10:18 driver -> ../../../../../bus/i2c/drivers/pcf8563 -r--r--r-- root root 4096 1970-01-02 10:18 modalias -r--r--r-- root root 4096 1970-01-02 10:18 name drwxr-xr-x root root 1970-01-02 10:18 power drwxr-xr-x root root 1970-01-02 10:18 rtc lrwxrwxrwx root root 1970-01-02 10:18 subsystem -> ../../../../../bus/i2c -rw-r--r-- root root 4096 1970-01-02 10:18 uevent root@android:/sys/class/i2c-adapter/i2c-1/1-0051 # cat name pcf8563 root@android:/sys/class/i2c-adapter/i2c-1/1-0051 # 注释:1-0051 1 表示 i2c-1这条I2C1总线上挂载的设备,如果是I2C2总线上挂载的设备,路径就是2-00XX了。 0051 一般的I2C设备的从机地址都是一个字节的,因为前两位为0x00(16进制的),后两位为pcf8563移位自后的I2C从机地址0x51(也是16进制的) 压缩包中的PCF8563-CN.pdf,datasheet告诉我们:I2C总线从地址:读,0A3H;写,0A2H。右移一位之后正好是0x51。 下面的代码可以完成这个功能: #include #include #include #include #include #include #include #include #include #include #include /* This is the structure as used in the I2C_RDWR ioctl call */ struct i2c_rdwr_ioctl_data { struct i2c_msg __user *msgs; /* pointers to i2c_msgs */ __u32 nmsgs; /* number of i2c_msgs */ }; int i2c_read_reg(char *dev, unsigned char *buf, unsigned slave_address, unsigned reg_address, int len) { struct i2c_rdwr_ioctl_data work_queue; unsigned char w_val = reg_address; int ret; int fd = open(dev, O_RDWR); if (!fd) { printf("Error on opening the device file\n"); return 0; } work_queue.nmsgs = 2; work_queue.msgs = (struct i2c_msg*)malloc(work_queue.nmsgs *sizeof(struct i2c_msg)); if (!work_queue.msgs) { printf("Memory alloc error\n"); close(fd); return 0; } ioctl(fd, I2C_TIMEOUT, 2); ioctl(fd, I2C_RETRIES, 1); (work_queue.msgs[0]).len = 1; (work_queue.msgs[0]).addr = slave_address; (work_queue.msgs[0]).buf = &w_val; (work_queue.msgs[1]).len = len; (work_queue.msgs[1]).flags = I2C_M_RD; (work_queue.msgs[1]).addr = slave_address; (work_queue.msgs[1]).buf = buf; ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue); if (ret < 0) { printf("Error during I2C_RDWR ioctl with error code: %d\n", ret); close(fd); free(work_queue.msgs); return 0; } else { printf("read salve:x reg:x\n", slave_address, reg_address); close(fd); free(work_queue.msgs); return len; } } int i2c_write_reg(char *dev, unsigned char *buf, unsigned slave_address, unsigned reg_address, int len) { struct i2c_rdwr_ioctl_data work_queue; unsigned char w_val = reg_address; unsigned char w_buf[len+1]; int ret; w_buf[0] = reg_address; int fd = open(dev, O_RDWR); if (!fd) { printf("Error on opening the device file\n"); return 0; } work_queue.nmsgs = 1; work_queue.msgs = (struct i2c_msg*)malloc(work_queue.nmsgs *sizeof(struct i2c_msg)); if (!work_queue.msgs) { printf("Memory alloc error\n"); close(fd); return 0; } ioctl(fd, I2C_TIMEOUT, 2); ioctl(fd, I2C_RETRIES, 1); (work_queue.msgs[0]).len = 1 + len; (work_queue.msgs[0]).addr = slave_address; (work_queue.msgs[0]).buf = w_buf; memcpy(w_buf + 1, buf, len); ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue); if (ret < 0) { printf("Error during I2C_RDWR ioctl with error code: %d\n", ret); close(fd); free(work_queue.msgs); return 0; } else { printf("write salve:x reg:x\n", slave_address, reg_address); close(fd); free(work_queue.msgs); return len; } } int main(int argc, char **argv) { unsigned int fd; unsigned int slave_address, reg_address; unsigned r_w; unsigned w_val; unsigned char rw_val; if (argc < 5) { printf("Usage:\n%s /dev/i2c-x start_addr reg_addr rw[0|1] [write_val]\n", argv[0]); return 0; } fd = open(argv[1], O_RDWR); if (!fd) { printf("Error on opening the device file %s\n", argv[1]); return 0; } sscanf(argv[2], "%x", &slave_address); sscanf(argv[3], "%x", &reg_address); sscanf(argv[4], "%d", &r_w); if (r_w == 0) { i2c_read_reg(argv[1], &rw_val, slave_address, reg_address, 1); printf("Read %s-%x reg %x, read value:%x\n", argv[1], slave_address, reg_address, rw_val); } else { if (argc < 6) { printf("Usage:\n%s /dev/i2c-x start_addr reg_addr r|w[0|1] [write_val]\n", argv[0]); return 0; } sscanf(argv[5], "%d", &w_val); if ((w_val & ~0xff) != 0) printf("Error on written value %s\n", argv[5]); rw_val = (unsigned char)w_val; i2c_write_reg(argv[1], &rw_val, slave_address, reg_address, 1); } return 0; } 在android/external/新建i2c-util目录,上述源代码存入android/external/i2c-util/i2c-util.c, R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\i2c-util\i2c-util.c 编写对应的Android.mk: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE = i2c-util # LOCAL_SRC_FILES := $(call all-subdir-c-files) LOCAL_SRC_FILES := i2c-util.c include $(BUILD_EXECUTABLE) 编译Android后,上述工具会位于/system/bin目录。在电路板上使用它: R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin\i2c-util 如果android已经编译了,只需要执行: rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ source build/envsetup.sh rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ lunch 选择:18. nuclear_evb-eng (注意:不同的ubuntu电脑,序号可能不同,但是只需要选择nuclear_evb-eng编译选项前面的序号既可!!!!) rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ cd i2c-util/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ mm 详细的编译步骤: Connecting to 192.168.1.103:22... Connection established. To escape to local shell, press 'Ctrl+Alt+]'. Welcome to Ubuntu 14.04 LTS (GNU/Linux 3.13.0-24-generic x86_64) * Documentation: https://help.ubuntu.com/ Last login: Sun Jun 26 19:23:30 2016 from 192.168.1.101 rootroot@rootroot-E400:~$ cd wyb/pcf8563_i2c1_r8_ruoge_ov2640/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640$ ll total 8606460 drwxr-xr-x 4 rootroot rootroot 4096 Jun 26 20:46 ./ drwxr-xr-x 19 rootroot rootroot 4096 Jun 25 06:50 ../ drwxrwxr-x 29 rootroot rootroot 4096 Jun 26 19:51 android/ drwxrwxr-x 8 rootroot rootroot 4096 Jun 26 16:35 lichee/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640$ cd android/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ source build/envsetup.sh including device/asus/grouper/vendorsetup.sh including device/asus/tilapia/vendorsetup.sh including device/generic/armv7-a-neon/vendorsetup.sh including device/generic/armv7-a/vendorsetup.sh including device/generic/mips/vendorsetup.sh including device/generic/x86/vendorsetup.sh including device/samsung/maguro/vendorsetup.sh including device/samsung/manta/vendorsetup.sh including device/samsung/toroplus/vendorsetup.sh including device/samsung/toro/vendorsetup.sh including device/softwinner/common/vendorsetup.sh including device/softwinner/crane-evb/vendorsetup.sh including device/softwinner/nuclear-256m/vendorsetup.sh including device/softwinner/nuclear-evb/vendorsetup.sh including device/softwinner/nuclear-r8m-evb/vendorsetup.sh including device/ti/panda/vendorsetup.sh including sdk/bash_completion/adb.bash rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ lunch You're building on Linux Lunch menu... pick a combo: 1. full-eng 2. full_x86-eng 3. vbox_x86-eng 4. full_mips-eng 5. full_grouper-userdebug 6. full_tilapia-userdebug 7. mini_armv7a_neon-userdebug 8. mini_armv7a-userdebug 9. mini_mips-userdebug 10. mini_x86-userdebug 11. full_maguro-userdebug 12. full_manta-userdebug 13. full_toroplus-userdebug 14. full_toro-userdebug 15. crane_evb-eng 16. nuclear_256m-user 17. nuclear_256m-eng 18. nuclear_evb-eng 19. nuclear_r8m_evb-eng 20. full_panda-userdebug Which would you like? [full-eng] 18 ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=4.2.2 TARGET_PRODUCT=nuclear_evb TARGET_BUILD_VARIANT=eng TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a-neon HOST_ARCH=x86 HOST_OS=linux HOST_OS_EXTRA=Linux-3.13.0-24-generic-x86_64-with-Ubuntu-14.04-trusty HOST_BUILD_TYPE=release BUILD_ID=JDQ39 OUT_DIR=out ============================================ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ ll total 156 drwxrwxr-x 29 rootroot rootroot 4096 Jun 26 19:51 ./ drwxr-xr-x 4 rootroot rootroot 4096 Jun 26 20:46 ../ drwxrwxr-x 3 rootroot rootroot 4096 Jun 13 11:38 abi/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:38 bionic/ drwxrwxr-x 5 rootroot rootroot 4096 Jun 13 11:38 bootable/ drwxrwxr-x 7 rootroot rootroot 4096 Jun 13 11:38 build/ drwxrwxr-x 11 rootroot rootroot 4096 Jun 13 11:38 cts/ drwxrwxr-x 18 rootroot rootroot 4096 Jun 13 11:38 dalvik/ drwxrwxr-x 18 rootroot rootroot 4096 Jun 13 11:38 development/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:38 device/ drwxrwxr-x 3 rootroot rootroot 4096 Jun 13 11:38 docs/ drwxrwxr-x 159 rootroot rootroot 4096 Jun 13 11:39 external/ drwxrwxr-x 14 rootroot rootroot 4096 Jun 13 11:40 frameworks/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:40 gdk/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:40 hardware/ drwxr-xr-x 2 rootroot rootroot 4096 Jun 26 19:37 i2cscan/ drwxr-xr-x 2 rootroot rootroot 4096 Jun 26 19:52 i2c-util/ drwxrwxr-x 11 rootroot rootroot 4096 Jun 13 11:40 libcore/ drwxrwxr-x 4 rootroot rootroot 4096 Jun 13 11:40 libnativehelper/ -r--r--r-- 1 rootroot rootroot 87 Jun 13 11:38 Makefile drwxrwxr-x 8 rootroot rootroot 4096 Jun 13 11:40 ndk/ drwxrwxr-x 4 rootroot rootroot 4096 Jun 26 16:43 out/ drwxrwxr-x 8 rootroot rootroot 4096 Jun 13 11:40 packages/ drwxrwxr-x 5 rootroot rootroot 4096 Jun 13 11:40 pdk/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:41 prebuilts/ drwxr-xr-x 2 rootroot rootroot 4096 Jun 25 13:01 read_pcf8563/ drwxrwxr-x 6 rootroot rootroot 4096 Jun 13 11:38 .repo/ drwxrwxr-x 51 rootroot rootroot 4096 Jun 13 11:41 sdk/ drwxrwxr-x 9 rootroot rootroot 4096 Jun 13 11:41 system/ drwxrwxr-x 4 rootroot rootroot 4096 Jun 13 11:41 tools/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ cd i2c-util/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ mm ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=4.2.2 TARGET_PRODUCT=nuclear_evb TARGET_BUILD_VARIANT=eng TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a-neon HOST_ARCH=x86 HOST_OS=linux HOST_OS_EXTRA=Linux-3.13.0-24-generic-x86_64-with-Ubuntu-14.04-trusty HOST_BUILD_TYPE=release BUILD_ID=JDQ39 OUT_DIR=out ============================================ PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/es-ES_zl0_sg.bin:system/tts/lang_pico/es-ES_zl0_sg.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/es-ES_ta.bin:system/tts/lang_pico/es-ES_ta.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/fr-FR_nk0_sg.bin:system/tts/lang_pico/fr-FR_nk0_sg.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/fr-FR_ta.bin:system/tts/lang_pico/fr-FR_ta.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/de-DE_gl0_sg.bin:system/tts/lang_pico/de-DE_gl0_sg.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/it-IT_cm0_sg.bin:system/tts/lang_pico/it-IT_cm0_sg.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/it-IT_ta.bin:system/tts/lang_pico/it-IT_ta.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/de-DE_ta.bin:system/tts/lang_pico/de-DE_ta.bin ignored. No private recovery resources for TARGET_DEVICE nuclear-evb make: Entering directory `/home/rootroot/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android' target thumb C: i2c-util cd R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin C:\Users\Administrator.USER-20150913SZ>r: R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin>adb remount remount succeeded R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin> R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin>dir i2c* 驱动器 R 中的卷是 rootroot 卷的序列号是 1A1C-E71D R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin 的目录 2016/06/26 21:10 5,388 i2c-util 1 个文件 5,388 字节 0 个目录 268,337,782,784 可用字节 R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin> R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin>adb push i2c-util /data/ 29 KB/s (5388 bytes in 0.180s) R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin> 将R8的串口连接到windows电脑上。通过串口工具:比如Xshell5(有些人可能喜欢使用SecureCRT)读取R8的串口打印 (ubuntu下请使用minicom,使用方法请自行搜索了) 波特率选择:115200 N 8 1 等R8的android启动完成之后(LCD进android主界面),输入:su [ 37.990060] init: process 'ril-daemon', pid 950 exited [ 38.010049] init: process 'ril-daemon' killing any children in process group su root@android:/ # root@android:/ # root@android:/ # cd /data root@android:/data # root@android:/data # ll drwxrwxr-x system system 1970-01-11 08:58 anr drwxrwx--x system system 1970-01-02 08:01 app drwx------ root root 1980-10-01 11:03 app-asec drwxrwx--x system system 1970-01-02 08:01 app-lib drwxrwx--x system system 1980-10-01 11:03 app-private drwx------ system system 1980-10-01 11:04 backup drwxrwx--x system system 1970-01-02 08:00 dalvik-cache drwxrwx--x system system 2016-06-21 10:11 data drwxr-x--- root log 1980-10-01 11:03 dontpanic drwxrwx--- drm drm 1980-10-01 11:04 drm -rw-rw-rw- root root 5388 2016-06-26 21:10 i2c-util drwxr-x--x root root 1980-10-01 11:03 local drwxrwx--- root root 1970-01-01 08:00 lost+found drwxrwx--- media_rw media_rw 1980-10-01 11:03 media drwxrwx--t system misc 1980-10-01 11:03 misc -rw------- system system 154 1970-01-02 08:02 pointercal drwx------ root root 1970-01-02 08:00 property -rwxrwxrwx root root 5392 2016-06-25 13:01 read_pcf8563 drwxrwx--x system system 1980-10-01 11:03 resource-cache drwxr-x--- root shell 1980-10-01 11:03 ssh drwxrwxr-x system system 1970-01-02 08:00 system drwx------ system system 1970-01-02 08:03 tombstones drwx--x--x system system 1980-10-01 11:03 user root@android:/data # (让i2c-util具有可执行权限:) root@android:/data # chmod 777 i2c-util root@android:/data # root@android:/data # ll i2c* -rwxrwxrwx root root 5388 2016-06-26 21:10 i2c-util root@android:/data # root@android:/data # root@android:/data # (可选执行) root@android:/data # sync root@android:/data # 注意:串口打印会打印很多log信息。上面的步骤中的状态信息已经被过滤了。 如果你的串口打印过量的log信息,属于正常现象! 如果不想要这么多的状态信息,可以考虑使用adb shell。 不过windows命令行中的adb shell不能够按TAB键自动补充,ubuntu的可以。 也许我们可以把windows的命令行特别设计一下(给它修正一下),让它也可以通过按TAB键来自动补全!^_ 读取pcf8563的第2个寄存器(秒钟值): 表 5:BCD 格式寄存器概况 标明“-”的位无效 地址 寄存器名称 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 02h 秒 VL 00~59BCD 码格式数 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:11 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:12 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:12 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:13 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:14 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:14 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:15 可以知道秒钟的值是变化的,基本上是一秒钟递增一次,I2C读取成功。 如果感兴趣的话,在执行读取命令的时候通过协议分析仪或者示波器来抓取I2C1的SCL/SDA的波形,来进行更加详尽的分析!^_ 方法二: 给出了一种复杂的解决办法(步骤从简,更多请参考开头的方法): R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\lichee\linux-3.4\drivers\rtc\rtc-sun5i.c 给这个驱动文件增加设备节点:/dev/a20_r8_pcf8563 增加设备节点的方法请参考: http://blog.csdn.net/mirkerson/article/details/8844997 android驱动学习---led实验 然后在这个驱动文件的pcf8563_probe函数处截获它的client指针(struct i2c_client *client) client2 = client; 用户可以通过在userspace直接访问设备节点:/dev/a20_r8_pcf8563(open) 然后调用ioctl:ioctl(fd, 0x00000001, 0x02); 来获取第2个寄存器:秒钟的值了。 #include #include #include #include #include #include #include #include #include #include #include int fd; int main(int argc, char **argv) { fd = open("/dev/a20_r8_pcf8563", O_RDWR); ioctl(fd, 0x00000001, 0x02); close(fd); return 0; } 执行过程(直接从内核打印秒钟值了,也可以看到秒钟值大概也是一秒钟递增一次!): root@android:/data # root@android:/data # ./read_pcf8563 [ 1397.060015] ****wyb drivers/rtc/rtc-sun5i.c:1169/r8_pcf8563_open()! open init.... [ 1397.071009] ****wyb drivers/rtc/rtc-sun5i.c:1130/r8_pcf8563_ioctl()! cmd=0x00000001 [ 1397.079076] ****wyb drivers/rtc/rtc-sun5i.c:1160/r8_pcf8563_ioctl()! cmd=0x00000001, value=0x00000046 [ 1397.088342] ****wyb drivers/rtc/rtc-sun5i.c:1177/r8_pcf8563_close()! close init root@android:/data # root@android:/data # ./read_pcf8563 [ 1398.409888] ****wyb drivers/rtc/rtc-sun5i.c:1169/r8_pcf8563_open()! open init.... [ 1398.411203] ****wyb drivers/rtc/rtc-sun5i.c:1130/r8_pcf8563_ioctl()! cmd=0x00000001 [ 1398.419273] ****wyb drivers/rtc/rtc-sun5i.c:1160/r8_pcf8563_ioctl()! cmd=0x00000001, value=0x00000047 [ 1398.428546] ****wyb drivers/rtc/rtc-sun5i.c:1177/r8_pcf8563_close()! close init root@android:/data # root@android:/data # root@android:/data # ./read_pcf8563 [ 1399.668173] ****wyb drivers/rtc/rtc-sun5i.c:1169/r8_pcf8563_open()! open init.... [ 1399.670939] ****wyb drivers/rtc/rtc-sun5i.c:1130/r8_pcf8563_ioctl()! cmd=0x00000001 [ 1399.679022] ****wyb drivers/rtc/rtc-sun5i.c:1160/r8_pcf8563_ioctl()! cmd=0x00000001, value=0x00000048 [ 1399.688299] ****wyb drivers/rtc/rtc-sun5i.c:1177/r8_pcf8563_close()! close init root@android:/data #
要模拟Linux I2C驱动,我们需要理解I2C协议和Linux驱动框架的基本原理。 I2C(Inter-Integrated Circuit)是一种串行通信协议,允许多个器件通过共享的两根线(SDA和SCL)进行通信。在Linux中,I2C驱动负责管理I2C总线上的设备与内核的通信。 首先,我们需要创建一个虚拟I2C设备。可以使用I2C-dev驱动模块来创建一个模拟的I2C设备节点文件。这可以通过在终端中运行“modprobe i2c-dev”命令来加载模块。 然后,我们需要编写一个I2C驱动程序,它需要遵循Linux驱动模型。驱动程序需要实现与I2C设备通信的函数,如读取和写入数据、发送和接收命令等。我们可以使用ioctl系统调用来实现这些操作。 另外,我们还需要在Linux的设备树(Device Tree)中添加对虚拟I2C设备的描述。这可以通过编辑设备树文件(如.dts或.dtsi)来完成。设备树会告诉内核如何初始化和配置I2C设备。 最后,我们需要编译和加载驱动程序。可以使用交叉编译工具链来编译驱动程序,并将其加载到Linux系统中。编译和加载驱动程序的具体步骤可以根据具体的开发环境和目标平台来进行配置和调整。 通过以上步骤,我们就可以在Linux系统上模拟一个I2C驱动。这样可以方便地进行I2C设备的开发和调试,而无需实际的硬件设备。同时,这也为Linux内核提供了一个通用的I2C接口,可以方便地与各种I2C设备进行通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值